【问题标题】:What is the best way to read input from keyboard using SDL?使用 SDL 从键盘读取输入的最佳方法是什么?
【发布时间】:2012-07-26 19:17:21
【问题描述】:

我每秒运行 n 次 update() 方法来“更新”用户的键盘输入,以便稍后在程序的逻辑部分中读取它。所以我在 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.");

另外,还有其他方法吗?

【问题讨论】:

  • 1只是手动实现了2,2有什么问题?您为什么要寻找不同的解决方案?

标签: input keyboard sdl


【解决方案1】:

您应该使用解决方案 2。

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

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

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

【讨论】:

  • 是的,我忘记了第二个解决方案中的 SDL_PumpEvents(),我将编辑帖子:D 谢谢
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      • 1970-01-01
      • 2010-09-06
      • 2013-05-07
      • 2017-03-08
      • 2013-02-03
      • 2010-09-24
      相关资源
      最近更新 更多