TouchPad 是一个底层触摸输入管理器,直接挂载在场景中的 UI 或游戏物体上,通过实现 Unity 事件系统接口(IPointerDownHandler, IDragHandler, IPointerUpHandler, IBeginDragHandler, IDropHandler, IPointerExitHandler)来接收原始指针事件,并将其转换为:
-
C# 事件 (供外部订阅,如
ScreenDragEvent) -
ExecuteEvents消息 (发送给碰撞体上的TouchPadMessageTarget组件)
代码解释
1.变量声明

| 接口名称 | 作用 | 回调方法 | 触发时机 |
|---|---|---|---|
IPointerDownHandler |
指针按下 | void OnPointerDown(PointerEventData eventData) |
鼠标/手指在物体上按下时 |
IBeginDragHandler |
开始拖拽 | void OnBeginDrag(PointerEventData eventData) |
按下后移动超过阈值,开始拖拽时(仅触发一次) |
IDragHandler |
拖拽中 | void OnDrag(PointerEventData eventData) |
拖拽过程中每帧触发 |
IPointerUpHandler |
指针抬起 | void OnPointerUp(PointerEventData eventData) |
鼠标/手指抬起时 |
IDropHandler |
放下 | void OnDrop(PointerEventData eventData) |
拖拽的物体被放到另一个可放置的物体上时 |
IPointerExitHandler |
指针退出 | void OnPointerExit(PointerEventData eventData) |
指针移出物体的碰撞区域时 |
2.变量声明
2.1 事件声明
Action 不是 Unity 专属 ,它是 C# 内置的委托类型 ,在 Unity 中用来做事件通知、方法回调、解耦代码(最常用:按钮点击、技能释放、UI 刷新、消息广播)。
Action- C# 内置的委托类型
https://blog.csdn.net/LFJINNAN/article/details/160478366
(Action = 可以存方法的变量,只能存 void 方法)

可以被外部订阅的委托字段
- 作用:让外部脚本(如
TouchManager)订阅并接收触摸事件,而不需要通过ExecuteEvents机制。
TouchPadEventArgs
https://blog.csdn.net/LFJINNAN/article/details/160482722?spm=1001.2014.3001.5502
2.2 属性声明
| 属性 | 类型 | 说明 |
|---|---|---|
ScreenTouchPos |
Vector2 |
当前触摸点的屏幕坐标(私有 set) |
ScreenDragDirection |
Vector2 |
计算当前拖拽方向(当前位置 - 上一帧位置) |
WorldTouchPos |
Vector3 |
屏幕坐标转世界坐标,依赖 Camera.main,若相机不存在则返回 Vector3.zero |
IsTouched |
bool |
是否正在触摸中(按下后未抬起/退出) |
IsActive |
bool |
触摸处理是否启用(可通过 SetTouchActivity 修改) |
CameraMain |
Camera |
简写属性,返回 Camera.main(每次调用都重新获取,注意性能) |
注意:
-
ScreenTouchPos和IsTouched只有set没有get? 实际上代码中是public Vector2 ScreenTouchPos { get; private set; },所以外部可读但不可写。 -
Camera.main每次访问都会调用FindGameObjectsWithTag,有一定开销,但在触摸事件中调用频率较高(每帧可能多次)。可以考虑缓存。
2.3 序列化字段(Inspector 可见)

-
dlog:编辑器调试日志开关,在UNITY_EDITOR预处理块中使用。 -
onlyTopCollider:是否只向最顶层的碰撞体发送消息。此值会传给tpea.SetTouch方法,由TouchPadEventArgs内部实现射线检测时使用。
[Tooltip]: 仅作用于Inspector 面板 ,用来给变量添加鼠标悬浮提示文字
2.4 私有字段(临时变量)
| 字段 | 类型 | 作用 |
|---|---|---|
hitList |
List<Collider2D> |
当前帧按下的碰撞体列表(或上一帧的列表) |
newHitList |
List<Collider2D> |
新一帧的碰撞体列表(实时射线检测结果) |
tpea |
TouchPadEventArgs |
复用的参数对象,减少 GC 分配 |
pointerID |
int |
当前活动的指针 ID(用于多点触控过滤) |
oldPosition |
Vector2 |
上一帧的屏幕坐标 |
2.4.1pointerID
pointerID 确保了用户拖拽哪张牌,系统就准确响应哪张牌,即使另一根手指不小心碰到屏幕也不会造成干扰。
| 方面 | 说明 |
|---|---|
| 核心作用 | 唯一标识并追踪一个特定的触摸点 |
| 主要使用场景 | 按下时记录,拖拽/抬起的验证,多点触控隔离 |
| 取值来源 | PointerEventData.pointerId(TouchPad)或 Touch.fingerId(TouchPadS) |
| 典型值示例 | 鼠标:-1 或固定值(如10);触摸第1指:0;第2指:1 |
| 不使用的后果 | 多点触控时状态混乱,拖拽目标错误 |
2.5 单例

3.单例与初始化(Awake)

单例:如果已存在实例,则销毁当前对象;否则将自己设为单例。
保证场景里 永远只能有一个该脚本对象
- 第一次加载:赋值自己为唯一实例
- 重复挂载 / 多复制物体:自动删掉多余的
4. 事件回调详细解析
4.1 OnPointerDown - 按下

-
通过
IsTouched确保只有第一次按下被处理(防止多点触控中第二个手指触发)。 -
重新创建
tpea(这里产生了 GC,是潜在的优化点)。 -
SetTouch内部进行射线检测,填充tpea.hits。 -
使用
ExecuteEvents.Execute<TouchPadMessageTarget>向所有命中碰撞体发送PointerDown消息。 -
记录第一个命中物体的
TouchPadMessageTarget组件到tpea.firstSelected。 -
触发外部事件
ScreenPointerDownEvent。