NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/Input/MigrationGuide.md

8.3 KiB
Raw Blame History

输入系统迁移指南

本指南帮助您从旧版 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. 创建解释器实例

// 旧系统: 使用全局单例
InputManager.Instance.DoSomething();

// 新系统: 创建专用实例
InputInterpreter inputInterpreter = InputInterpreterFactory.CreateInterpreter(
    InputInterpreterType.AutoPlatform,  // 解释器类型,参见上表
    "MainInput",                        // 名称用于创建的GameObject命名
    this,                               // 处理器实现IMobileInputEventHandler接口
    false                               // 可选dontDestroyOnLoad默认为false
);

2. 处理输入事件

// 旧系统: 事件订阅
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. 控制输入状态

// 启用/禁用输入处理
inputInterpreter.enabled = false;  // 禁用整个解释器
inputInterpreter.IsLocked = true;  // 锁定输入但保持对象活跃

// 切换输入模式:销毁旧解释器,创建新解释器
Destroy(inputInterpreter.gameObject);
inputInterpreter = InputInterpreterFactory.CreateInterpreter(
    InputInterpreterType.Touch_ExcludeUI,
    "UIInput",
    this
);

4. 处理多输入域

// 为不同域创建多个解释器
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. 资源清理

// 销毁解释器(两种方式均可)
if (inputInterpreter != null)
{
    inputInterpreter.Destroy();  // 推荐方式,会自动处理相关资源
    // 或
    // Destroy(inputInterpreter.gameObject);
}

使用UIInputInterpreter

UIInputInterpreter是一个特殊的解释器直接与Unity的UI系统集成用于将UI事件转换为输入事件。

创建基于现有UI对象的解释器

// 获取一个UI对象例如按钮、面板等
GameObject uiObject = GameObject.Find("MyUIPanel");

// 创建基于此UI对象的输入解释器
UIInputInterpreter uiInterpreter = UIInputInterpreterFactory.CreateInterpreter(
    uiObject,                  // 目标UI对象
    "UIInterpreter",           // 名称
    this,                      // 处理器
    true,                      // 是否阻止事件继续传播默认true
    false                      // 是否不随场景销毁默认false
);

// 配置长按触发时间
uiInterpreter.SetLongPressThreshold(0.8f);

创建全屏覆盖的解释器

// 创建一个覆盖整个屏幕的透明输入层用于捕获所有UI事件
UIInputInterpreter fullscreenInterpreter = UIInputInterpreterFactory.CreateFullScreenInterpreter(
    "FullscreenInput",        // 名称
    this,                     // 处理器
    100,                      // Canvas排序顺序越大越前默认为32767
    false                     // 是否不随场景销毁
);

与其他解释器并用

UIInputInterpreter可以与其他类型的解释器并存用于处理不同的输入域

// 创建处理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;
}

完整示例

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.TouchInputInterpreterType.PC。或者使用 UIInputInterpreter 直接在UI对象上处理输入事件。

Q: 解释器在场景切换后不工作?
A: 创建解释器时设置 dontDestroyOnLoad 参数为 true,例如:

inputInterpreter = InputInterpreterFactory.CreateInterpreter(
    InputInterpreterType.AutoPlatform,
    "PersistentInput",
    this,
    true  // 设置为不随场景销毁
);

Q: 如何访问输入状态?
A: InputInterpreter 提供了各种方法查询当前输入状态:

bool isTouching = inputInterpreter.HasTouch();
Vector2 touchPos = inputInterpreter.GetTouchPosition();
Vector2 touchDelta = inputInterpreter.GetTouchDelta();

Q: UIInputInterpreter与普通解释器有什么区别?
A: UIInputInterpreter直接与Unity UI系统集成可以捕获UI事件并转发为标准输入事件。它适用于需要与UI交互的场景可以直接附加在UI对象上或创建全屏覆盖层。