460 likes | 480 Views
OOSDL. 靜宜大學資工系 蔡奇偉 副教授 2006-2007. 內容大綱. 前言 組成類別 CPoint, CRect, CSurface CScreen CSDLApp, CGameApp 範例. 前言. Object-Oriented SDL 把一些 SDL 資料型態封裝成類別,使其更容易使用。 提供 Game Programming Framework ,以簡化遊戲程式的開發。. 組成類別. 基本型態: CPoint: 二維的點座標,主要用於儲存位置資訊。 CRect: 封裝 SDL_Rect 型態的矩形類別。
E N D
OOSDL 靜宜大學資工系 蔡奇偉 副教授 2006-2007
內容大綱 • 前言 • 組成類別 • CPoint, CRect, CSurface • CScreen • CSDLApp, CGameApp • 範例
前言 • Object-Oriented SDL • 把一些 SDL 資料型態封裝成類別,使其更容易使用。 • 提供 Game Programming Framework,以簡化遊戲程式的開發。
組成類別 • 基本型態: • CPoint: 二維的點座標,主要用於儲存位置資訊。 • CRect: 封裝 SDL_Rect 型態的矩形類別。 • CSurface: 封裝 SDL_Surface 型態的繪圖頁類別。 • CJoysticks: 封裝 SDL_Joystick 型態的搖桿類別。 • Clock & Timer 時鐘與定時器 • Framework: • CSDLApp: 簡單 SDL 應用程式的 framework • CGameApp: 基本的遊戲程式 framework • CScreen: 遊戲螢幕
CPoint 類別 struct DECLSPEC CPoint { CPoint (Sint16 x = 0, Sint16 y = 0); void Set (Sint16 x, Sint16 y); bool operator== (const CPoint &pt); bool operator!= (const CPoint &pt); bool InsideRect (CRect &r); };
CRect 類別 class DECLSPEC CRect : public SDL_Rect 成員函式 CRect (Sint16 x = 0, Sint16 y = 0, Uint16 w = 0, Uint16 h = 0); void Set (Sint16 x, Sint16 y, Uint16 w, Uint16 h); bool operator== (const CRect &r); bool operator!= (const CRect &r); bool IsEqualSize (const CRect &r); bool IsNonEqualSize (const CRect &r); bool ContainPoint (CPoint &pt);
Sint16 Left (); Sint16 Top (); Sint16 Right (); Sint16 Bottom (); Uint16 width (); Uint16 Height (); Width Top Height Botom Left Right
CSurface CSurface (); CSurface (SDL_Surface *pSurface); CSurface (CSurface &cs); // Copy construction ~CSurface () operator SDL_Surface * () const; SDL_Surface * GetSDLSurfacePtr () const; CSurface& operator= (const CSurface &cs); CSurface& operator= (SDL_Surface *pSurface);
// Create a blank surface. bool Create (Uint32 flags, int width, int height, int depth =32, Uint32 Rmask = SDL_RMASK, Uint32 Gmask = SDL_GMASK, Uint32 Bmask = SDL_BMASK, Uint32 Amask = SDL_AMASK); // Create a CSurface from pixel data. bool Create (void *pixels, int width, int height, int pitch, int depth = 32, Uint32 Rmask = SDL_RMASK, Uint32 Gmask = SDL_GMASK, Uint32 Bmask = SDL_BMASK, Uint32 Amask = SDL_AMASK); // Load an image file bool LoadImage (const char *file, bool bDisplayFormat = true); // Save CSurface to a BMP file int SaveBMP (const char *file);
int Width (); int Height (); bool Lock (); void Unlock (); Uint32 GetPixel (int x, int y); void PutPixel (int x, int y, Uint32 pixel);
// Color conversion Uint32 MapRGB (Uint8 r, Uint8 g, Uint8 b); Uint32 MapRGBA (Uint8 r, Uint8 g, Uint8 b, Uint8 a); void GetRGB (Uint32 pixel, Uint8 &r, Uint8 &g, Uint8 &b); void GetRGBA (Uint32 pixel, Uint8 &r, Uint8 &g, Uint8 &b, Uint8 &a);
// Colorkey bool SetColorKey (Uint32 key, bool useRLE = true) bool SetColorKey (Uint8 r = 0, Uint8 g = 0, Uint8 b = 0, bool useRLE = true) bool ClearColorKey (); bool HasColorKey (); // Alpha bool SetAlpha (Uint8 alpha, bool useRLE = true) bool ClearAlpha () bool HasAlpha ()
// Clipping CRect void SetClipRect (CRect &rect); void ResetClipRect (); void GetClipRect (CRect &rect); // Fill surface bool Fill (Uint32 color); bool Fill (Uint8 r, Uint8 g, Uint8 b); // Fill part of surface bool FillRect(CRect &rect, Uint32 color); bool FillRect(CRect &rect, Uint8 r, Uint8 g, Uint8 b);
// Blit this surface to another surface bool Blit (SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); bool Blit (SDL_Rect *srcrect, SDL_Surface *dst, CPoint &position); bool Blit (CSurface &dst, Sint16 x, Sint16 y); // Blit this surface to the screen surface bool Show (CRect &srcrect, CRect &rect); bool Show (CRect &srcrect, CPoint &position); bool Show (CRect &srcrect, Sint16 x, Sint16 y); bool Show (Sint16 x, Sint16 y);
CScreen 類別 CScreen (int width, int height, int bpp, Uint32 flags); virtual bool Show (CSurface &surface, SDL_Rect *srcrect, SDL_Rect *dstrect); virtual bool Present (); bool isDirty (); void SetDirty (); void ResetDirty (); void SetBackgroundColor (Uint32 color); void SetBackgroundColor(m_pSurface->MapRGB(r,g,b)); void Clear (); void Clear (Uint32 color);
CSDLApp • void SetScreen (CScreen *pScreen = NULL); • 若參數為 NULL,則使用預設的螢幕物件(640x480x32, 軟性螢幕繪圖頁, 視窗畫面)。 • void SetCaption (const char *title, • const char *icon = NULL); • 若採用視窗螢幕,此函式可用來設定視窗的標題與 icon。 • void GetCaption(char **title, char **icon); • 若採用視窗螢幕,此函式可用來取得視窗的標題與 icon 。
virtual bool InitializeSDL ( • Uint32 flags = SDL_INIT_VIDEO); • 初始化 SDL 函式庫。預設的旗標值只啟動 Video 子系統。此成員函式必須是第一個被呼叫的函式。 • virtual bool InitializeApp (); • 你應該改寫此成員函式,在其中加入所需的應用程式初始化設定。 • virtual void BeforePollEvent (); • 如果你的應用程式在處理事件之前,需做某些計算,你可以改寫此成員函式。 • virtual bool AppMain (); • 遊戲迴圈中的主要程式碼。 • virtual bool QuitApp (); • 改寫此成員函式來處理結束程式前的清理動作。
事件處理的相關成員函式 virtual bool ProcessNextEvent (); virtual void SetApplication (void *pTheApp);
virtual void OnKeyDown (const SDL_keysym &keysym); virtual void OnKeyUp (const SDL_keysym &keysym); virtual void OnMouseMotion (Uint8 state, Uint16 x, Uint16 y, Sint16 xrel, Sint16 yrel); virtual void OnMouseButtonDown (Uint8 button, Uint16 x, Uint16 y); virtual void OnMouseButtonUp (Uint8 button, Uint16 x, Uint16 y); virtual void OnUser (Uint8 type, int code, void *data1, void *data2); virtual void OnQuit ();
// Joystick events virtual void OnJoyAxis (Uint8 which, Uint8 axis, Sint16 value); virtual void OnJoyButtonDown (Uint8 which, Uint8 button); virtual void OnJoyButtonUp (Uint8 which, Uint8 button); virtual void OnJoyHat (Uint8 which, Uint8 hat, Uint8 value); virtual void OnJoyBall (Uint8 which, Uint8 ball, Sint16 xrel, Sint16 yrel);
virtual void OnActiveEvent (Uint8 gain, Uint8 state); virtual void OnResize (int w, int h); virtual void OnExpose (); virtual void OnSysWM ();
void PumpEvents (); int WaitEvent (); int PeepEvents (int numevents, SDL_eventaction action, Uint32 mask); int PollEvent (); int PushEvent (SDL_Event *event); void SetEventFilter (SDL_EventFilter filter); SDL_EventFilter GetEventFilter (); Uint8 EventState (Uint8 type, int state);
Uint8 EnableEvent (Uint8 type); Uint8 DisableEvent (Uint8 type); Uint8 QueryEvent (Uint8 type); Uint8 *GetKeyState (int *numkeys); SDLMod GetModState (); void SetModState (SDLMod modstate); char *GetKeyName (SDLKey key); int EnableUNICODE (); int DisableUNICODE (); int QueryUNICODE ();
int EnableKeyRepeat ( • int delay = SDL_DEFAULT_REPEAT_DELAY, • int interval = SDL_DEFAULT_REPEAT_INTERVAL); • int DisableKeyRepeat (); • Uint8 GetMouseState (int *x, int *y); • Uint8 GetRelativeMouseState (int *x, int *y); • Uint8 GetAppState (); • int JoystickEventState (int state);
CSDLApp 的遊戲迴圈(Game Loop) InitializeApp(); while (!m_bQuit) { BeforePollEvent(); m_bQuit = ProcessNextEvent(); if (m_bQuit) break; AppMain(); } QuitApp();
最簡單的 OOSDL 程式 • #include "oosdl.h“ • CSDLApp myApp; • int main (int argc, char* argv[]) • { • myApp.InitializeSDL(); • myApp.SetScreen(); • myApp.Run(); • return EXIT_SUCCESS; • }
使用 CSDLApp 的步驟 • 宣告一個繼承 CSDLApp 的類別,在其中依所需,改寫相關的成員函式,譬如: • class CMyApp : public CSDLApp • { • // 宣告本類別所需的成員函式與資料成員 • // 依所需地改寫 CSDLApp 中的成員函式 • };
範例: oosdl04.cpp class CMySDLApp : public CSDLApp { protected: virtual bool InitializeApp (); private: CSurface background, ball; }; bool CMySDLApp::InitializeApp () { background.LoadImage ("bkg01.bmp"); ball.LoadImage ("ball.bmp"); background.Show(0, 0); ball.SetColorKey(0, 0, 0); ball.Show(192, 112); return true; } 改寫以加入本程式所需的初始化設定 本程式所需的資料成員
在主函式中,定義一個 CMyApp 的物件,譬如: • int main( int argc, char* argv[] ) • { • CMySDLApp myApp; • // 其他項目 • }
在主函式中,開始呼叫 CMySDLApp 的成員函式 InitializeSDL(),譬如: • int main( int argc, char* argv[] ) • { • CMySDLApp myApp; • myApp.InitializeSDL(); • // 其他項目 • }
接下來呼叫 CMySDLApp 的成員函式 SetScreen(),譬如: • int main( int argc, char* argv[] ) • { • CMySDLApp myApp; • myApp.InitializeSDL(); • myApp.SetScreen(); • // 其他項目 • }
SetScreen() 將選擇 640x480 的視窗為螢幕物件。你可以用以下的方式將螢幕設成 1024x768 的視窗: • myApp.SetScreen(new CScreen(1024,768,0, • SDL_SWSURFACE | SDL_ANYFORMAT)); • CScreen 建構函式的宣告如下: • CScreen::CScreen (int width, int height, int bpp, Uint32 flags); • 其中的參數意義和 SDL_SetVideoMode() 相同。
最後呼叫 CMySDLApp 的成員函式 Run(),譬如: • int main( int argc, char* argv[] ) • { • CMySDLApp myApp; • myApp.InitializeSDL(); • myApp.SetScreen(); • // 其他項目 • myApp.Run(); • return EXIT_SUCCESS; • }
範例: 加入事件的處理 (oosdl07.cpp) class CMySDLApp : public CSDLApp { protected: virtual bool InitializeApp (); virtual bool AppMain (); // Events virtual void OnKeyDown (const SDL_keysym &keysym); virtual void OnKeyUp (const SDL_keysym &keysym); private: CSurface background, ball; int ball_x, ball_y; int ball_xvel, ball_yvel; int ball_speed, ball_speed_inc; };
bool CMySDLApp::InitializeApp () • { • background.LoadImage("bg.png"); • ball.LoadImage("ball.png"); • ball.SetColorKey(0, 0, 0); • ball_x = (SCREEN_WIDTH - BALL_WIDTH) /2; • ball_y = (SCREEN_HEIGHT - BALL_HEIGHT) /2; • ball_xvel = 0; • ball_yvel = 0; • ball_speed = 1; • ball_speed_inc = 0; • background.Show(0, 0); • ball.Show(ball_x, ball_y); • return true; • }
inline void restrict (int &x, int min, int max) • { • if (x < min) • x = min; • else if (x > max) • x = max; • } • bool CMySDLApp::AppMain () • { • if (ball_speed_inc != 0) • { • ball_speed += ball_speed_inc; • if (ball_speed < 1) • ball_speed = 1; • }
if (ball_xvel != 0 || ball_yvel !=0) • { • int x_old = ball_x, y_old = ball_y; • ball_x += ball_xvel; • ball_y += ball_yvel; • restrict(ball_x, 0, SCREEN_WIDTH - BALL_WIDTH); • restrict(ball_y, 0, SCREEN_HEIGHT - BALL_HEIGHT); • if (ball_x != x_old || ball_y != y_old) • { • background.Show(0, 0); • ball.Show(ball_x, ball_y); • } • } • return true; • }
void CMySDLApp::OnKeyDown (const SDL_keysym &keysym) • { • switch (keysym.sym) • { • case SDLK_UP: ball_yvel = -ball_speed; break; • case SDLK_DOWN: ball_yvel = ball_speed; break; • case SDLK_LEFT: ball_xvel = -ball_speed; break; • case SDLK_RIGHT: ball_xvel = ball_speed; break; • case SDLK_EQUALS: ball_speed_inc = 1; break; • case SDLK_MINUS: ball_speed_inc = -1; break; • case SDLK_HOME: • ball_x = (SCREEN_WIDTH - BALL_WIDTH) /2; • ball_y = (SCREEN_HEIGHT - BALL_HEIGHT) /2; • break; • default: • CMySDLApp::OnKeyDown(keysym); • } • }
void CMySDLApp::OnKeyUp (const SDL_keysym &keysym) • { • switch (keysym.sym) • { • case SDLK_UP: • if (ball_yvel < 0) ball_yvel = 0; • break; • case SDLK_DOWN: • if (ball_yvel > 0) ball_yvel = 0; • break; • case SDLK_LEFT: • if (ball_xvel < 0) ball_xvel = 0; • break; • case SDLK_RIGHT: • if (ball_xvel > 0) ball_xvel = 0; • break; • case SDLK_EQUALS: • if (ball_speed_inc > 0) ball_speed_inc = 0; • break; • case SDLK_MINUS: • if (ball_speed_inc < 0) ball_speed_inc = 0; • break; • } • }
int main( int argc, char* argv[] ) { CMySDLApp myApp; myApp.InitializeSDL(); myApp.SetScreen(); myApp.SetCaption(WINDOW_TITLE); myApp.Run(); return EXIT_SUCCESS; }
CGameApp • 繼承 CSDLApp,並加入以下的修改 • 其中呼叫 SDL_Init (SDL_EVERYTHING) • 加入遊戲時鐘與定時器 • 預設為 Fixed Frame Rate,每秒約為 30 張畫格 • 可用下面的方法改為 Variable Frame Rate: • CMyGameApp myGameApp(false);
範例: oosdl13.cpp class BallObj : public CSurface { public: BallObj () : CSurface(), m_x(0), m_y(0) {} void SetPosition (Uint16 x, Uint16 y) { m_x = x; m_y = y; } bool Show() { return CSurface::Show(m_x, m_y); } private: Uint16 m_x, m_y; // ball screen position };
class CMyGameApp : public CGameApp { public: CMyGameApp() : CGameApp() {} ~CMyGameApp () {} protected: virtual bool InitializeApp (); virtual bool AppMain (); private: BallObj redball, blueball; };
bool CMyGameApp::InitializeApp () { m_pScreen->SetBackgroundColor(0, 0, 0); redball.SetPosition(0, 0); redball.LoadImage("redball.png"); redball.SetColorKey(0, 0, 0); blueball.SetPosition((SCREEN_WIDTH-BALL_WIDTH)/2, (SCREEN_HEIGHT-BALL_HEIGHT)/2); blueball.LoadImage("blueball.png"); blueball.SetColorKey(0, 0, 0); return true; }
bool CMyGameApp::AppMain () • { • const float PERIOD = 6.0; // period in second • const float RADIUS = 200; // in pixels • // angular increment • double angle_inc = 2.0*M_PI* • m_pGameClock->GetFrameDefaultTime()/PERIOD; • int nFrame = m_pGameClock->GetFrameNumber()-1; • int x = RADIUS * cos(nFrame*angle_inc) - BALL_WIDTH/2 + SCREEN_WIDTH/2; • int y = RADIUS * sin(nFrame*angle_inc) - BALL_HEIGHT/2 + SCREEN_HEIGHT/2; • // Update ball position and then show it. • redball.SetPosition(x, y); • m_pScreen->Clear(); • redball.Show(); • blueball.Show(); • return true; • }
int main( int argc, char* argv[] ) { CMyGameApp myGameApp; myGameApp.InitializeSDL(); myGameApp.SetScreen(); myGameApp.SetCaption(WINDOW_TITLE); myGameApp.Run(); return EXIT_SUCCESS; }