SDL遊戲教程第三課 消息(Events)

翻譯聲明:
    本系列教程來自
Dev Hub,一切解釋權歸原作者。我只是出自個人愛好,才翻譯了本系列教程。因爲本人也是個初學者,而且英語水平有限,錯誤難免,望各路高手指正。

本課原文地址:http://www.sdltutorials.com/sdl-events/


和遊戲開發基礎相關的有一個叫事件(譯者注:Events,我感覺還是消息比較貼切,以後就譯爲“消息”)的模塊。消息是程序和用戶之間最基本的交互。一個消息可能來自鍵盤、鼠標、遊戲杆、遊戲板等或者來自操作系統。要想處理好用戶和遊戲之間的交互,瞭解消息的運行機制很重要。前面我們已經用過消息了,雖然只是用來關閉窗口,現在我們就看看如何從用戶那裏接受消息。

如果你沒跟上(譯者注:你就去自己回顧下吧~),每個課程都是建立在前一個的基礎之上的,所以我們就使用前面一節課的代碼。爲了跟蹤所有的消息,並把它們傳遞給適當的函數,我們就要建立一個新的類。創建兩個文件,CEvent.h和CEvent.cpp。這兩個文件要處理我們的消息,並調用相應的函數。CApp要繼承此類,以便我們需要捕獲一個消息的時候簡單的重寫一個函數就行了。

打開CEvent.h,添加如下代碼:
  1. #ifndef _CEVENT_H_
  2. #define _CEVENT_H_
  3. #include <SDL.h>
  4. class CEvent {
  5.     public:
  6.         CEvent();
  7.         virtual ~CEvent();
  8.         virtual void OnEvent(SDL_Event* Event);
  9.         virtual void OnInputFocus();
  10.         virtual void OnInputBlur();
  11.         virtual void OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode);
  12.         virtual void OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode);
  13.         virtual void OnMouseFocus();
  14.         virtual void OnMouseBlur();
  15.         virtual void OnMouseMove(int mX, int mY, int relX, int relY, bool Left,bool Right,bool Middle);
  16.         virtual void OnMouseWheel(bool Up, bool Down);  //Not implemented
  17.         virtual void OnLButtonDown(int mX, int mY);
  18.         virtual void OnLButtonUp(int mX, int mY);
  19.         virtual void OnRButtonDown(int mX, int mY);
  20.         virtual void OnRButtonUp(int mX, int mY);
  21.         virtual void OnMButtonDown(int mX, int mY);
  22.         virtual void OnMButtonUp(int mX, int mY);
  23.         virtual void OnJoyAxis(Uint8 which, Uint8 axis, Sint16 value);
  24.         virtual void OnJoyButtonDown(Uint8 which, Uint8 button);
  25.         virtual void OnJoyButtonUp(Uint8 which, Uint8 button);
  26.         virtual void OnJoyHat(Uint8 which, Uint8 hat, Uint8 value);
  27.         virtual void OnJoyBall(Uint8 which, Uint8 ball, Sint16 xrel, Sint16 yrel);
  28.         virtual void OnMinimize();
  29.         virtual void OnRestore();
  30.         virtual void OnResize(int w,int h);
  31.         virtual void OnExpose();
  32.         virtual void OnExit();
  33.         virtual void OnUser(Uint8 type, int code, void* data1, void* data2);
  34. };
  35. #endif

