前段时间做了个Windows系统的大屏触控程序,最多同时支持十点触控,并且在各自的小窗口中要分别处理,即每个小窗口中的触点为一个处理组,判断其单点或多点操作。按以往移动端程序的触屏事件Input.GetTouch(int index)不满足需求,着实费了一番功夫。
首先分享常用的移动端触控方法,单指、双指操作。这里举例为单指操作模型旋转,双指同向移动操作模型平移,双指反向移动操作模型缩放。单指操作不再赘述,双指操作我选用向量判断。
public void SingleTouch()
{
Debug.Log("SingleTouch");
if (Input.GetTouch(0).phase == TouchPhase.Began || !isSingleFinger)
{
//在开始触摸或者从两字手指放开回来的时候记录一下触摸的位置
preSingleTouchPosition = Input.GetTouch(0).position;
}
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
currentModel.transform.Rotate(Vector3.up, -Input.GetTouch(0).deltaPosition.x * 0.5f);
preSingleTouchPosition = Input.GetTouch(0).position;
}
isSingleFinger = true;
}
public void DoubleTouch()
{
Debug.Log("DoubleTouch:" + Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position));
if (isSingleFinger)
{
oldPosition1 = Input.GetTouch(0).position;
oldPosition2 = Input.GetTouch(1).position;
beginTouchDistance = Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
currentScale = currentModel.transform.localScale;
currentPosition = currentModel.transform.localPosition;
}
if (Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(1).phase == TouchPhase.Moved)
{
Vector2 xiangliang1 = Input.GetTouch(0).position - oldPosition1;
Vector2 xiangliang2 = Input.GetTouch(1).position - oldPosition2;
float dir = Vector2.Dot(xiangliang1.normalized, xiangliang2.normalized);
if (dir <= 1 && dir >= 0)
{
currentModel.transform.Translate(Input.GetTouch(0).deltaPosition.x * 0.01f, Input.GetTouch(1).deltaPosition.y * 0.01f, 0, Space.World);
}
else if (dir >= -1 && dir < 0)
{
float currentTouchDistance = Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
float tmpScale = currentTouchDistance / beginTouchDistance - 1f;
tmpScale += currentScale.x;
tmpScale = Mathf.Clamp(tmpScale, 0.5f, 3f);
currentModel.transform.localScale = Vector3.one * tmpScale;
}
}
isSingleFinger = false;
}
以上为移动端常用的触控方法,接下来简述一下Windows大屏触控。
首先来说,需求为在大屏上点击弹出小窗口,窗口中会有所点模型的操作,平移、旋转、缩放以及UI控制的动画等展示。因所选大屏最多支持十点触控,故限制小窗口最多生成5个,且每个小窗口需要独立操作,即在窗口1内的操作不会影响其他窗口或窗口外的点击事件,并且窗口1外的触控同样不影响窗口1内的操作。所以这里需要面向对象的概念,将触点作为对象,创建类。这里由于功能并不复杂,小窗口作为预制体生成,所以只需定义一个点击的窗口对应的UI控制组件和一个触点集合,就可以完成需求。
public class A
{
public UIManager obj;//自定义UI控制脚本
public List<Touch> touch = new List<Touch>();
}
然后实例这个类进行处理,这里我只判断了点在哪个窗口内,然后将窗口内所有点存入集合,方便在控制脚本里调用并响应相应的事件。
public void ClickObject()
{
Debug.Log("ClickObject");
a = new List<A>();
for (int i = 0; i < Input.touchCount; i++)
{
eventDataCurrentPosition.position = Input.GetTouch(i).position;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
if(results.Count > 0)
{
if (results[0].gameObject.transform.parent.GetComponent<UIManager>() != null)
{
if(a.Count == 0)
{
A a1 = new A();
a1.obj = results[0].gameObject.transform.parent.GetComponent<UIManager>();
a1.touch.Add(Input.GetTouch(i));
a.Add(a1);
}
else
{
int aa = a.Count;
for (int j = 0; j < aa; j++)
{
if(a[j].obj == results[0].gameObject.transform.parent.GetComponent<UIManager>())
{
a[j].touch.Add(Input.GetTouch(i));
}
else
{
A a1 = new A();
a1.obj = results[0].gameObject.transform.parent.GetComponent<UIManager>();
a1.touch.Add(Input.GetTouch(i));
a.Add(a1);
}
}
}
}
}
}
}
要注意,由于小窗口使用UI组件显示,因此需要先保证EventSystem的存在,PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current),否则窗口中的点击将无法触发,也就无法记录并进行后续操作。
对象类及分组处理已完成,接下来向单指、双指的触控方法中传参即可,需根据实际需求及应用环境进行处理,这里就不作过多描述。