我将 WM_KEYDOWN 和 WM_KEYUP 与地图结合使用来处理按键事件,但当我同时按下太多按键时,它会产生滞后。
下面是我用来处理此事件的代码。
std::map<Key, KeyStatus> StatusKey;
void UpdateKeyEvent(const MSG& msg) noexcept
{
switch (msg.message)
{
case WM_KEYDOWN:
SetStatusKey(msg.wParam);
return;
case WM_KEYUP:
ReUpStatusKey(msg.wParam);
return;
}
}
void SetStatusKey(const WPARAM& wParam) noexcept
{
Key key = static_cast<Key>(wParam);
if (StatusKey.find(key) == StatusKey.end()) {
StatusKey.insert(std::make_pair(key, Down));
return;
}
else {
if (StatusKey[key] == NONE_GET || StatusKey[key] == Up) {
StatusKey[key] = Down;
}
}
}
void UpdateStatusKey() noexcept
{
for (auto& Key : StatusKey)
{
if (Key.second == Down)
{
Key.second = Hold;
}
}
}
void ReUpStatusKey(const WPARAM& wParam) noexcept
{
Key key = static_cast<Key>(wParam);
StatusKey[key] = Up;
}
float GetKeyRaw(const Key& key) noexcept
{
if (StatusKey.find(key) != StatusKey.end()) {
if (StatusKey[key] != Up && StatusKey[key] != NONE_GET) {
return 1.0f;
}
}
return 0.0f;
}
在主循环中,我像这样使用 UpdateKeyEvent
while (TRUE)
{
if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
EventMessage::UpdateKeyEvent(Msg);
if (Msg.message == WM_QUIT)
break;
}
}
简而言之,我当前使用 Windows 消息循环实现的键盘输入处理可能有太多缺陷。我希望得到大家关于如何优化我的输入处理代码的建议。谢谢你!
PS: 我尝试使用 GetKeyState、GetAsyncKeyState 和 GetKeyboardState,但它们的功能与我上面编码的方式并不完全相同。
想法#1
您的 SetStatusKey 似乎正在进行三次查找。一次使用
find
调用,然后使用 StatusKey[key] ==
比较进行两次额外查找。
更改此:
void SetStatusKey(const WPARAM& wParam) noexcept
{
Key key = static_cast<Key>(wParam);
if (StatusKey.find(key) == StatusKey.end()) {
StatusKey.insert(std::make_pair(key, Down));
return;
}
else {
if (StatusKey[key] == NONE_GET || StatusKey[key] == Up) {
StatusKey[key] = Down;
}
}
}
对此:
void SetStatusKey(const WPARAM& wParam) noexcept
{
Key key = static_cast<Key>(wParam);
auto itor = StatusKey.find(key);
KeyStatus status = itor == StatusKey.end() ? NONE_GET : itor->second;
if (status == NONE_GET || status == Up)
{
StatusKey[key] = Down;
}
}
想法#2
停止使用
std::map
并使用 std::unordered_map
代替。 O(lg N) 与 O(1) 性能权衡。
想法#3
只需使用数组即可。
KeyStatus StatusKey[256] = {};
在代码中的某个位置,您可以在主循环开始之前将数组初始化为所有
Up
或 NONE_GET
值。那么您不需要使用 .find() 或任何其他方法。您可以像这样直接访问数组:
BYTE keyIndex = (BYTE)wParam;
StatusKey status = StatusKey[keyIndex];
if (status == NONE_GET || status == Up)
{
StatusKey[key] = Down;
}
想法#4。与 #3 类似,但不要使用 WM_KEYDOWN 或 WM_KEYUP 消息来保持按键状态更新。只需在游戏循环的每次迭代中使用
GetKeyboardState
函数轮询整个键盘状态即可。很久以前,当我在游戏工作室工作时,这就是我们用来在每一帧上轮询键盘的方法。