116 lines
4.5 KiB
Markdown
116 lines
4.5 KiB
Markdown
# InputModule 常见问题
|
||
|
||
## 编译错误
|
||
|
||
### `CS0117: 'GameEntry' does not contain a definition for 'InputModule'`
|
||
|
||
**原因:** 基座项目的 `GameEntry.Custom.cs` 中没有添加 `InputModule` 静态属性。
|
||
|
||
**解决:**
|
||
1. 在 `GameEntry.Custom.cs` 中添加:
|
||
```csharp
|
||
public static InputModuleComponent InputModule { get; private set; }
|
||
```
|
||
2. 在 `InitCustomComponents()` 中赋值:
|
||
```csharp
|
||
InputModule = UnityGameFramework.Runtime.GameEntry.GetComponent<InputModuleComponent>();
|
||
```
|
||
|
||
> 如果项目决定**不接入** InputModule,请确保场景中没有挂载 `VirtualJoystickBridge` / `VirtualButtonBridge`(或删除 `Presentation/` 目录)。这两个 bridge 会自动查找场景中的 `InputModuleComponent`,但不再硬编码依赖 `GameEntry.InputModule`。
|
||
|
||
### `The type or namespace name 'InputModuleComponent' could not be found`
|
||
|
||
**原因:** 使用了 `InputModuleComponent` 的代码所在程序集没有引用 `SepCore.Runtime` 或 `SepCore.InputModule.Base`。
|
||
|
||
**解决:** 检查相关 `.asmdef` 的 `references` 中是否包含 `SepCore.Runtime`(因为 `InputModuleComponent` 通过 `asmref` 编译进 `SepCore.Runtime`)。
|
||
|
||
### `SepCore.Presentation` 编译失败,找不到 `InputCommand` 等类型
|
||
|
||
**原因:** `SepCore.Presentation.asmdef` 没有引用 `SepCore.InputModule.Base`。
|
||
|
||
**解决:** 在 `SepCore.Presentation.asmdef` 的 `references` 中添加 `GUID:d54b9488b03814a44ab937f0aeb738b1`(即 `SepCore.InputModule.Base`)。
|
||
|
||
---
|
||
|
||
## 运行时问题
|
||
|
||
### Play 后输入没有反应
|
||
|
||
**检查清单:**
|
||
1. `Launcher` 场景中是否挂载了 `InputModuleComponent`
|
||
2. 启动 Procedure 中是否调用了 `GameEntry.InputModule?.OnInit()`
|
||
3. 当前上下文是否正确设置(默认初始化后为 `None`,需要 `SetContext` 或 `SetGameplayExploreContext`)
|
||
4. 是否有 listener 注册到了正确的 `InputActionId`
|
||
|
||
### UI 打开后 Gameplay 输入没有禁用
|
||
|
||
**原因:** 没有使用 `PushContext(InputContextId.Dialog)` 或 `SetContext(InputContextId.UI)`。
|
||
|
||
**解决:**
|
||
- 对于覆盖层弹窗(从 Gameplay 打开 Dialog):使用 `PushContext(InputContextId.Dialog)`,关闭时 `PopContext()`
|
||
- 对于大场景切换(Menu -> Main):使用 `SetContext(InputContextId.GameplayExplore)`
|
||
|
||
### 重绑后绑定没有保存
|
||
|
||
**原因:** `InputModuleComponent` 的 `_saveBindingOverridesOnDestroy` 为 `false`,且没有手动调用 `SaveBindingOverrides()`。
|
||
|
||
**解决:**
|
||
- 在 Inspector 中勾选 `_saveBindingOverridesOnDestroy`
|
||
- 或在重绑成功后手动调用 `GameEntry.InputModule.SaveBindingOverrides()`
|
||
|
||
### 重绑时报冲突
|
||
|
||
**原因:** 新绑定的按键与 Global map 或同一 map 内的其他 action 冲突。
|
||
|
||
**解决:** 当前设计不允许同设备冲突绑定。如果确实需要共享按键(例如同一按钮在不同上下文下做不同的事),应通过上下文切换来隔离,而不是把两个 action 绑定到同一个按键上。
|
||
|
||
---
|
||
|
||
## 设备与提示
|
||
|
||
### 手柄插入后 UI 提示没有刷新
|
||
|
||
**原因:** 没有监听 `DeviceKindChanged` 事件。
|
||
|
||
**解决:**
|
||
```csharp
|
||
GameEntry.InputModule.DeviceKindChanged += OnDeviceChanged;
|
||
|
||
private void OnDeviceChanged(InputDeviceKind kind)
|
||
{
|
||
// 刷新所有按键提示
|
||
}
|
||
```
|
||
|
||
### 触摸虚拟摇杆后设备类型没有变为 Touch
|
||
|
||
**原因:** `VirtualJoystickBridge` 的 `_injectDeviceKind` 为 `false`。
|
||
|
||
**解决:** 在 Inspector 中勾选 `_injectDeviceKind`。
|
||
|
||
---
|
||
|
||
## 设计约束
|
||
|
||
### 能否在业务代码里直接判断 `CurrentDeviceKind == Gamepad`?
|
||
|
||
**不推荐。** 业务层应消费 `InputCommand` 的语义值,设备判断留给 UI/Presentation 层。如果确实需要,建议通过 `DeviceKindChanged` 事件在 UI 层做适配,而不是分散在 gameplay 逻辑中。
|
||
|
||
### 为什么 UI 点击不经过 InputModule?
|
||
|
||
这是 P2 的设计决策:UI 原始输入(点击、拖拽、导航)继续由 Unity EventSystem 处理。InputModule 只负责 gameplay 语义输入和上下文切换。这样避免了双重分发和跨平台复杂度。
|
||
|
||
### 能否把 InputModule 完全独立成一个不依赖 UGF 的模块?
|
||
|
||
当前版本有 3 个地方依赖 UGF:
|
||
1. `InputModuleComponent` 继承自 `GameFrameworkComponent`
|
||
2. 绑定覆盖持久化使用 `SettingComponent`
|
||
3. `GameEntry` 接入约定
|
||
|
||
如果要完全剥离 UGF,需要:
|
||
- 把 `InputModuleComponent` 改为普通 `MonoBehaviour`
|
||
- 自己实现设置持久化接口
|
||
- 去掉 `GameEntry` 相关的接入模板
|
||
|
||
这不是当前 P6 的目标,但架构上 `Base` 层本身已经零依赖 UGF。
|