使用SDL从键盘读取输入的最佳方式是什么



我每秒运行一个update()方法n次;"更新";用户的键盘输入,这样我以后就可以在程序的逻辑部分中读取它。因此,我在SDL文档中找到了两种实现方法,但我不确定应该使用哪一种。

1;使用SDL_PollEvent循环所有事件,搜索按键按下/按下事件,并将关键状态保存在映射中,这样我就可以检查程序逻辑中的每个关键状态。

注意:或者,我也可以使用SDL_PeepEvents而不是SDL_PollEvent来只获取重要的事件类型;因此,它不会";扔掉";队列上的事件。

std::map<int, bool> keyboard; // Saves the state(true=pressed; false=released) of each SDL_Key.
    
void update()
{
    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
        switch(event.type)
        {
            case SDL_KEYDOWN:
                keyboard[event.key.keysym.sym] = false;
                break;
            case SDL_KEYUP:
                keyboard[event.key.keysym.sym] = true;
                break;
        }
    }
}

2;从键盘上每帧拍一张快照,这样我就可以很容易地阅读了。

Uint8* keyboard;
    
void update()
{
    SDL_PumpEvents();
    keyboard = SDL_GetKeyState(NULL);
}

使用以上任何一种实现,我都可以像这样读取keyboard

if (key_map[SDLK_Return]) printf("Return has been pressed.");

此外,还有其他方法吗?

我更喜欢做1的变体,填充三个数组,不仅指示当前状态,还指示哪些键刚刚下降,哪些键刚刚上升。这使我可以轻松地在代码中检查这些事件(而无需与以前的快照进行比较),但最重要的是,它不会错过持续时间不到一帧的事件。例如,如果你的游戏由于机器速度慢而以每秒10帧的速度运行,用户可能会在两次调用更新例程之间按下并释放一个重要键,然后你的系统将永远不会注册它。这非常令人沮丧。

SDL还会在按下按键时发送按键事件,这允许您在每次按下按键时都有多个按键按下事件。我发现这在实现键盘滚动项目列表时特别有用,例如键盘控制的菜单。

您应该使用解决方案2。

为什么?正如SDL_GetKeyState()文档所指出的,在使用它之前,您需要调用SDL_PumpEvents()来更新状态数组。

当您调用SDL_PollEvent()时,它会隐式调用SDL_PumpEvents()。因此,它基本上更新了SDL_GetKeyState()的数组。通过手动解析这些事件,您只需创建第二个数组(实际上是一个慢得多的映射),其中包含SDL已经为您收集的相同信息。

所以,我敢说,第一个解决方案意味着两次做同样的事情。如果您决定支持重复按键(SDL_EnableKeyRepeat()),那么您将重新实现SDL的更大部分。

我意识到这个问题已经很老了,但我的回答可能会让一些人受益。就我个人而言,我使用了两个带有SDL_GetKeyState的数组。我存储一个数组来保存当前帧的键盘状态,另一个数组保存最后一帧的键盘状况。(有了一些memcpy命令,更新它们真的很容易。)除了这两个数组,我还有一个映射,可以将"a"之类的字符串转换为SDL扫描代码值,但这是可选的。

然后,当您需要检查某个东西是否被释放或按下时,您可以将这两个数组组合起来进行检查。(我把它作为一个函数。)例如,如果你知道这个键是在这一帧按下的,但上一帧没有按下,那么它显然只是在这一框按下的。if (currentFrame["A"] == true && lastFrame["A"] == false) {/*just pressed*/}

然后你会对被释放的人采取相反的做法。我发现这种方法非常容易实现和使用。

最新更新