「SDL第四篇」事件處理

SDL中的事件處理

要想了解 SDL 的事件處理,我們必須要知道的一個原理是,SDL將所有事件都存放在一個隊列中。所有對事件的操作,其實就是對隊列的操作。了解了這個原理後,我們再來說SDL提供的 API 就很容易理解了。

  • SDL_PollEvent: 將隊列頭中的事件拋出來。
  • SDL_WaitEvent: 當隊列中有事件時,拋出事件。否則處於阻塞狀態,釋放 CPU。
  • SDL_WaitEventTimeout: 與SDL_WaitEvent的區別時,當到達超時時間後,退出阻塞狀態。
  • SDL_PeekEvent: 從隊列中取出事件,但該事件不從隊列中刪除。
  • SDL_PushEvent: 向隊列中插入事件。

SDL只提供了這樣幾個簡單的API,下面們來介紹幾個常見的事件:

  • SDL_WindowEvent : Window窗口相關的事件。
  • SDL_KeyboardEvent : 鍵盤相關的事件。
  • SDL_MouseMotionEvent : 鼠標移動相關的事件。
  • SDL_QuitEvent : 退出事件。
  • SDL_UserEvent : 用戶自定義事件。

關於事件更加詳的信息可以到 SDL Wiki 上進行查詢。現在我們來看一個使用的例子吧。

例子

在我們之前文章的例子中,大家已經發現一個問題,那就是窗口只顯示了 3 秒鐘,之後就自動消失了。

有的同學可以會通過修改代碼最後面的 SDL_Delay 函數,增加它的等待時間讓窗口多活一段時間。

但這樣的體驗實在是太糟糕了。有沒有一種好的辦法可以解決這個問題呢?能不能窗口一直顯示,直到檢測到用戶按了ctrl+c 或 使用鼠標點擊關閉按鈕後才關閉呢?

當然是可以的。我們只需要在之前的程序的末尾增加下面這段代碼即可。它會一直檢測用戶是否按下了退出按鈕。如果檢測到了,則直接退出,否則保持顯示狀態。

while(!quit){      SDL_Event event;      while(SDL_PollEvent(&event)){          switch(event.type){              case SDL_QUIT:                 quit = 1;                 break;              default:                 SDL_Log(".");          }      }  }

SDL_PollEvent 與 SDL_WaitEvent

增加了上面的代碼,我們的實驗程序似乎也顯的很正規了。但有一個問題不知你發現沒有 ?當我們打開任務管理器時,發現我們的程序居然佔了 100% 的 CPU。My GOD!這個的結果是決對不能接受的。

是什麼原因造成的呢?我們來仔細看一下我們增加的代碼吧。它由兩層 while 循環組成,最裏面的while循環的意思是,當隊列中一直能取出事件,那就讓他一直做下去,直到事件隊列為空。外面的while循環的意思是,當隊列為空的時候,重新執行內部的while循環。

也就是說,這段代碼一直在工作,從不休息。所以導致cpu佔到了 100%。即然找到了問題的原因,我們就好處理了,只要在外層循環的最後 delay一下,讓CPU休息一下就好了。

當然,SDL還為我們提供了 SDL_WaitEvent方法,使用這個API,你的CPU就不會跑到 100%了,因為當它發現隊列為空時,它會阻塞在那裡,並將CPU釋放掉。

即然有 SDL_WaitEvent了,為什麼還要有SDL_PollEvent呢?這主要是由於使用的場景不同。對於遊戲來說,它要求事件的實時處理; 而對於一些其它實時性不高的case來說,則可以使用 SDL_WaitEvent了。

小結

到此,本文的內容就介紹完了。在本文中主要介紹了SDL是如何處理事件的,SDL為我們提供了非常簡單的API,這大大減少了我們的開發成本。

另外,我在文章的最後,介紹了SDL_PollEvent 與 SDL_WaitEvent兩個 API的區別。這也是使用 SDL 事件處理中最容易引起困惑的地方。

希望本文能對您有所幫助,謝謝!