【问题标题】:SDL2 Key repeat delaySDL2 键重复延迟
【发布时间】:2014-02-14 05:11:50
【问题描述】:

我正在尝试使用 SDL 2.0.1 开发强大的游戏输入系统。我希望完全没有输入延迟。

我以前使用SDL_GetKeyboardState() 来做这件事,但我改用SDL_EventSDL_PollEvent() 来为键盘、鼠标和操纵杆输入提供统一的界面(一切都通过事件完成)。

这很好用,但如果我想在按住键时连续输入(例如移动字符),在 SDL 注意到键被重复之前会有一点延迟。

在 SDL 1.2 中,可以使用函数调用来设置此延迟。现在它不再(据我所知)。

如何消除这种延迟?我应该切换回直接读取键盘状态吗?

作为参考,这是我目前获得输入的方式...

SDL_Event sdlEvent;
while (running)
{
    SDL_PollEvent(&sdlEvent);
    switch (sdlEvent.type)
    {
    case SDL_QUIT:
        running = false;
        break;
    case SDL_KEYDOWN:
        printf("Key down!\n");
        break;
    default:
        break;
    }
}

应用程序打印"Key down!",然后在一小段时间(大约一秒)内什么也没有,然后重复打印直到按键被释放。

那么我该如何摆脱这种延迟呢?

【问题讨论】:

  • 在此期间您是否收到该键的SDL_KEYUP 事件?
  • 没有。在我释放密钥之前,这都是SDL_KEYDOWN 事件。然后它是SDL_KEYUP 事件的恒定流(直到我移动鼠标或按下另一个键,所以我猜如果没有事件,SDL_PollEvent(&sdlEvent) 不会改变sdlEvent - 有趣)。

标签: c keyboard-events sdl-2


【解决方案1】:

here 所述,跨平台工作的正确过程是使用 SDL 密钥状态而不是事件:

const Uint8* keystates = SDL_GetKeyboardState(NULL);

if(keystates[SDL_SCANCODE_DOWN])
{
    printf("Key down!\n");    
}

通过这种方式,您可以绕过任何基于操作系统的键盘延迟。 完整教程: http://lazyfoo.net/tutorials/SDL/18_key_states/index.php

【讨论】:

    【解决方案2】:

    由于您没有获得SDL_KEYUP,因此您可以只获得bool,即true,直到您获得SDL_KEYUP

    SDL_Event sdlEvent;
    while (running)
    {
        bool keyDown = false;
        while ( SDL_PollEvent(&sdlEvent) )
        {
            switch (sdlEvent.type)
            {
                case SDL_QUIT:
                    running = false;
                    break;
                case SDL_KEYDOWN:
                    keyDown = true;
                    break;
                case SDL_KEUP:
                    keyDown = false;
                    break;
                default:
                    break;
            }
        }
        if ( keyDown )
            printf("Key down!\n");
    }
    

    当然,您需要一些东西来存储所有键,例如数组。 (或者更好;使用C++std::map)然后你可以使用SDL_Keycodeevent.key.keysym.sym)作为键。

    【讨论】:

    • 这段代码会和最初的错误一样,每帧只会检查堆栈上的第一个事件。
    • @jordsti Ahh... 当然,没看到它没有放在循环中
    • 你把我引向了正确的方向。当我使用动作(作为字符串)和回调时,我现在保留了一组应该被触发的动作。在 keydown 上,我将相关操作添加到集合中。在 keyup 上,我将其删除。完美运行。谢谢!
    • @RaptorDotCpp 没问题。祝你游戏好运! =)
    【解决方案3】:

    首先,您应该将您的事件轮询到一个循环中,否则您每帧只会获得一个事件 所以

    SDL_Event sdlEvent;
    while (running)
    {
        while(SDL_PollEvent(&sdlEvent))
        {
            switch (sdlEvent.type)
            {
            case SDL_QUIT:
                running = false;
                break;
            case SDL_KEYDOWN:
                printf("Key down!\n");
                break;
            default:
                break;
            }
        }
    }
    

    并且,为了处理您的按键延迟,应该创建一个按键按下的结构,以及按键启动时的时间戳。您可以将这些结构放入向量中,然后在为该键捕获键时将其删除。要处理按键延迟,只需向下迭代您的按键,并检查当前时间戳和按键初始时间戳之间的差异。

    【讨论】:

    • 时间戳的用途是什么?只要在收到SDL_KEYDOWN 时将bool 设置为true,并且在收到SDL_KEYUP 之前不将其设置为false,就不会有延迟。
    • this -> 然后在一小段时间(大约一秒钟)内什么也没有,然后重复打印,直到松开按键。使用布尔值,它也可以工作,但仅适用于一个键或操作,如果您想对多个键执行此操作,那就是这样做的方法。
    • 只要bool 保持设置为true,就会解决这个问题。除非我误解了,否则他不想要延迟,因此不需要时间戳。
    • 是的,你需要一个时间戳,如果你想每秒重复你的动作绑定到你的键,你需要知道最后一个动作的时间是什么时候......
    • 他的应用程序就是这样做的。它打印“Key Down”,然后一秒钟没有任何东西,然后它连续打印“Key Down”。据我了解,他希望它每帧都打印“Key Down”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-03
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    相关资源
    最近更新 更多