# 输入系统迁移指南 本指南帮助您从旧版 InputManager 迁移到新的 InputInterpreter 系统。 ## 迁移优势 - **组件化设计** - 告别单例模式,减少全局依赖 - **简化API** - 更直观的接口和清晰的类层次结构 - **更好的隔离性** - 不同输入域使用独立解释器实例 - **平台自适应** - 自动选择最适合当前平台的输入处理方式 ## 架构对比 **旧系统**:全局 InputManager 单例处理所有输入事件 **新系统**:组件式 InputInterpreter,通过工厂方法创建,支持多实例 ## InputInterpreter 类型说明 | 类型 | 说明 | 适用场景 | |------|------|----------| | `AutoPlatform` | 根据平台自动选择适合的输入解释器 | 通用场景,自动适配 | | `AutoPlatform_ExcludeUI` | 自动选择并忽略UI区域的输入 | 游戏主场景,避免UI交互冲突 | | `Touch` | 触摸输入解释器 | 移动设备,处理所有触摸 | | `Touch_ExcludeUI` | 忽略UI区域的触摸输入 | 移动设备游戏场景 | | `PC` | 鼠标键盘输入解释器 | PC平台 | | `PC_ExcludeUI` | 忽略UI区域的鼠标输入 | PC平台游戏场景 | | `UI` | 基于Unity UI系统的输入解释器 | 与UI系统集成,处理UI事件 | ## 迁移步骤 ### 1. 创建解释器实例 ```csharp // 旧系统: 使用全局单例 InputManager.Instance.DoSomething(); // 新系统: 创建专用实例 InputInterpreter inputInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.AutoPlatform, // 解释器类型,参见上表 "MainInput", // 名称(用于创建的GameObject命名) this, // 处理器实现(IMobileInputEventHandler接口) false // 可选:dontDestroyOnLoad,默认为false ); ``` ### 2. 处理输入事件 ```csharp // 旧系统: 事件订阅 InputManager.Instance.OnTap += HandleTap; // 新系统: 实现接口方法 public class MyController : MonoBehaviour, IMobileInputEventHandler { // 必须实现所有接口方法 public void OnTap(Vector2 position) { /* 单次点击 */ } public void OnPressMove(Vector2 delta) { /* 拖动,delta为移动距离 */ } public void OnPointerDown(Vector2 position) { /* 按下时触发 */ } public void OnPointerUp(Vector2 position) { /* 抬起时触发 */ } public void OnLongPress(Vector2 position) { /* 长按开始触发 */ } public void OnLongPressUp(Vector2 position) { /* 长按结束触发 */ } public void OnZoom(float delta) { /* 缩放,delta为缩放比例变化 */ } } ``` ### 3. 控制输入状态 ```csharp // 启用/禁用输入处理 inputInterpreter.enabled = false; // 禁用整个解释器 inputInterpreter.IsLocked = true; // 锁定输入但保持对象活跃 // 切换输入模式:销毁旧解释器,创建新解释器 Destroy(inputInterpreter.gameObject); inputInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.Touch_ExcludeUI, "UIInput", this ); ``` ### 4. 处理多输入域 ```csharp // 为不同域创建多个解释器 InputInterpreter uiInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.PC, // 处理所有输入 "UIInput", uiHandler ); InputInterpreter gameInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.PC_ExcludeUI, // 忽略UI区域输入 "GameInput", gameHandler ); // 通过启用/禁用控制优先级 uiInterpreter.enabled = true; gameInterpreter.enabled = false; ``` ### 5. 资源清理 ```csharp // 销毁解释器(两种方式均可) if (inputInterpreter != null) { inputInterpreter.Destroy(); // 推荐方式,会自动处理相关资源 // 或 // Destroy(inputInterpreter.gameObject); } ``` ## 使用UIInputInterpreter UIInputInterpreter是一个特殊的解释器,直接与Unity的UI系统集成,用于将UI事件转换为输入事件。 ### 创建基于现有UI对象的解释器 ```csharp // 获取一个UI对象(例如按钮、面板等) GameObject uiObject = GameObject.Find("MyUIPanel"); // 创建基于此UI对象的输入解释器 UIInputInterpreter uiInterpreter = UIInputInterpreterFactory.CreateInterpreter( uiObject, // 目标UI对象 "UIInterpreter", // 名称 this, // 处理器 true, // 是否阻止事件继续传播(默认true) false // 是否不随场景销毁(默认false) ); // 配置长按触发时间 uiInterpreter.SetLongPressThreshold(0.8f); ``` ### 创建全屏覆盖的解释器 ```csharp // 创建一个覆盖整个屏幕的透明输入层,用于捕获所有UI事件 UIInputInterpreter fullscreenInterpreter = UIInputInterpreterFactory.CreateFullScreenInterpreter( "FullscreenInput", // 名称 this, // 处理器 100, // Canvas排序顺序(越大越前,默认为32767) false // 是否不随场景销毁 ); ``` ### 与其他解释器并用 UIInputInterpreter可以与其他类型的解释器并存,用于处理不同的输入域: ```csharp // 创建处理UI操作的解释器 UIInputInterpreter uiInterpreter = UIInputInterpreterFactory.CreateInterpreter( uiCanvasObject, "UIInput", uiHandler ); // 创建处理游戏区操作的解释器 InputInterpreter gameInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.AutoPlatform_ExcludeUI, "GameInput", gameHandler ); // 通过启用/禁用来控制输入优先级 public void SwitchToUIMode() { uiInterpreter.enabled = true; gameInterpreter.enabled = false; } public void SwitchToGameMode() { uiInterpreter.enabled = false; gameInterpreter.enabled = true; } ``` ## 完整示例 ```csharp using UnityEngine; using Framework; public class InputExample : MonoBehaviour, IMobileInputEventHandler { private InputInterpreter inputInterpreter; private void Start() { // 创建与当前平台匹配的解释器,忽略UI区域输入 inputInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.AutoPlatform_ExcludeUI, "GameInput", this ); // 配置解释器参数(可选) inputInterpreter.LongPressTime = 0.8f; // 设置长按触发时间 inputInterpreter.TapIntervalTime = 0.3f; // 设置连续点击间隔 } // 实现所需接口方法 public void OnTap(Vector2 position) { Debug.Log($"点击: {position}"); } public void OnPressMove(Vector2 delta) { Debug.Log($"拖动: {delta}"); } public void OnPointerDown(Vector2 position) { } public void OnPointerUp(Vector2 position) { } public void OnLongPress(Vector2 position) { } public void OnLongPressUp(Vector2 position) { } public void OnZoom(float delta) { } private void OnDestroy() { if (inputInterpreter != null) inputInterpreter.Destroy(); } } ``` ## 常见问题 **Q: 输入事件没有触发?** A: 确保正确实现了所有必需的接口方法,且解释器创建时传入了正确的处理器。检查解释器对象是否启用(enabled),以及是否被锁定(IsLocked)。 **Q: 如何处理UI上的输入?** A: 使用不排除UI的解释器类型,如 `InputInterpreterType.Touch` 或 `InputInterpreterType.PC`。或者使用 `UIInputInterpreter` 直接在UI对象上处理输入事件。 **Q: 解释器在场景切换后不工作?** A: 创建解释器时设置 `dontDestroyOnLoad` 参数为 `true`,例如: ```csharp inputInterpreter = InputInterpreterFactory.CreateInterpreter( InputInterpreterType.AutoPlatform, "PersistentInput", this, true // 设置为不随场景销毁 ); ``` **Q: 如何访问输入状态?** A: InputInterpreter 提供了各种方法查询当前输入状态: ```csharp bool isTouching = inputInterpreter.HasTouch(); Vector2 touchPos = inputInterpreter.GetTouchPosition(); Vector2 touchDelta = inputInterpreter.GetTouchDelta(); ``` **Q: UIInputInterpreter与普通解释器有什么区别?** A: UIInputInterpreter直接与Unity UI系统集成,可以捕获UI事件并转发为标准输入事件。它适用于需要与UI交互的场景,可以直接附加在UI对象上或创建全屏覆盖层。