在 'while' 中测试 'SDL_PollEvent' 的正确方法

The correct way to test 'SDL_PollEvent' in a 'while'

正如手册所说,函数 SDL_PollEvent "Returns 1 if there is a pending event or 0 if there are none available." ,这就是我们使用测试 SDL_PollEvent(&e)!=0 的原因(其中 eSDL_Event)。

但是,使用这个测试怎么样:!SDL_PollEvent(&e)?它应该可以工作,但显然它会引起一些问题。

这里有一个代码示例:

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

    int main(int argc, char* args[]){
      SDL_Init(SDL_INIT_VIDEO);
      SDL_Window* window =   SDL_CreateWindow("Hello",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100,  SDL_WINDOW_SHOWN);
      SDL_Event e;
      int quit=0;
      while(!quit){
          //Here the test
          while (!SDL_PollEvent(&e)){
             if (e.type==SDL_QUIT)
                quit=1;
             else if ( e.type == SDL_KEYDOWN )
                printf( "Hello\n" );
          }
      }
      SDL_DestroyWindow(window);
      SDL_Quit();
      return 0;
   }

这段代码应该做的是打开一个新的 window 并在每次按下某个键时在控制台中打印 "Hello" 。这段代码在测试 SDL_PollEvent(&e)!=0 时工作正常,但是当我使用测试 !SDL_PollEvent(&e) 时它没有读取 SDL_KEYDOWN 事件(但它确实在 while 中输入并处理 SDL_QUIT 事件没有任何问题)。
为什么会出现这种行为?

while (!SDL_PollEvent(&e))

需要:

while (SDL_PollEvent(&e))

如果应该和SDL_PollEvent(&e) != 0

一样

因为!SDL_PollEvent(&e)等同于调用while(0)

(1 != 0)为真,(!1)为假。

无论如何,您可能应该使用 SDL_WaitEvent

附录

人们可能认为这样做更清楚,因为它可以确保对用户输入做出反应。然而,这目前是一个 OS 依赖并且可能是疯狂的 CPU 猪并且会最大化你的 CPU 这个线程(在 Windows 上)。所以你可能认为你可以在那里等待 1 秒,但是你的 window 将变得完全没有反应或充其量非常迟钝...... 如果您可以忍受一点 CPU 无所事事的开销,那么您可以妥协使用 20-100 [ms] 延迟。

...
    // Set the event handler...
    ...
    bool isRunning = true;
    while (isRunning) {
        // Do the main thing here...
        ...
        while(SDL_PollEvent(&windowEvent)) {
            switch (windowEvent.type) {
                case SDL_QUIT:              isRunning = false;
                case SDL_KEYDOWN:           isRunning = false;
                case SDL_MOUSEBUTTONDOWN:   isRunning = false;
                break;
            }
            SDL_Delay(100); // Wrong!
        }
    }
    // End the program

很明显这也不是正确的方法。我们需要使用一些其他机制。查看 SDL 回购协议,我们发现了一个很长但非常相关的关于未解决问题的讨论:


解决问题

确保在 SDL_PollEvent().

之前将延迟放在外循环中
    // main loop
    ...
        while(SDL_PollEvent(&windowEvent)) {
            switch (windowEvent.type) {
                case SDL_QUIT:              isRunning = false;
                case SDL_KEYDOWN:           isRunning = false;
                case SDL_MOUSEBUTTONDOWN:   isRunning = false;
                break;
            }
        }
        SDL_Delay(100); // Right!
    }