开箱即食,快来领取移动端 FPS 视野旋转控制解决方案 - TouchPad !
前言:
约是2年前,笔者写了一个摇杆,前段时间有个同学拿着这个仓库向笔者讨教怎么做出像吃鸡游戏那样使用手指拖拽屏幕右侧控制视野旋转的功能。
新手上路,光讲思路也不能解决问题,于是便索性写成 TouchPad 组件跟之前的摇杆整合,也挺好。
实现:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using static InputExtension;
public class TouchPad : MonoBehaviour
{
/// <summary>
/// 以此字符开头的UI不会阻碍 TouchPad 拖拽
/// </summary>
public string filterPrefix = "#";
public TouchPadEvent OnTouchPadValueChanged = new TouchPadEvent();
[System.Serializable]
public class TouchPadEvent : UnityEvent<Vector2> { }
//记录的那些不在UI上触发的点
private List<Touch> fingerIds = new List<Touch>();
private void Update() //不要使用 FixedUpdate 感觉 Touch 不能正确同步状态
{
if (Input.touchCount > 0)
{
foreach (var item in Input.touches)
{
int index = fingerIds.FindIndex(touch => touch.fingerId == item.fingerId);
//1. 如果 Touch 未被收录,考虑收录之
if (index == -1)
{
//2. 收集有效 Touch ,其特点为:刚按下 + 没打到UI上 + 在屏幕右侧
if (item.phase == TouchPhase.Began && item.position.x > Screen.width * 0.5f && !item.IsRaycastUI(filterPrefix))
{
fingerIds.Add(item);
}
}
else
{
if (item.phase == TouchPhase.Ended || item.phase == TouchPhase.Canceled)
{
fingerIds.RemoveAt(index); //3. 如果此Touch 已失效(unity 会回传 phase = end 的 touch),则剔除之
}
else
{
fingerIds[index] = item; //4. 由于Touch是 非引用类型的临时变量,所以要主动更新之
}
}
}
//5. 有效Touch 处于 move 则可以驱动事件了:
foreach (var item in fingerIds)
{
if (item.phase == TouchPhase.Moved)
{
OnTouchPadValueChanged.Invoke(item.deltaPosition);
}
}
}
}
👉Github托管👈
Tips:
- 代码本身没有什么难点,要留意的是
Touch
是struct
(值类型)需要主动赋值(见代码中注释 4 ) - 代码中引用的 InputExtension 用于检测Touch按下时是否点在了UI上。
- 考虑到并不是所有 UI 都会阻塞拖拽,比如吃鸡中扫射便是按在了UI还能拖拽,所以脚本中提供了 UI 过滤逻辑哈~
演示:
TouchpadTips
- 依次演示灵敏度调节、与摇杆协同、多手指响应、UI 阻塞、UI非阻塞拖拽。
- 拖着小方块的操作类比吃鸡游戏中的扫射哈,自行脑补。
写到最后:
- 多提取公共组件,使用事件解耦,避免相同逻辑重复写。
- 本文提到的 InputExtension 见[Unity 3d] 判断手指/鼠标按下触发在UI上的正确方法 - 简书
- 希望对有兴趣的同学带来些许帮助。
网友评论