C++ SDL2运行得太快了——为什么我只按一个按钮,它就会读取多个输入?

C++ SDL2运行得太快了——为什么我只按一个按钮,它就会读取多个输入?,c++,sdl,sdl-2,C++,Sdl,Sdl 2,我已经开始编写SDL2程序。我希望integercount在用户按向右箭头键时上升一个,在用户按向左键时下降一个 #include <iostream> #include <SDL2/SDL.h> int main(){ SDL_Window *window= SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);

我已经开始编写SDL2程序。我希望integer
count
在用户按向右箭头键时上升一个,在用户按向左键时下降一个

#include <iostream>
#include <SDL2/SDL.h>

int main(){
    SDL_Window *window= SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
    int count=      0;
    bool isRunning= true;
    SDL_Event ev;
    while(isRunning){
        if(SDL_PollEvent(&ev)){
            if(ev.type == SDL_QUIT  ||  ev.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
                return 0;
        }

        const Uint8 *keystate=    SDL_GetKeyboardState(NULL);

        if(keystate[SDL_SCANCODE_LEFT])
            --count;
        else if(keystate[SDL_SCANCODE_RIGHT])
            ++count;

        std::cout << count << std::endl;
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}
当我快速点击右箭头键时,我希望
count
只增加一个,但它却从
0
增加到
4

为什么?

如何解决此问题?

类似于(它实际上询问鼠标按钮,但键盘也是如此):

不要使用键盘状态,而是使用SDL事件。SDL每按下一个按钮将触发一个事件,而快速
while
-循环可以在一次按键过程中触发多次。

类似于(它实际上询问鼠标按钮,但键盘也是如此):


不要使用键盘状态,而是使用SDL事件。SDL每按下一个按钮将触发一个事件,而快速
while
-循环可以在一次按键过程中触发多次。

即使该示例远不是一个最小的、完整的示例,并且它无法编译,我想问题可能是由于缺少对
SDL\u PumpEvents
的调用

自以下日期起:

注意:使用SDL_PumpEvents()更新状态数组

否则,状态数组将不会被更新,并且不会产生您正在经历的结果

注意

也就是说,尝试依赖事件,而不是用来表示键盘的内部状态数组

编辑

问题更新后更新

您应该将
SDL\u polleevent
上的
if
替换为
while
,如下所示:

while (SDL_PollEvent(&event)) {
    // here you have an event, you can use it
}
否则,即使没有事件,它也会跳过
if
并遍历其他语句。
这意味着,如果没有任何事件,键盘的状态在第一次按键后不会被更新,但您仍然会对其进行迭代


有关
SDL_polleevent
如何工作的更多详细信息,请参阅。

尽管示例远不是一个最小的、完整的示例,而且它无法编译,但我想问题可能是由于缺少对
SDL_PumpEvents
的调用

自以下日期起:

注意:使用SDL_PumpEvents()更新状态数组

否则,状态数组将不会被更新,并且不会产生您正在经历的结果

注意

也就是说,尝试依赖事件,而不是用来表示键盘的内部状态数组

编辑

问题更新后更新

您应该将
SDL\u polleevent
上的
if
替换为
while
,如下所示:

while (SDL_PollEvent(&event)) {
    // here you have an event, you can use it
}
否则,即使没有事件,它也会跳过
if
并遍历其他语句。
这意味着,如果没有任何事件,键盘的状态在第一次按键后不会被更新,但您仍然会对其进行迭代


有关
SDL\u polleevent
工作原理的更多详细信息,请参阅。

我在
循环时更改了

while(isRunning){
    while(SDL_PollEvent(&ev)){
        if(ev.type == SDL_QUIT  ||  ev.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
            return 0;
        else if(ev.type == SDL_KEYDOWN){
            if(ev.key.keysym.scancode == SDL_SCANCODE_LEFT){
                --count;
                std::cout << count << std::endl;
            }
            else if(ev.key.keysym.scancode == SDL_SCANCODE_RIGHT){
                ++count;
                std::cout << count << std::endl;
            }
        }
    }
}
然后离开:

4
3
2
1
0

我将
循环更改为以下内容:

while(isRunning){
    while(SDL_PollEvent(&ev)){
        if(ev.type == SDL_QUIT  ||  ev.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
            return 0;
        else if(ev.type == SDL_KEYDOWN){
            if(ev.key.keysym.scancode == SDL_SCANCODE_LEFT){
                --count;
                std::cout << count << std::endl;
            }
            else if(ev.key.keysym.scancode == SDL_SCANCODE_RIGHT){
                ++count;
                std::cout << count << std::endl;
            }
        }
    }
}
然后离开:

4
3
2
1
0

您的问题是向SDL请求一个keystate数组,在您的场景中,这不是最好的方法。那么,SDL在这种情况下做什么?它只提供一个包含信息的数组,不管当前密钥是否被持有。你试着尽可能短地按下按钮,但是你的循环时间真的很快。因此,要解决这个问题,您可以使用事件系统的按键功能,当您按下一个按钮时,该功能会为您提供true(按键释放事件的配对是
SDL\u KEYUP

主要的区别在于:是按键被按住了,还是我只是按下并改变了它的状态

下面是一个示例(在SDL_PumpEvent或SDL_PollEvent中使用):

请注意,此方法不使用扫描代码,而是使用键代码。(由于键盘类型不同,它们可能产生与扫描码不同的结果)<代码>SDLK
常量都是键代码。此外(如果你想玩游戏的话),扫描代码有利于玩家移动,按键事件有利于GUI元素

有关更多信息,请参阅:

我希望你能理解!
Lasoloz

您的问题是向SDL请求一个keystate数组,在您的场景中,这不是最好的方法。那么,SDL在这种情况下做什么?它只提供一个包含信息的数组,不管当前密钥是否被持有。你试着尽可能短地按下按钮,但是你的循环时间真的很快。因此,要解决这个问题,您可以使用事件系统的按键功能,当您按下一个按钮时,该功能会为您提供true(按键释放事件的配对是
SDL\u KEYUP

主要的区别在于:是按键被按住了,还是我只是按下并改变了它的状态

下面是一个示例(在SDL_PumpEvent或SDL_PollEvent中使用):

请注意,此方法不使用扫描代码,而是使用键代码。(由于键盘类型不同,它们可能产生与扫描码不同的结果)<代码>SDLK
常量都是键代码。此外(如果你想玩游戏的话),扫描代码有利于玩家移动,按键事件有利于GUI元素

有关更多信息,请参阅:

我希望你能理解!
Lasoloz

如果您还有其他问题,请创建一个新问题。如果这是一个谢谢你的答案,请接受其中一个答案(正确的一个)并删除该答案。谢谢。如果您还有其他问题,请创建一个新问题。如果这是一个谢谢你的答案,请接受其中一个答案(正确的一个)并删除该答案。非常感谢。