赞
踩
=== 2024/5/23更新:添加鼠标模拟 ===
代码示例在最下面
效果如图:
Unity使用结构体Touch
定义触屏设备的输入,每一个触控点(可以理解为每一个手指)对应一个Touch
,其中主要的属性如下:
属性 | 含义 |
---|---|
fingerId | 触控点的编号,在该触控点的生命周期内(从点下到抬起)是不变的 |
phase | 触控点的状态,是一个Touch.Phase枚举,包括: Began(手指按下), Move(手指滑动), Stationary(手指已经按下且保持不动), Ended(手指抬起), Canceled(系统停止跟踪该触控点) |
position | 触控点在屏幕的坐标(屏幕坐标系) |
其他的属性参考https://docs.unity3d.com/ScriptReference/Touch.html |
需要注意的是对于fingerId的分配,类似于下面的过程:
使用一个数组表示哪些触控点当前被激活,初始为:
[0][0][0][0][0]
其中0表示未激活,1表示已激活。每按下一个手指时,从头寻找第一个未激活的空位,把它的索引赋给fingerId,例如按下第一个手指后,数组变为:
[1][0][0][0][0]
手指①的fingerId=0,这个时候再按下第二个手指,数组变为:
[1][1][0][0][0]
手指①的fingerId=0,手指②的fingerId=1,这个时候松开第一个手指,数组变为:
[0][1][0][0][0]
手指②的fingerId不变,还是1,这时候再按下第三个手指,数组变为:
[1][1][0][0][0]
手指②的fingerId不变,还是1,把数组的0号为给手指③,因此手指③的fingerId=0
Untiy的Input类中与Touch有关的API如下:
函数 | 含义 |
---|---|
Input.TouchCount | int, 触控点数量,即当前按下的手指数 |
Input.touches | Touch[],当前所有的Touch结构体数组 |
Input.GetTouch(int index) | 返回第index个Touch,index与fingerId无关 |
Input.multiTouchEnabled{get;set;} | 是否支持多点触控 |
当存在多个摇杆时,需要控制每个摇杆对应的fingerId,这里把摇杆类命名为JoyStick,另外定义一个控制类TouchEvent用于管理Touch与JoyStick的对应关系,TouchEvent在每次Update中读取所有的Touch:
代码如下:
TouchEvent.cs
using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; public class TouchEvent : MonoBehaviour { private Dictionary<int, JoyStick> id2JoyDic = new Dictionary<int, JoyStick>();//fingerId与摇杆的映射 private List<JoyStick> joyList = new List<JoyStick>();//UI上所有的摇杆 public void AddJoy(JoyStick joy) { joyList.Add(joy);//添加摇杆,由JoyStick在开始时调用 } // Update is called once per frame void Update() { #if UNITY_STANDALONE_WIN || UNITY_EDITOR //鼠标模拟触控 var touches = Input.touches.ToList(); if(Input.GetMouseButtonDown(0))//如果有鼠标点击 { var touch = new Touch();//模拟一个触控点 touch.fingerId = 100;//给一个不会重复的fingerId touch.position = Input.mousePosition;//鼠标的位置 touch.phase = TouchPhase.Began;//模拟按下 touches.Add(touch);//加入到触控点列表 } else if (Input.GetMouseButton(0)) { var touch = new Touch(); touch.fingerId = 100; touch.position = Input.mousePosition; touch.phase = TouchPhase.Moved; touches.Add(touch); } else if (Input.GetMouseButtonUp(0)) { var touch = new Touch(); touch.fingerId = 100; touch.position = Input.mousePosition; touch.phase = TouchPhase.Ended; touches.Add(touch); } #endif foreach (var touch in touches)//遍历所有的触控点 { if (touch.phase == TouchPhase.Began)//有新的触控点 { foreach (var joy in joyList) { if (joy.inTouchArea(touch.position) //判断是否在可触控范围内 && !id2JoyDic.ContainsValue(joy)) //如果对应的摇杆已经有触控点就忽略 { id2JoyDic.Add(touch.fingerId, joy);//加入新的触控点,绑定摇杆 } } } if (id2JoyDic.ContainsKey(touch.fingerId))//如果该触控点已经绑定了摇杆 { id2JoyDic[touch.fingerId].ReadTouch(touch);//读取触控操作 if (touch.phase == TouchPhase.Canceled || touch.phase == TouchPhase.Ended)//已离开的触控点 { //移除触控点 id2JoyDic.Remove(touch.fingerId); } } } } }
摇杆就是一个大圈+一个小圈组成,并且有一个可以触发的区域,如图:
矩形白色区域代表可以开始触控的区域,当手指按下时,把大圈的位置设为Touch的position,当手指滑动时,让小圈跟着动,并且限制它相对大圈的最大距离。
代码如下:
JoyStick.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; public class JoyStick : MonoBehaviour { public TouchEvent touchEvent;//多点触控管理类 public bool isFixedArea = false;//摇杆位置是否固定 private RectTransform touchArea;//可以触控的范围 public RectTransform circle;//摇杆的大圈 public RectTransform point;//摇杆的小圈 private float maxOffset;//摇杆离中心的最大距离 //public float xAxis = 0; //public float yAxis = 0; public UnityEvent onDown, onDrag, onUp;//按下、滑动、抬起的事件 // Start is called before the first frame update void Start() { touchArea = this.GetComponent<RectTransform>(); maxOffset = Mathf.Min(circle.rect.width, circle.rect.height) / 2;//计算大圈的最小半径作为小圈的最大移动距离 touchEvent.AddJoy(this);//注册摇杆 } /// <summary> /// 读取触控操作,由TouchEvent调用 /// </summary> /// <param name="touch"></param> public void ReadTouch(Touch touch) { if (touch.phase == TouchPhase.Began && !isFixedArea) { //如果手指按下 circle.position = touch.position;//把大圈移动到手指按下的位置 onDown.Invoke();//触发按下事件 } else if ((touch.phase == TouchPhase.Began && isFixedArea) || touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary) { //如果手指已经按下 Vector3 prePointPos = point.position;//记录之前的位置 Vector3 offset = new Vector3(touch.position.x, touch.position.y, 0) - prePointPos;//两帧的手指偏移量 point.position += offset;//让小圈跟着动 if ((point.position - circle.position).magnitude > maxOffset) { point.position = circle.position + (point.position - circle.position).normalized * maxOffset;//限制摇杆的移动 } //xAxis = offset.x / maxOffset;//计算归一化偏移量 //yAxis = offset.y / maxOffset; //print(string.Format("xAxis: {0} -- yAxis: {1}", xAxis, yAxis)); onDrag.Invoke();//触发滑动事件 } else if (touch.phase == TouchPhase.Ended) { //如果手指抬起 point.position = circle.position;//重置小圈的位置到大圈的中心 onUp.Invoke();//触发抬起事件 } } /// <summary> /// 判断某一点是否在可触控范围(矩形)内,由TouchEvent调用 /// </summary> /// <param name="pos"></param> /// <returns></returns> public bool inTouchArea(Vector2 pos) { Rect rect = touchArea.rect; rect.x += touchArea.position.x; rect.y += touchArea.position.y; return rect.Contains(pos); } public void OnDownTest() { print("down"); } public void OnDragTest() { print("drag"); } public void OnUpTest() { print("up"); } }
把TouchEven.cst挂在任意物体上,我这里挂在了EventSystem上
每一个摇杆如图中红框所示,
在手机上安装Unity Remote app,下载链接:
链接:https://pan.baidu.com/s/1moiz-4It5euHtpd86cLwgQ
提取码:z0fy
在Unity中点击edit->project settings,设置Editor,如图:
手机打开USB调试,连接电脑,然后运行,记得调整好分辨率
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。