說(shuō)到狀態(tài)管理,很多人第一時(shí)間想到的,就是狀態(tài)機(jī)了,根據(jù)不同的游戲狀態(tài),調(diào)用不同的游戲過(guò)程,來(lái)進(jìn)行游戲更新和渲染 。一般來(lái)說(shuō),我們都是在游戲更新和渲染過(guò)程里面,用一個(gè)大大的 switch 語(yǔ)句,來(lái)確定當(dāng)前的游戲狀態(tài),如果狀態(tài)數(shù)量少的話,倒沒(méi)所謂,但是,一旦游戲狀態(tài)多起來(lái)了,全部狀態(tài)都塞到一個(gè)過(guò)程里面,閱讀起來(lái),就變得非常困難了,維護(hù)起來(lái)的話,就更加難上加難 。
那么,有沒(méi)有什么比較好的辦法,對(duì)游戲中的各種狀態(tài)進(jìn)行一個(gè)統(tǒng)一的管理呢 ? 至少,看起來(lái),代碼不會(huì)那么亂七八糟(笑),答案顯然易見(jiàn)的,廢話不說(shuō),我們直接上代碼 :
1 //----------------------------------- 2 // 游戲狀態(tài)祖先類 3 //----------------------------------- 4 5 class IGameState 6 { 7 // 8 // 初始化 9 // 10 virtual initialize( ) = 0; 11 12 // 13 // 銷毀 14 // 15 virtual shutdown( ) = 0; 16 17 // 18 // 更新 19 // 20 virtual update( ) = 0; 21 22 // 23 // 渲染 24 // 25 virtual render( ) = 0; 26 27 // 28 // 暫停 29 // 30 virtual pause( ) = 0; 31 32 // 33 // 恢復(fù) 34 // 35 virtual resume( ) = 0; 36 37 // 38 // windows 消息處理 39 // 40 virtual msgproc( UINT _msg, WPARAM _wParam, LPARAM _lParam ) = 0; 41 };
我們創(chuàng)建一個(gè) IGameState 純虛類,抽象出一個(gè)游戲狀態(tài)應(yīng)有的各種行為和能力,然后,我們?cè)賮?lái)實(shí)際創(chuàng)建不同的游戲狀態(tài) :
1 //----------------------------------- 2 // 創(chuàng)建一個(gè)游戲介紹狀態(tài) 3 //----------------------------------- 4 5 class CIntroGameState : public IGameState 6 { 7 }; 8 9 //----------------------------------- 10 // 創(chuàng)建一個(gè)游戲主菜單狀態(tài) 11 //----------------------------------- 12 13 class CMainMenuState : public IGameState 14 { 15 }; 16 17 //----------------------------------- 18 // 創(chuàng)建一個(gè)系統(tǒng)設(shè)定狀態(tài) 19 //----------------------------------- 20 21 class CSystemSetting : public IGameState 22 { 23 }; 24 25 // ...
最后一行注釋里面的三個(gè)點(diǎn)是告訴我們,我們可以創(chuàng)建更多的游戲狀態(tài),而不是僅僅限制在上面三個(gè)狀態(tài),然后,我們的游戲狀態(tài),理所當(dāng)然地就交給我們的游戲?qū)ο髞?lái)進(jìn)行維護(hù)啦 :
1 //----------------------------------- 2 // 游戲?qū)ο箢?/strong> 3 //----------------------------------- 4 5 class CGame : public IGameState 6 { 7 // CGame 可以通過(guò)切換 game state 來(lái)更新繪制不同的狀態(tài) 8 9 setGameState( IGameState * _state ){ cur_game_state = _state; } 10 11 // 返回 cur_game_state 可以得知當(dāng)前正在更新繪制哪一個(gè)狀態(tài) 12 13 IGameState * getGameState( void ){ return cur_game_state; } 14 15 // 保存游戲狀態(tài) 16 17 pushGameState( IGameState * _state ){ game_state.push( cur_game_state ); cur_game_state = _state; } 18 19 // 恢復(fù)游戲狀態(tài) 20 21 popGameState( void ){ cur_game_state = game_state.top( ); game_state.pop( ); } 22 23 private: 24 25 // 當(dāng)前正在運(yùn)行哪一個(gè)狀態(tài) 26 27 IGameState * cur_game_state; 28 29 // 游戲狀態(tài)堆棧, 用于游戲狀態(tài)的回溯 30 31 stack< IGameState * > game_state; 32 };
為了讓各種游戲狀態(tài)對(duì)象之間可以互相交互,我們必須提供一些全局的函數(shù)以及全局的對(duì)象,當(dāng)然,如果各位讀者們有更好的方法,請(qǐng)留言給我哈(笑) :
1 //----------------------------------- 2 // 全局對(duì)象和函數(shù) 3 //----------------------------------- 4 5 CGame _game; 6 7 CGame * getGame( void ){ return & _game; } 8 9 IGameState * intro_game = new CIntroGameState( ); 10 IGameState * main_menu = new CMainMenuGameState( ); 11 IGameState * sys_setting = new CSystemSetting( );
然后就是我們的游戲初始化過(guò)程:
1 //----------------------------------- 2 // 程序入口點(diǎn) 3 //----------------------------------- 4 5 void main( void ) 6 { 7 // 初始化游戲 8 9 _game.initialize( ); 10 11 // 游戲初始化后進(jìn)入介紹界面 12 13 _game.setGameState( intro_game ); 14 15 // 運(yùn)行游戲 16 17 while( true ) 18 { 19 _game.update( ); 20 _game.render( ); 21 } 22 23 // 銷毀游戲 24 25 _game.shutdown( ); 26 }
最后,重頭戲到了,我們每一個(gè)游戲狀態(tài)對(duì)象,只管負(fù)責(zé)自己的更新和渲染,如果需要通知游戲?qū)ο筮M(jìn)行狀態(tài)切換,那么可以看看下面代碼 :
1 class CIntroGameState : public IGameState 2 { 3 update( ) 4 { 5 // 如果在播放游戲介紹畫(huà)面時(shí), 用戶按下了 Esc 按鍵 6 7 if( ESC_key pressed ) 8 { 9 // 切換到游戲主菜單狀態(tài) 10 11 getGame( )->setGameState( main_menu ); 12 } 13 } 14 }; 15 16 class CMainMenuGameState : public IGameState 17 { 18 update( ) 19 { 20 // 如果在游戲主菜單里面, 用戶點(diǎn)擊了系統(tǒng)設(shè)置按鈕 21 22 if( sys_setting_button clicked ) 23 { 24 // 切換到系統(tǒng)設(shè)置狀態(tài) 25 26 getGame( )->setGameState( sys_setting ); 27 } 28 } 29 }; 30 31 class CSysMenuGameState : public IGameState 32 { 33 // ...... 34 };
---------------------------------------------------------------------------------
OK,這些代碼,應(yīng)該不需要太多的描述了,看起來(lái)也很容易懂 。
最后,請(qǐng)大家不要吝嗇自己的技術(shù),把自己用過(guò)的管理游戲狀態(tài)或者游戲?qū)ο蟮姆椒ǘ颊f(shuō)出來(lái),大家互相學(xué)習(xí)學(xué)習(xí)哈,因?yàn)槿绻覀兯浪缹⒅R(shí)揣在口袋里面,那么那些沒(méi)有掌握到這些知識(shí)的人,又非常迫切需要這些知識(shí)的人,就會(huì)非常著急,甚至?xí)丝s,這樣子,我們就當(dāng)真成了罪人咯嘻嘻 。