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

252 lines
8.3 KiB
Markdown
Raw Normal View 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. 创建解释器实例
```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对象上或创建全屏覆盖层。