非常強大的一個類吧?好了,接着打開CEvent.cpp,並添加如下代碼:
  1. #include "CEvent.h"
  2. CEvent::CEvent() {
  3. }
  4. CEvent::~CEvent() {
  5.     //Do nothing
  6. }
  7. void CEvent::OnEvent(SDL_Event* Event) {
  8.     switch(Event->type) {
  9.         case SDL_ACTIVEEVENT: {
  10.             switch(Event->active.state) {
  11.                 case SDL_APPMOUSEFOCUS: {
  12.                     if ( Event->active.gain )   OnMouseFocus();
  13.                     else                OnMouseBlur();
  14.                     break;
  15.                 }
  16.                 case SDL_APPINPUTFOCUS: {
  17.                     if ( Event->active.gain )   OnInputFocus();
  18.                     else                OnInputBlur();
  19.                     break;
  20.                 }
  21.                 case SDL_APPACTIVE: {
  22.                     if ( Event->active.gain )   OnRestore();
  23.                     else                OnMinimize();
  24.                     break;
  25.                 }
  26.             }
  27.             break;
  28.         }
  29.         case SDL_KEYDOWN: {            OnKeyDown(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
  30.             break;
  31.         }
  32.         case SDL_KEYUP: {            OnKeyUp(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
  33.             break;
  34.         }
  35.         case SDL_MOUSEMOTION: {            OnMouseMove(Event->motion.x,Event->motion.y,Event->motion.xrel,Event->motion.yrel,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_LEFT))!=0,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_RIGHT))!=0,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_MIDDLE))!=0);
  36.             break;
  37.         }
  38.         case SDL_MOUSEBUTTONDOWN: {
  39.             switch(Event->button.button) {
  40.                 case SDL_BUTTON_LEFT: {
  41.                     OnLButtonDown(Event->button.x,Event->button.y);
  42.                     break;
  43.                 }
  44.                 case SDL_BUTTON_RIGHT: {
  45.                     OnRButtonDown(Event->button.x,Event->button.y);
  46.                     break;
  47.                 }
  48.                 case SDL_BUTTON_MIDDLE: {
  49.                     OnMButtonDown(Event->button.x,Event->button.y);
  50.                     break;
  51.                 }
  52.             }
  53.             break;
  54.         }
  55.         case SDL_MOUSEBUTTONUP: {
  56.             switch(Event->button.button) {
  57.                 case SDL_BUTTON_LEFT: {
  58.                     OnLButtonUp(Event->button.x,Event->button.y);
  59.                     break;
  60.                 }
  61.                 case SDL_BUTTON_RIGHT: {
  62.                     OnRButtonUp(Event->button.x,Event->button.y);
  63.                     break;
  64.                 }
  65.                 case SDL_BUTTON_MIDDLE: {
  66.                     OnMButtonUp(Event->button.x,Event->button.y);
  67.                     break;
  68.                 }
  69.             }
  70.             break;
  71.         }
  72.         case SDL_JOYAXISMOTION: {            OnJoyAxis(Event->jaxis.which,Event->jaxis.axis,Event->jaxis.value);
  73.             break;
  74.         }
  75.         case SDL_JOYBALLMOTION: {        OnJoyBall(Event->jball.which,Event->jball.ball,Event->jball.xrel,Event->jball.yrel);
  76.             break;
  77.         }
  78.         case SDL_JOYHATMOTION: {
  79. OnJoyHat(Event->jhat.which,Event->jhat.hat,Event->jhat.value);
  80.             break;
  81.         }
  82.         case SDL_JOYBUTTONDOWN: {           OnJoyButtonDown(Event->jbutton.which,Event->jbutton.button);
  83.             break;
  84.         }
  85.         case SDL_JOYBUTTONUP: {
  86.             OnJoyButtonUp(Event->jbutton.which,Event->jbutton.button);
  87.             break;
  88.         }
  89.         case SDL_QUIT: {
  90.             OnExit();
  91.             break;
  92.         }
  93.         case SDL_SYSWMEVENT: {
  94.             //Ignore
  95.             break;
  96.         }
  97.         case SDL_VIDEORESIZE: {
  98.             OnResize(Event->resize.w,Event->resize.h);
  99.             break;
  100.         }
  101.         case SDL_VIDEOEXPOSE: {
  102.             OnExpose();
  103.             break;
  104.         }
  105.         default: {
  106.             OnUser(Event->user.type,Event->user.code,Event->user.data1,Event->user.data2);
  107.             break;
  108.         }
  109.     }
  110. }
  111. void CEvent::OnInputFocus() {
  112.     //Pure virtual, do nothing
  113. }
  114. void CEvent::OnInputBlur() {
  115.     //Pure virtual, do nothing
  116. }
  117. void CEvent::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode) {
  118.     //Pure virtual, do nothing
  119. }
  120. void CEvent::OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode) {
  121.     //Pure virtual, do nothing
  122. }
  123. void CEvent::OnMouseFocus() {
  124.     //Pure virtual, do nothing
  125. }
  126. void CEvent::OnMouseBlur() {
  127.     //Pure virtual, do nothing
  128. }
  129. void CEvent::OnMouseMove(int mX, int mY, int relX, int relY, bool Left,bool Right,bool Middle) {
  130.     //Pure virtual, do nothing
  131. }
  132. void CEvent::OnMouseWheel(bool Up, bool Down) {
  133.     //Pure virtual, do nothing
  134. }
  135. void CEvent::OnLButtonDown(int mX, int mY) {
  136.     //Pure virtual, do nothing
  137. }
  138. void CEvent::OnLButtonUp(int mX, int mY) {
  139.     //Pure virtual, do nothing
  140. }
  141. void CEvent::OnRButtonDown(int mX, int mY) {
  142.     //Pure virtual, do nothing
  143. }
  144. void CEvent::OnRButtonUp(int mX, int mY) {
  145.     //Pure virtual, do nothing
  146. }
  147. void CEvent::OnMButtonDown(int mX, int mY) {
  148.     //Pure virtual, do nothing
  149. }
  150. void CEvent::OnMButtonUp(int mX, int mY) {
  151.     //Pure virtual, do nothing
  152. }
  153. void CEvent::OnJoyAxis(Uint8 which,Uint8 axis,Sint16 value) {
  154.     //Pure virtual, do nothing
  155. }
  156. void CEvent::OnJoyButtonDown(Uint8 which,Uint8 button) {
  157.     //Pure virtual, do nothing
  158. }
  159. void CEvent::OnJoyButtonUp(Uint8 which,Uint8 button) {
  160.     //Pure virtual, do nothing
  161. }
  162. void CEvent::OnJoyHat(Uint8 which,Uint8 hat,Uint8 value) {
  163.     //Pure virtual, do nothing
  164. }
  165. void CEvent::OnJoyBall(Uint8 which,Uint8 ball,Sint16 xrel,Sint16 yrel) {
  166.     //Pure virtual, do nothing
  167. }
  168. void CEvent::OnMinimize() {
  169.     //Pure virtual, do nothing
  170. }
  171. void CEvent::OnRestore() {
  172.     //Pure virtual, do nothing
  173. }
  174. void CEvent::OnResize(int w,int h) {
  175.     //Pure virtual, do nothing
  176. }
  177. void CEvent::OnExpose() {
  178.     //Pure virtual, do nothing
  179. }
  180. void CEvent::OnExit() {
  181.     //Pure virtual, do nothing
  182. }
  183. void CEvent::OnUser(Uint8 type, int code, void* data1, void* data2) {
  184.     //Pure virtual, do nothing
  185. }

