10

update()每秒运行 n 次方法来“更新”用户的键盘输入,以便稍后在程序的逻辑部分中读取它。所以我在 SDL Docs 中找到了两种实现方法,但我不确定应该使用哪一种。

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.");

另外,还有其他方法吗?

4

3 回答 3

10

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

SDL 还会在按键被按下时发送按键事件,这样您就可以为每个按键设置多个按键事件。我发现这在通过项目列表实现键盘滚动时特别有用,例如键盘控制的菜单。

于 2012-07-28T19:39:09.780 回答
5

您应该使用解决方案 2。

为什么?正如SDL_GetKeyState()文档指出的那样,在使用它之前,您应该调用SDL_PumpEvents()以更新状态数组。

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

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

于 2012-07-28T08:24:04.587 回答
4

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

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

然后你会为释放做相反的事情。我发现该方法非常易于实施和使用。

于 2016-02-27T01:48:50.467 回答