IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> unity c# 触摸屏物体识别桌算法 -> 正文阅读

[游戏开发]unity c# 触摸屏物体识别桌算法

实操的时候出现算出来的坐标不对,没有时间去找问题,优化了,所以代码仅供参考。

使用的是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()中获取到的坐标并不精确。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 21:31:23  更:2022-02-14 21:32:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:41:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码