代碼有點多呵,不過應該已經覆蓋了所有的SDL消息了。我們要做的很簡單,建立一個SDL_Event指針,然後根據其類型進行switch,並調用相應的函數。由於消息比較多,所有代碼看起來有點長。

現在一切就緒,讓我們回到CApp.h,然後把這兩個連接起來:
  1. #ifndef _CAPP_H_
  2. #define _CAPP_H_
  3. #include <SDL.h>
  4. #include "CEvent.h"
  5. #include "CSurface.h"
  6. class CApp : public CEvent {
  7.     private:
  8.         bool            Running;
  9.         SDL_Surface*    Surf_Display;
  10.         SDL_Surface*    Surf_Test;
  11.     public:
  12.         CApp();
  13.         int OnExecute();
  14.     public:
  15.         bool OnInit();
  16.         void OnEvent(SDL_Event* Event);
  17.         void OnLoop();
  18.         void OnRender();
  19.         void OnCleanup();
  20. };
  21. #endif

編譯一切正常。我們已經設定好了消息類,現在就讓我們把消息連接到我們新類的結構裏。打開CApp_OnEvent.cpp並編輯如下函數:
  1. #include "CApp.h"
  2. void CApp::OnEvent(SDL_Event* Event) {
  3.     CEvent::OnEvent(Event);
  4. }
 
現在我們已經把消息結構傳送給我們的類了,要注意調用正確的回調函數。現在,當我們要檢查一個消息的時候,就重寫一個函數。由於我們去掉了對SDL_QUIT消息的檢查,就讓我們用函數來代替。再次打開CApp.h,並添加如下函數:
  1.  
  2. #ifndef _CAPP_H_
  3. #define _CAPP_H_
  4. #include <SDL.h>
  5. #include "CEvent.h"
  6. #include "CSurface.h"
  7. class CApp : public CEvent {
  8.     private:
  9.         bool            Running;
  10.         SDL_Surface*    Surf_Display;
  11.         SDL_Surface*    Surf_Test;
  12.     public:
  13.         CApp();
  14.         int OnExecute();
  15.     public:
  16.         bool OnInit();
  17.         void OnEvent(SDL_Event* Event);
  18.         void OnExit();
  19.         void OnLoop();
  20.         void OnRender();
  21.         void OnCleanup();
  22. };
  23. #endif
 
OnExit()函數會處理SDL_QUIT消息。現在我們有了原型,讓我們定義下它都做些什麼。打開CApp_OnEvent.cpp,並添加如下代碼:
  1. #include "CApp.h"
  2. void CApp::OnEvent(SDL_Event* Event) {
  3.     CEvent::OnEvent(Event);
  4. }
  5. void CApp::OnExit() {
  6.     Running = false;
  7. }

重新編譯一下,試試看。你應該可以像以前那樣退出程序。

我希望你能認真看看我們檢查的那些消息。以後我們將在我們的遊戲裏用到某些消息,現在你就先去熟悉熟悉吧。

跳到下一節課,看看創建我們的第一個遊戲吧,Tic-Tac-Toe.

SDL 消息 —— 課程文件:
Win32:Zip,Rar
Linux:Tar(多謝Gaten)
發佈了8 篇原創文章 · 獲贊 11 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章