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