【问题标题】:The correct way to test 'SDL_PollEvent' in a 'while'在“while”中测试“SDL_PollEvent”的正确方法
【发布时间】:2015-04-17 18:31:45
【问题描述】:

正如手册所说,函数SDL_PollEvent“如果有待处理的事件,则返回 1,如果没有可用的事件,则返回 0。” ,这就是我们使用测试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;
   }

这段代码应该做的是每次按下一个键时打开一个新窗口并在控制台中打印“Hello”。这段代码在测试SDL_PollEvent(&amp;e)!=0 下运行良好,但是当我使用测试!SDL_PollEvent(&amp;e) 时它不会读取SDL_KEYDOWN 事件(但它确实会在一段时间内输入并处理SDL_QUIT 事件而没有任何问题)。 为什么会有这种行为?

【问题讨论】:

    标签: c++ c sdl sdl-2


    【解决方案1】:
    while (!SDL_PollEvent(&e))
    

    需要:

    while (SDL_PollEvent(&e))
    

    如果应该和SDL_PollEvent(&amp;e) != 0一样

    因为!SDL_PollEvent(&amp;e)和调用while(0)是一样的

    【讨论】:

      【解决方案2】:

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

      你可能应该改用SDL_WaitEvent

      【讨论】:

      • SDL_WaitEvent 在只有一个线程的情况下几乎没用。
      • @HolyBlackCat 不,不是。我不认为在忙着等待“没用”的时候不一直烧掉 100% 的 CPU。移动设备用户会感谢您。
      • 你是对的。但我不知道它如何与单线程一起使用,除非您的 appclitaion 完全被动并立即对输入做出反应。
      • @HolyBlackCat 通过使用计时器和用户定义的事件。您安装了一个(例如)每 1/120 秒运行一次的计时器。计时器调用您的函数,该函数将事件发布到队列中。 (需要用户自定义事件,因为不能直接在timer函数里做东西,看手册)
      • @HolyBlackCat 好吧,文档说它在单独的线程中运行。这很令人烦恼,因为每个平台都不应该需要单独的线程 - 事实上,我认为您通常不需要为 Windows 上的计时器提供单独的线程(以及 SDL 的替代库,Allegro 5 不需要在单独的线程上使用计时器。)
      【解决方案3】:

      附录

      人们可能认为这样做更清楚,因为它可以确保对用户输入做出反应。然而,这目前是一个依赖于操作系统的并且可能是疯狂的 CPU 猪,并且会为这个线程(在 Windows 上)最大化你的 CPU。所以你可能认为你可以在那里等待 1 秒钟,但是你的窗口将变得完全没有响应或者充其量是非常滞后...... 如果您可以忍受一点 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!
          }
      

      【讨论】:

      • 延迟必须在外循环,而不是内循环。延迟最好适应每帧花费的时间,以保持恒定的 FPS。
      • 确实! 解决了。 谢谢。不知道为什么这么多示例根本没有任何延迟。
      猜你喜欢
      • 1970-01-01
      • 2021-11-11
      • 2017-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多