实操的时候出现算出来的坐标不对,没有时间去找问题,优化了,所以代码仅供参考。
使用的是Lean Touch插件,免费的。
模块由三个点构成,基本构成等腰三角形,但是实际是会有误差的。
我的想法是在识别时,1.先计算出所有的边的长度,并记录下坐标。2.然后对比配置文件中的长度,记录符合配置文件的长度。3.然后再对比配置文件中的角度值。
主要算法在OnFingerUpdate()中,Update()中按下W键,则是记录模块的三条边长度和顶角的角度。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Lean.Touch;
using UnityEngine.UI;
using System;
public class touchTest : MonoBehaviour
{
public Text text;
public Text text2;
public static List<LeanFinger> Fingers = new List<LeanFinger>(10);
private static List<LeanFinger> allFingers = new List<LeanFinger>();
//记录模块最后一次的旋转角度,并进行比较,当前是正转是反转
private double[] RecordLastAngel = new double[6] { 0, 0, 0, 0, 0, 0 };
public GameObject[] MoveObj;
public GameObject RecordPage;
void Start()
{
//MoveObj[0].transform.rotation = Quaternion.Euler(Vector3.forward * (float)-60);
}
private void OnEnable()
{
LeanTouch.OnFingerUpdate += OnFingerUpdate;
LeanTouch.OnFingerDown += OnFingerDown;
LeanTouch.OnFingerUp += OnFingerUp;
LeanTouch.OnFingerSwipe += OnFingerSwipe;
}
private void OnDisable()
{
LeanTouch.OnFingerUpdate -= OnFingerUpdate;
LeanTouch.OnFingerDown -= OnFingerDown;
LeanTouch.OnFingerUp -= OnFingerUp;
LeanTouch.OnFingerSwipe -= OnFingerSwipe;
}
public class PtoP_Length
{
public float distances { get; set; }
public Vector2 FirstPosition { get; set; }
public Vector2 SecondPosition { get; set; }
}
void OnFingerUpdate(LeanFinger finger)
{
var fingers = LeanTouch.Fingers;
text.text = "";
if (fingers.Count >= 4)
{
List<PtoP_Length> PtoP_length = new List<PtoP_Length>();
PtoP_length.Clear();
//Debug.Log("1" + fingers[0].ScreenPosition);
//Debug.Log("2" + fingers[1].ScreenPosition);
//Debug.Log("3" + fingers[2].ScreenPosition);
//Debug.Log("4" + fingers[3].ScreenPosition);
//所有点到点的长度
for (int i = 1; i < fingers.Count; i++)
{
//text.text += fingers[i].ScreenPosition.ToString() + "|";
for (int j = i + 1; j < fingers.Count; j++)
{
double temp = getPointBetweenLength(fingers[i].ScreenPosition, fingers[j].ScreenPosition);
//记录点到点的长度和两点的坐标
PtoP_Length ppl = new PtoP_Length();
ppl.FirstPosition = fingers[i].ScreenPosition;
ppl.SecondPosition = fingers[j].ScreenPosition;
ppl.distances = (float)(temp);
PtoP_length.Add(ppl);
text2.text += temp + "|";
}
}
//对比配置文件中的令牌数据
List<int> RecordDis = new List<int>();
//RecordDis.Clear();
for (int i = 0; i < ReadXml.ID.Count; i++)
{
RecordDis.Clear();
//对比配置文件中符合距离的数据
for (int j = 0; j < PtoP_length.Count; j++)
{
//记录符合距离的数据
if (PtoP_length[j].distances > (Convert.ToInt32(ReadXml.DisA[i]) - 10)
&& PtoP_length[j].distances < (Convert.ToInt32(ReadXml.DisA[i]) + 10))
{
RecordDis.Add(j);
}
else if (PtoP_length[j].distances > (Convert.ToInt32(ReadXml.DisB[i]) - 10)
&& PtoP_length[j].distances < (Convert.ToInt32(ReadXml.DisB[i]) + 10))
{
RecordDis.Add(j);
}
else if (PtoP_length[j].distances > (Convert.ToInt32(ReadXml.DisC[i]) - 10)
&& PtoP_length[j].distances < (Convert.ToInt32(ReadXml.DisC[i]) + 10))
{
RecordDis.Add(j);
}
}
bool temprecordbool = false;
//获取正确角度的数值
for (int k = 0; k < RecordDis.Count; k++)
{
for (int l = 0; l < RecordDis.Count; l++)
{
if (temprecordbool == false)
{
for (int o = 0; o < RecordDis.Count; o++)
{
//获取所有可能
double temp1 = PtoP_length[RecordDis[k]].distances;
double temp2 = PtoP_length[RecordDis[l]].distances;
double temp3 = PtoP_length[RecordDis[o]].distances;
//获取所有可能的角度
double tempangle = GetAngle(temp1, temp2, temp3);
//把记录下的角度增减10度左右,因为可能会有误差
double angleplus = Convert.ToDouble(ReadXml.Angle[i]) + 10;
double anglejian = Convert.ToDouble(ReadXml.Angle[i]) - 10;
//然后和所有的角度进行比对
if (tempangle <= angleplus && tempangle >= anglejian)
{
//角度正确,即表示temp1为(1,2),temp2为(2,3),temp3为(1,3)或者(3,1)
//坐标只有3个点,那么只需要PtoP_length[RecordDis[k]].distances上的两个点
//就是第一个和第二个,第二个vet2为顶点坐标,
//PtoP_length[RecordDis[l]].distances的第二个坐标即为最后一个坐标点
Vector2 vet1 = PtoP_length[RecordDis[k]].FirstPosition;
Vector2 vet2 = PtoP_length[RecordDis[k]].SecondPosition;
Vector2 vet3 = PtoP_length[RecordDis[l]].SecondPosition;
Vector2 centerPoint = GetCiclePoint(vet1, vet2, vet3);
MoveObj[i].transform.position = new Vector2(centerPoint.x, centerPoint.y);
//计算角度值,角度值为坐标系的上方为:0~180度,坐标系的下方为:-1~-179度
//angel = Math.atan2(y, x)
double xposition = vet2.x - centerPoint.x;
double yposition = vet2.y - centerPoint.y;
double roationAngel = Math.Round(Math.Atan2(yposition, xposition), 2);
if (roationAngel < 0)
roationAngel = roationAngel + 360;
//if (RecordLastAngel[i] == 0) //第一次为空时,记录坐标,后面都是通过获取到的实时角度来和第一次记录的坐标,来进行计算,是正转还是反转
RecordLastAngel[i] = roationAngel;
//当前旋转的角度,负数为反转,正数为正转
double newAngel = roationAngel - RecordLastAngel[i];
//if (newAngel > 5 || newAngel < -5)
//{
text2.text += "编号:" + i.ToString() + "的坐标为" + centerPoint + "角度为:" + roationAngel + "旋转了:" + newAngel;
MoveObj[i].transform.rotation = Quaternion.Euler(Vector3.forward * (float)newAngel);
temprecordbool = true;
//}
//MoveObj[i].transform.Rotate(0f, 0f, 2f);//每一帧绕自身坐标轴Z轴旋转2度
}
//else
//{
// //角度不对,即移出屏幕
// MoveObj[i].transform.position = new Vector2(-2000, -2000);
// MoveObj[i].transform.Rotate(0f, 0f, 0f);
// for (int ab = 0; ab < RecordLastAngel.Length; ab++)
// { RecordLastAngel[ab] = 0; }
//}
}
}
}
}
}
}
}
/// <summary>
/// 任意两点之间的长度
/// </summary>
/// <param name="p"></param>
/// <param name="p2"></param>
/// <returns></returns>
double getPointBetweenLength(Vector2 p, Vector2 p2)
{
double value = Math.Sqrt(Math.Abs(p.x - p2.x) * Math.Abs(p.x - p2.x) + Math.Abs(p.y - p2.y) * Math.Abs(p.y - p2.y));
return Math.Round(value, 2);
}
string SanJiao(double b1, double b2, double b3)
{
string ss = "";
//首先判断能否组成三角形
if (b1 + b2 > b3 && b1 + b3 > b2 && b2 + b3 > b1)
{
//return "可以组成三角形";
//判断是怎样的三角形,并输出
if (b1 == b2 && b2 == b3)
{
ss = "是等边三角形";
}
else if (b1 == b2 || b2 == b3 || b1 == b3)
ss = "是等腰三角形";
else if (b1 * b1 + b2 * b2 == b3 * b3 || b1 * b1 + b3 * b3 == b2 * b2 || b3 * b3 + b2 * b2 == b1 * b1)
ss = "是直角三角形";
}
else
ss = "输入的三边不能组成三角形";
return ss;
}
//返回等腰三角形的顶角
//但公式不能算出等腰三角形的顶角
//令牌的三条边会有误差,正好不形成等腰三角,可以直接调用
/// <summary>
/// 计算角度
/// </summary>
/// <param name="a">长度最小的两条边</param>
/// <param name="b">长度最小的两条边</param>
/// <param name="c">最长的一条边长度</param>
/// <returns></returns>
double GetAngle(double a, double b, double c)
{
try
{
double sss = Math.Acos((a * a + b * b - c * c) / (2 * a * b)) / Math.PI * 180;
return sss;
}
catch { return 0; }
}
//获取三点的中心点
Vector2 GetCiclePoint(Vector2 first, Vector2 second, Vector2 thrid)
{
float tempA1;
float tempA2, tempB1, tempB2;
float tempC1, tempC2;
float temp, x, y;
tempA1 = first.x - first.x;
tempB1 = first.y - second.y;
tempC1 = float.Parse(((Math.Pow(first.x, 2) - Math.Pow(second.x, 2) + Math.Pow(first.y, 2) - Math.Pow(second.y, 2)) / 2).ToString());
tempA2 = thrid.x - second.x;
tempB2 = thrid.y - second.y;
tempC2 = float.Parse(((Math.Pow(thrid.x, 2) - Math.Pow(second.x, 2) + Math.Pow(thrid.y, 2) - Math.Pow(second.y, 2)) / 2).ToString());
temp = tempA1 * tempB2 - tempA2 * tempB1;
if (temp == 0)
{
x = first.x;
y = first.y;
}
else
{
x = (tempC1 * tempB2 - tempC2 * tempB1) / temp;
y = (tempA1 * tempC2 - tempA2 * tempC1) / temp;
}
return new Vector2(x, y);
}
void OnFingerDown(LeanFinger finger)
{
//Debug.Log("Finger:" + finger.Index);
//text2.text = text2.text + finger.TapCount + "\r\n";
}
void OnFingerUp(LeanFinger finger)
{
//for (int i = 0; i < text2.Length; i++)
//{
// text2[i].text = "";
//}
}
void OnFingerSwipe(LeanFinger finger)
{
//Debug.Log("FingerSwipe:" + finger.ScreenPosition);
}
public Text text3;
void Update()
{
text3.text = MoveObj[0].transform.position.x.ToString()+","+ MoveObj[0].transform.position.y.ToString();
//MoveObj[0].transform.Rotate(0f, 0f, 2f);//每一帧绕自身坐标轴Z轴旋转2度
var fingers = LeanTouch.Fingers;
//Debug.Log("update:" + fingers.Count);
//text.text = text.text + fingers.ScreenPosition + "\r\n";
//Debug.Log("Finger:" + LeanGesture.GetTwistDegrees());
//LeanGesture.GetTwistDegrees();
if (Input.GetKeyDown(KeyCode.D))
{
RecordPage.SetActive(!RecordPage.activeInHierarchy);
}
if (Input.GetKeyDown(KeyCode.W) && RecordPage.activeInHierarchy)
{
if (fingers.Count == 3)
{
//记录模块坐标
double firstBian = getPointBetweenLength(fingers[1].ScreenPosition, fingers[2].ScreenPosition);
double secondBian = getPointBetweenLength(fingers[2].ScreenPosition, fingers[3].ScreenPosition);
double thridBian = getPointBetweenLength(fingers[1].ScreenPosition, fingers[3].ScreenPosition);
double temp1 = firstBian - secondBian;
double temp2 = firstBian - thridBian;
double temp3 = secondBian - thridBian;
string id = RecordPage.transform.GetChild(0).transform.GetChild(0).transform.GetComponent<Text>().text;
if (temp1 <= 10 && temp1 >= -10)
{
double angle = GetAngle(firstBian, secondBian, thridBian);
ReadXml.readxml.UpdateXml(id, firstBian.ToString(), secondBian.ToString(), thridBian.ToString(), angle.ToString());
}
else if (temp2 <= 10 && temp2 >= -10)
{
double angle = GetAngle(firstBian, thridBian, secondBian);
ReadXml.readxml.UpdateXml(id, firstBian.ToString(), thridBian.ToString(), secondBian.ToString(), angle.ToString());
}
else if (temp3 <= 10 && temp3 >= -10)
{
double angle = GetAngle(secondBian, thridBian, firstBian);
ReadXml.readxml.UpdateXml(id, secondBian.ToString(), thridBian.ToString(), firstBian.ToString(), angle.ToString());
}
}
}
//allFingers.Clear();
//allFingers.AddRange(LeanTouch.Fingers);
//allFingers.AddRange(LeanTouch.InactiveFingers);
//allFingers.Sort((a, b) => a.Index.CompareTo(b.Index));
//for (var i = 0; i < allFingers.Count; i++)
//{
// var finger = allFingers[i];
// //var progress = touch.TapThreshold > 0.0f ? finger.Age / touch.TapThreshold : 0.0f;
// //var style = GetFadingLabel(finger.Set, progress);
// //if (style.normal.textColor.a > 0.0f)
// //{
// var screenPosition = finger.ScreenPosition;
// var state = "UPDATE";
// if (finger.Down == true) state = "DOWN";
// if (finger.Up == true) state = "UP";
// if (finger.IsActive == false) state = "INACTIVE";
// if (finger.Expired == true) state = "EXPIRED";
// if (finger.Index != -42)
// {
// string sss = finger.Index + " - " + state + " + " + Mathf.FloorToInt(screenPosition.x) + ", " + Mathf.FloorToInt(screenPosition.y);
// }
//}
}
}
以下是参考图片和链接
?
Object Interaction With Touchscreens : 6 Steps (with Pictures) - Instructables
感兴趣的,可以试试在OnFingerDown()中先识别哪个几个点是按下了,然后在OnFingerUpdate()中再处理,会更精准点。因为OnFingerUpdate()中获取到的坐标并不精确。
|