3.5 KiB
3.5 KiB
Input Flow And Frame Semantics
这套输入系统怎么理解
当前 XCEngine 输入系统更接近“轻量级、同步、帧驱动的输入管理器”,而不是完整设备抽象框架。
它有两个核心层:
InputModule负责接平台消息。InputManager负责保存状态并提供事件与查询接口。
这意味着真正的输入流向是:
- 平台窗口系统产生命令或消息。
- 平台后端把消息翻译成
ProcessKeyDown、ProcessMouseMove一类调用。 InputManager更新状态并同步广播事件。- 游戏或工具层在当前帧读取轮询状态。
Update()在帧边界清理瞬时状态。
为什么同时保留事件和轮询
事件和轮询各有适合的地方:
- UI、输入法、编辑器面板更适合订阅事件。
- 游戏逻辑、相机控制、角色移动更适合每帧轮询。
InputManager 同时提供这两种方式,是为了避免你在上层自己重复维护一套输入缓存。
帧边界怎么理解
当前实现里,Update() 不是“采集输入”,而是“结束上一帧的瞬时状态”。
它会清理:
IsKeyPressed依赖的本帧按下标记IsMouseButtonClicked依赖的本帧点击标记GetMouseDeltaGetMouseScrollDelta
所以最重要的实践是:
- 每帧只调用一次
Update()。 - 保持调用时机一致。
- 在清理之前,先消费掉当前帧的瞬时输入。
和 Unity 的对照
从使用方式上看,InputManager 很像 Unity 旧版 Input Manager:
- 有具名轴:
Horizontal、Vertical - 有具名按钮:
Jump、Fire1、Fire2、Fire3 - 查询接口偏向
GetAxis/GetButton
但当前实现并不等同于 Unity:
- 没有平滑、重力、灵敏度、死区等高级参数。
GetAxisRaw当前只在“按下这一帧”返回非零,不等同于 Unity 中“原始持续值”的语义。Mouse X和Mouse Y默认虽然被注册了,但当前实现并不会通过鼠标移动更新它们。
平台桥接是怎么接进来的
InputModule 的意义是把平台消息层隔离掉。当前 Windows 路径里:
WindowsInputModule::HandleMessage负责处理WM_KEYDOWN、WM_MOUSEMOVE、WM_MOUSEWHEEL等消息。- 它再调用
InputManager::Process*统一更新状态。
这样做的好处是:
- 游戏层不用知道 Win32 消息细节。
- 将来如果换 GLFW、SDL 或其它平台层,
InputManager可以不变。
当前版本最该知道的限制
KeyCode底层值当前有重复,部分键会共享状态槽。- Windows 路径当前不能准确区分左右 Ctrl / Alt / Shift。
- 触摸与摇杆接口基本是预留位。
- 事件回调是同步执行的,不是异步消息队列。
Shutdown()当前不会清空事件监听器;如果单例跨生命周期反复初始化,要自己管理订阅者。
推荐使用方式
初始化阶段:
using namespace XCEngine::Input;
InputManager::Get().Initialize(windowHandle);
平台消息阶段:
windowsInputModule.HandleMessage(hwnd, msg, wParam, lParam);
游戏逻辑阶段:
if (InputManager::Get().GetButton("Jump")) {
// ...
}
帧边界阶段:
InputManager::Get().Update(deltaTime);