
在移动端项目开发里最磨人的环节往往不是逻辑设计而是“没有真机怎么调试触控交互”。尤其是双指缩放、旋转、多指点按这类依赖触摸事件的功能如果只靠Input.GetMouseButton硬写等提交到手机上跑的时候往往会出现坐标不对、手势识别错误、UI响应迟钝等一系列问题。Unity 编辑器里其实自带了多点触控模拟能力很多老开发者习惯把它叫做 Multi-touch Simulator也有新版本叫 Device Simulator / Touch Simulation。它能把鼠标模拟成一根甚至多根手指让触摸相关代码在编辑器里直接运行起来。这篇文章会围绕 Multi-touch Simulator 做一次完整的实操记录先讲清楚它是什么、解决什么问题然后带你找到入口学会模拟单指和多指操作接着结合旧版 Input Manager 和新版 Input System 分别写出可运行的触摸读取脚本最后补充一个可视化调试窗口的制作思路、常见问题排查以及移动端手势开发的工程建议。无论你是刚接触 Unity 的新手还是已经做过几个移动端项目的开发者都可以照着这篇文章一步步把多点触控调试环境搭起来。需要提前说明的是本文讲解的是 Unity 编辑器内置能力不依赖任何第三方 SDK。示例环境以 Unity 2021.3 LTS / Unity 2022.3 LTS 为参考不同版本菜单位置会略有差异但核心思路是一样的。1. Multi-touch Simulator 是什么解决什么问题1.1 移动端调试的痛点很多手游项目在开发过程中都会遇到同一个尴尬场景UI 上明明写好了双指缩放逻辑代码看起来也没问题但连接 Android / iOS 真机调试时要么数据线不稳定要么机型太老要么公司测试机不够用。于是开发者只能硬着头皮用鼠标模拟点击用一个伪“触摸点”去测试手势最后到了真机上才发现逻辑完全跑偏。这些问题本质上都指向同一个需求在编辑器环境里能不能获得逼真的多点触控输入Multi-touch Simulator 就是为此服务的。它允许你在 Unity 编辑器的模拟屏幕中把鼠标动作转换成一个或多个触摸事件。你的游戏脚本不需要修改任何代码只要读取Input.touches、Input.touchCount或者新 Input System 里的Touchscreen.current就能像在真机上一样拿到触摸点数据。1.2 它到底做了什么从原理上来说Multi-touch Simulator 并不是给鼠标增加触摸功能而是把鼠标的按键状态、坐标位移转换成 Unity 输入系统里的 Touch 数据。这个过程发生在输入事件进入你的脚本之前所以你的业务代码感知不到“这是鼠标在操作”它只会觉得自己收到了一组正常的触摸点。举个例子当你打开 Device Simulator 后按住鼠标左键在屏幕里拖动鼠标按下会转换为触摸 Begin拖动过程中会持续产生触摸 Move松开鼠标会转换为触摸 End如果启用了第二个触摸点那么两个鼠标“手指”同时存在时输入系统会生成touchCount 2两个触摸点分别有各自的 phase、position、deltaTime。你的双指缩放代码这时就会正常工作。不过有一点要清楚模拟器终究不是真机它无法模拟压力感应、手指大小、设备触摸采样率等硬件特性。它适合验证“手势识别逻辑”和“坐标转换逻辑”不适合做最终的手感调优。1.3 内置模拟器 vs 第三方插件Unity Asset Store 上也有不少名字叫 Multi-touch Simulator 的插件它们通常提供更丰富的触摸可视化、手势录制回放、多指同时点击等功能。但它们和编辑器内置方案并不冲突。内置模拟器的优势是零成本、零依赖、更新跟版本同步并且对新旧输入系统都有支持。缺点是界面比较克制很多人不知道第二根手指怎么按出来。第三方插件则通常把入口和交互做得很白话但你需要考虑付费、版本兼容、代码安全性等问题。个人建议是优先把内置模拟器用熟。如果项目确实需要录制回放或者跨设备同步测试再去评估第三方工具。本文后续内容都基于内置方案展开。2. 环境准备与版本说明2.1 Unity 版本与模拟器入口Multi-touch Simulator 这个概念从 Unity 4.x 时代就存在了那时候你可以在 Game View 右上角找到一个手指图标点击后就能开启模拟。在较新的 Unity 2020 版本里Unity 主推的是 Device Simulator 窗口它支持选择模拟设备、旋转屏幕、调整分辨率并且把触摸模拟做成了可视化的开关按钮。本文的操作说明以 Unity 2021.3 LTS / Unity 2022.3 LTS 为主。如果你用的是 Unity 2019 或 Unity 6入口可能不在完全相同的菜单里但整体逻辑一致在编辑器的模拟屏幕内触发触摸事件让脚本读到的touchCount发生变化。2.2 输入系统配置Active Input Handling在开始模拟触摸之前有一个非常容易踩坑的配置项Active Input Handling。这个选项位于Project Settings Player Other Settings Active Input Handling它有三种取值Input Manager (Old)Input System Package (New)Both如果你的项目只启用了旧版 Input Manager那么Input.touches可以正常工作但Touchscreen.current会一直为 null。如果你的项目只启用了新 Input System那Input.touches就会被停用。如果设置成 Both新旧两套接口可以同时使用但要注意两者对触摸输入的驱动机制会有一定差异。为了在调试期间灵活切换建议把它设置成Both这样新旧触摸代码都能收到模拟数据。设置完成后 Unity 通常会提示重启编辑器。2.3 示例项目结构为了下一步的代码演示我们规划一个最简单的项目结构Assets/ Scenes/ Main.unity // 测试场景 Scripts/ TouchDebug.cs // 打印触摸信息 PinchZoom.cs // 双指缩放 TwoFingerRotate.cs // 双指旋转 TouchVisualizer.cs // 可视化调试窗口静态数据容器 Editor/ TouchVisualizerWindow.cs // 编辑器窗口绘制这里的几个脚本会分别覆盖触摸读取、手势识别、编辑器调试展示。你不一定需要全建出来按需复制即可。3. 打开模拟器并模拟单指触摸3.1 打开 Device Simulator推荐使用 Unity 的 Device Simulator 窗口入口在Window General Device Simulator打开后会看到一个模拟的手机屏幕界面。在窗口顶部通常有设备型号下拉菜单、旋转按钮、分辨率设置等操作项。这个窗口里显示的画面和 Game View 一样是当前场景的实时画面但它多了一层“模拟真实设备屏幕”的外框方便你观察 UI 适配和全面屏安全区。如果你更习惯用 Game View也可以直接点击 Game View 左上角的下拉菜单选择 Simulator 模式。这两种方式本质上是同一套模拟逻辑Device Simulator 的可视化信息更丰富更适合做移动端调试。3.2 模拟单指触摸的基本操作进入播放模式后在 Device Simulator 的模拟屏幕上按住鼠标左键并拖动就相当于一根手指在屏幕上触摸并滑动。观察触摸相位大概是这么对应的鼠标按下触摸 Begin鼠标按住并移动触摸 Move鼠标松开触摸 End需要注意的是这个过程必须发生在模拟器窗口内部。如果你只是把鼠标停在普通 Game View 上拖动是不能产生触摸事件的因为普通 Game View 没有启用触摸模拟。3.3 用代码验证触摸数据先写一个最简单的触摸调试脚本挂到场景中的任意物体上。它的作用是实时打印当前触摸点数量和每个触摸点的状态。这样我们就能直观地看到模拟器是否在工作。// 文件路径Assets/Scripts/TouchDebug.cs using UnityEngine; public class TouchDebug : MonoBehaviour { void Update() { if (Input.touchCount 0) { for (int i 0; i Input.touchCount; i) { Touch touch Input.GetTouch(i); Debug.Log($Touch {i}: pos{touch.position}, phase{touch.phase}); } } } }把脚本挂到场景后点击 Play然后在 Device Simulator 窗口里按住鼠标左键拖动。你应该能在 Console 窗口看到类似的日志Touch 0: pos(126.0, 389.0), phaseBegan Touch 0: pos(130.0, 386.0), phaseMoved Touch 0: pos(180.0, 320.0), phaseMoved Touch 0: pos(180.0, 320.0), phaseEnded如果能看到这些日志说明模拟器的单指触摸链路已经打通。4. 多指触摸实操双指缩放与旋转4.1 模拟第二根手指的方式很多人在 Multi-touch Simulator 上卡住不是因为没找到入口而是不知道怎么按出“第二根手指”。正如前面所说不同 Unity 版本的快捷键并不完全一致常见的有 Shift 鼠标左键、Ctrl 鼠标左键、Alt 鼠标左键。在 Device Simulator 窗口里也可能存在一个“Add Touch”按钮点击后鼠标再点击屏幕就会生成第二个触摸点。如果你使用的是比较新的 Unity 版本可以在 Device Simulator 窗口的左上角或者屏幕边缘找到触摸模拟控制条它通常会显示一个手指图标和添加按钮。点一下 Add Touch然后用鼠标左键在屏幕上再点一次就产生了第二根手指。有一点需要提醒第二根手指的模拟往往需要你先把鼠标移动到模拟屏幕内再按下触发键。如果你在屏幕外按下组合键再拖进屏幕触摸点可能不会生效。这些细节在不同版本里会有差异如果你在某个版本里实测出来的快捷键和网上查到的不同以编辑器窗口的提示为准。4.2 双指缩放脚本接下来我们写一个双指缩放脚本并把它挂到场景中的 Cube 上验证模拟器的多点触控能力。// 文件路径Assets/Scripts/PinchZoom.cs using UnityEngine; public class PinchZoom : MonoBehaviour { public float zoomSpeed 0.1f; public float minScale 0.2f; public float maxScale 5f; private float previousDistance 0f; void Update() { if (Input.touchCount ! 2) { previousDistance 0f; return; } Touch touch0 Input.GetTouch(0); Touch touch1 Input.GetTouch(1); float currentDistance Vector2.Distance(touch0.position, touch1.position); if (previousDistance 0f) { float delta currentDistance - previousDistance; float scaleFactor 1f delta * zoomSpeed; Vector3 newScale transform.localScale * scaleFactor; newScale.x Mathf.Clamp(newScale.x, minScale, maxScale); newScale.y Mathf.Clamp(newScale.y, minScale, maxScale); newScale.z Mathf.Clamp(newScale.z, minScale, maxScale); transform.localScale newScale; } previousDistance currentDistance; } }这个脚本的逻辑非常直观每帧检查Input.touchCount是否等于 2。计算两个触摸点之间的距离。对比上一帧距离得到差值。根据差值计算缩放比例并应用到物体的localScale上。运行后先模拟单指触摸你会发现 Cube 不会改变大小因为touchCount不等于 2。然后添加第二根手指同时拖动鼠标让两个点之间的距离变化Cube 就会变大或变小。这里有一个小建议如果你发现缩放方向反了可以交换delta的正负号或者检查两个触摸点的索引顺序。因为在某些版本里第二根手指的触摸索引可能不稳定。4.3 双指旋转脚本除了缩放旋转也是多点触控最常见的需求。实现思路是计算上一帧两个触摸点连线的角度再计算当前帧的角度差值就是旋转角。// 文件路径Assets/Scripts/TwoFingerRotate.cs using UnityEngine; public class TwoFingerRotate : MonoBehaviour { public float rotateSpeed 0.1f; private float previousAngle 0f; void Update() { if (Input.touchCount ! 2) { previousAngle 0f; return; } Touch touch0 Input.GetTouch(0); Touch touch1 Input.GetTouch(1); Vector2 delta touch1.position - touch0.position; float currentAngle Mathf.Atan2(delta.y, delta.x) * Mathf.Rad2Deg; if (previousAngle ! 0f) { float angleDelta currentAngle - previousAngle; transform.Rotate(0f, 0f, angleDelta * rotateSpeed); } previousAngle currentAngle; } }把PinchZoom和TwoFingerRotate同时挂到一个物体上时你会发现双指手势可以同时驱动缩放和旋转。这也是模拟器的优势你可以在编辑器里一次性验证多个手势的叠加效果。4.4 运行验证与结果说明这里有一个完整的验证流程打开 Device Simulator选择一台接近目标机型的设备比如 iPhone 13 或 Pixel 6。创建场景在场景中心放置一个 Cube把PinchZoom挂上。点击 Play模拟单指拖动确认 Cube 不变化。启用第二根手指让两个触摸点的距离从近到远移动Cube 应该逐渐放大。再让距离从远到近移动Cube 应该逐渐缩小。如果 Cube 的 Scale 变化符合预期说明 Multi-touch Simulator 已经正确产生了至少两个触摸点。这个验证过程虽然简单但它能帮你过滤掉 80% 的“模拟器无效”问题。5. 新 Input System 下的多点触控模拟5.1 为什么用新输入系统时要注意Unity 的新 Input System 引入了完全不同的触摸 API。如果你已经把项目切换到新的输入系统那么使用Input.touches可能不再有效需要改用Touchscreen来读取触摸数据。而且新输入系统对“模拟触摸设备”的识别方式和老版本不太一样。它把触摸屏看作一个 Input Device只有当模拟器真的创建了 Touchscreen 设备时Touchscreen.current才会返回非 null 值。很多时候你觉得模拟器有效但Touchscreen.current始终为空就是因为当前输入处理模式或者设备模拟没有被正确激活。5.2 使用 Touchscreen 读取触摸下面这段代码是新 Input System 下读取触摸点的最小示例把它挂到场景物体上即可// 文件路径Assets/Scripts/TouchscreenDebug.cs using UnityEngine; using UnityEngine.InputSystem; public class TouchscreenDebug : MonoBehaviour { void Update() { var touchscreen Touchscreen.current; if (touchscreen null) { Debug.Log(No touchscreen detected); return; } for (int i 0; i touchscreen.touches.Count; i) { var touch touchscreen.touches[i]; if (touch.press.isPressed) { Vector2 position touch.position.ReadValue(); Debug.Log($New Input Touch {i}: {position}); } } } }需要说明的是不同 Unity 版本的新 Input System API 可能会有细微差别比如部分字段名在不同版本中发生了变化。上面这段代码在 Unity 2021/2022 的常见版本中可以运行如果你用的是更新版本以官方 API 文档为准。当模拟器把鼠标转换成触摸后Touchscreen.current应该不再是 null。你也可以在OnEnable时候打印一次Touchscreen.current用来确认模拟设备是否被成功创建。5.3 新旧输入混用时的注意事项把Active Input Handling设置为 Both 后新旧两套 API 可以同时读取触摸。但有一个容易忽视的点两套输入系统对触摸事件的相位判断可能不同步比如旧 Input 已经开始 Move新 Input 可能还停留在 Began 状态。这个差异在编辑器模拟器环境下会更明显因为模拟器本身是在软件层面生成触摸数据不像真机有硬件中断的实时性。所以在实际开发中建议项目早期就确定“主输入方案”新项目、需要复杂输入逻辑直接使用新 Input System。老项目、只是给移动端加几个触摸手势继续使用旧 Input Manager。不建议为了兼容而长期混用否则模拟器调试和真机表现都可能出现偏差。6. 制作一个简单的触摸可视化调试窗口进阶6.1 为什么需要可视化调试窗口直接用 Debug.Log 打印触摸信息虽然简单但日志刷新太快很难看出触摸点的运动轨迹。如果能把触摸点实时绘制在某个窗口里调试起来会直观很多。下面我们用 C# 脚本加 EditorWindow 做一个轻量级触摸可视化窗口你可以把它理解成“自建 Multi-touch Simulator 监视面板”。整体思路是在运行时由一个 MonoBehaviour 收集当前帧的触摸数据保存到静态字段中编辑器窗口每隔一段时间读取这些静态字段并在窗口中画圆和坐标信息。6.2 静态数据容器脚本先写一个 MonoBehaviour负责从 Input 系统中提取触摸数据并保存到一个静态结构中。// 文件路径Assets/Scripts/TouchVisualizer.cs using UnityEngine; using System.Collections.Generic; public class TouchVisualizer : MonoBehaviour { public struct TouchInfo { public int id; public Vector2 position; } public static ListTouchInfo CurrentTouches new ListTouchInfo(); void Update() { CurrentTouches.Clear(); for (int i 0; i Input.touchCount; i) { Touch touch Input.GetTouch(i); CurrentTouches.Add(new TouchInfo { id touch.fingerId, position touch.position }); } } }将这个脚本挂到场景中的任意物体上。它本身不做任何渲染只是一个数据中转站。6.3 EditorWindow 绘制触摸点接下来创建编辑器窗口脚本注意要放在Editor文件夹下否则会在打包时被包含进去。// 文件路径Assets/Editor/TouchVisualizerWindow.cs using UnityEngine; using UnityEditor; public class TouchVisualizerWindow : EditorWindow { [MenuItem(Window/Touch Visualizer)] public static void Open() { GetWindowTouchVisualizerWindow(Touch Visualizer); } void OnGUI() { if (TouchVisualizer.CurrentTouches null) { return; } EditorGUILayout.LabelField(Running Touch Count, TouchVisualizer.CurrentTouches.Count.ToString()); foreach (var touch in TouchVisualizer.CurrentTouches) { EditorGUILayout.LabelField($Touch {touch.id}, touch.position.ToString()); } } void OnInspectorUpdate() { Repaint(); } }打开菜单Window Touch Visualizer点击 Play 后你就能在窗口中看到当前触摸点的位置。如果同时开启了双指模拟窗口会实时显示两个触摸点信息。这个示例虽然不像第三方插件那样把轨迹画成一幅图但它证明了“触摸数据可以从游戏逻辑中被摆到编辑器界面上”。如果你有需要可以继续扩展比如在窗口中用GUI.BeginGroup和GUI.Box画出手指点位甚至记录近几十帧的轨迹。7. 常见问题与排查手册7.1 常见问题速查表问题现象常见原因解决思路模拟器里鼠标拖动但Input.touchCount始终为 0没有进入 Simulator / Device Simulator 模式打开 Device Simulator并在播放模式下操作能模拟单指但无法模拟第二根手指没有找到 Add Touch 或对应快捷键查看 Device Simulator 工具栏的触摸模拟开关尝试 Shift / Ctrl / Alt 组合键脚本用Input.touches没反应Active Input Handling 只启用了新 Input System改为 Both 或旧 Input Manager新 Input System 下Touchscreen.current为 null模拟设备没有被正确识别安装并启用 Input System Package重启编辑器后再进入播放双指缩放方向相反delta正负号问题对比前后帧距离必要时调整delta符号触摸坐标在 UI 上不对屏幕坐标没有转换成 Canvas 坐标使用RectTransformUtility或Camera.ScreenToWorldPoint转换Device Simulator 窗口打不开项目构建平台或版本受限尝试 File Build Settings 切换到 Android / iOS 平台后再打开7.2 找不到模拟器入口有些 Unity 版本中只有当你把项目切换到 Android/iOS 平台后Game View 才会出现模拟器相关选项。如果你在工具栏看不到手指图标可以尝试打开Window General Device Simulator检查当前 Game View 的纵横比设置设置为“模拟设备”模式在 Project Settings Editor Device Simulator 中确认功能没有被关闭切换构建平台本身不会影响编辑器内的模拟但它会解锁一些平台相关的编辑器功能。7.3 UGUI 点击没有反应很多项目用IPointerDownHandler和 EventSystem 处理触摸点击。模拟器把鼠标转换成触摸后UGUI 是否能响应取决于两点场景中是否有 EventSystemEventSystem 的 Input Module 是否与新输入系统匹配如果 UI 对鼠标点击正常、对模拟触摸没有反应优先检查 EventSystem 上挂的是StandaloneInputModule还是InputSystemUIInputModule。如果你项目启用了新输入系统但场景里还是旧版 StandaloneInputModuleUGUI 可能不会把触摸点击识别为有效输入。7.4 触摸坐标不对模拟器里的屏幕分辨率会跟随设备模型设置变化。触摸坐标是绝对像素坐标它对应的是当前模拟屏幕的分辨率。如果你的 Game 视图不是设备分辨率触摸坐标和屏幕宽高比可能与预期不符。调试方式很简单用Screen.width和Screen.height打出来对比一下检查是否等于设备模拟器设定的分辨率。如果差异较大说明你并不是在正确的模拟分辨率下测试。8. 最佳实践与工程建议8.1 模拟器只能验证逻辑不能替代真机再强调一次Multi-touch Simulator 是“逻辑验证器”不是“手感验证器”。它能帮你快速发现双指缩放手势有没有触发、UI 是否挡住了触摸区域、坐标转换是否错误但它无法模拟真机的触摸采样率、多点触控硬件差异、系统手势冲突等问题。因此在项目排期里一定要留出真机回归测试时间。至少需要覆盖不同屏幕尺寸的手机不同系统版本横竖屏切换与系统手势边缘返回、通知栏滑动的冲突模拟器用得好能帮你提前修掉 90% 的纯逻辑错误让真机阶段专注于体验调优。8.2 手势识别分层设计我在实际项目里会把触摸处理拆成三层输入读取层从旧Input或新InputSystem读取触摸数据。手势识别层根据触摸点数量、位移、时间判断是 Tap、DoubleTap、Drag、Pinch、Rotate。业务响应层接收手势结果执行模型缩放、UI 切换、角色移动等行为。这样拆分的好处是将来从旧输入系统迁移到新输入系统时只需要改第一层UI 从 UGUI 换成 UI Toolkit 时只需要改第三层。中间的手势识别逻辑可以一直复用。8.3 屏幕坐标与 Canvas 坐标转换触摸数据是屏幕像素坐标和 Canvas 的本地坐标并不一样。当你想把 UI 元素移动到手指位置时不要直接赋值。UGUI 下推荐使用RectTransformUtility.ScreenPointToLocalPointInRectangle( canvasRectTransform, screenPoint, camera, out localPoint );3D 场景中可以使用Vector3 worldPos Camera.main.ScreenToWorldPoint(screenPoint);在模拟器里调试时尤其要注意 Canvas 的 Render Mode 和参考分辨率不同的设置会导致坐标比例不同。8.4 日志与条件编译每帧打印触摸信息在开发期很爽但到了发布版本就是性能灾难。建议给调试日志加上条件编译特性让它在非编辑器环境下自动消失。using UnityEngine; public class TouchLogHelper { [System.Diagnostics.Conditional(UNITY_EDITOR)] public static void Log(string message) { Debug.Log(message); } }用法很简单TouchLogHelper.Log($Current touch count: {Input.touchCount});这样发布版不会包含这些字符串拼接和 Debug.Log 调用对移动端性能更友好。9. 总结与下一步回到开头的场景如果你正被移动端多点触控折磨不妨先把 Multi-touch Simulator 用起来。打开 Device Simulator放一个打印触摸信息的脚本再放一个双指缩放脚本用十分钟确认整个触摸链路是通的。接下来再把手势识别、UI 坐标转换和真机验证逐一补齐你会发现移动端调试并没有想象中那么痛苦。这篇文章里提到的代码和技术思路基本覆盖了日常开发中最常用的部分。如果你的目标是做一个手势敏感的小游戏或交互应用下一步可以试着扩展这些脚本比如加入滑动速度判断、长按识别、三指手势、以及触摸轨迹可视化。把这些基础能力沉淀成自己的工具类后你会发现自己开发移动端项目的效率明显提升。如果你在模拟器里测试时发现了不同版本的第二指快捷键或者遇到过其他更隐蔽的问题欢迎在评论区分享出来。技术环境总是在变但“让编辑器更像真机”这件事值得我们持续折腾。