说到状态管理,很多人第一时间想到的,就是状态机了,根据不同的游戏状态,调用不同的游戏过程,来进行游戏更新和渲染 。一般来说,我们都是在游戏更新和渲染过程里面,用一个大大的 switch 语句,来确定当前的游戏状态,如果状态数量少的话,倒没所谓,但是,一旦游戏状态多起来了,全部状态都塞到一个过程里面,阅读起来,就变得非常困难了,维护起来的话,就更加难上加难 。
那么,有没有什么比较好的办法,对游戏中的各种状态进行一个统一的管理呢 ? 至少,看起来,代码不会那么乱七八糟(笑),答案显然易见的,废话不说,我们直接上代码 :
1 //-----------------------------------
2 // 游戏状态祖先类
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 // 恢复
34 //
35 virtual resume( ) = 0;
36
37 //
38 // windows 消息处理
39 //
40 virtual msgproc( UINT _msg, WPARAM _wParam, LPARAM _lParam ) = 0;
41 };我们创建一个 IGameState 纯虚类,抽象出一个游戏状态应有的各种行为和能力,然后,我们再来实际创建不同的游戏状态 :
1 //-----------------------------------
2 // 创建一个游戏介绍状态
3 //-----------------------------------
4
5 class CIntroGameState : public IGameState
6 {
7 };
8
9 //-----------------------------------
10 // 创建一个游戏主菜单状态
11 //-----------------------------------
12
13 class CMainMenuState : public IGameState
14 {
15 };
16
17 //-----------------------------------
18 // 创建一个系统设定状态
19 //-----------------------------------
20
21 class CSystemSetting : public IGameState
22 {
23 };
24
25 // ...最后一行注释里面的三个点是告诉我们,我们可以创建更多的游戏状态,而不是仅仅限制在上面三个状态,然后,我们的游戏状态,理所当然地就交给我们的游戏对象来进行维护啦 :
1 //-----------------------------------
2 // 游戏对象类
3 //-----------------------------------
4
5 class CGame : public IGameState
6 {
7 // CGame 可以通过切换 game state 来更新绘制不同的状态
8
9 setGameState( IGameState * _state ){ cur_game_state = _state; }
10
11 // 返回 cur_game_state 可以得知当前正在更新绘制哪一个状态
12
13 IGameState * getGameState( void ){ return cur_game_state; }
14
15 // 保存游戏状态
16
17 pushGameState( IGameState * _state ){ game_state.push( cur_game_state ); cur_game_state = _state; }
18
19 // 恢复游戏状态
20
21 popGameState( void ){ cur_game_state = game_state.top( ); game_state.pop( ); }
22
23 private:
24
25 // 当前正在运行哪一个状态
26
27 IGameState * cur_game_state;
28
29 // 游戏状态堆栈, 用于游戏状态的回溯
30
31 stack< IGameState * > game_state;
32 };为了让各种游戏状态对象之间可以互相交互,我们必须提供一些全局的函数以及全局的对象,当然,如果各位读者们有更好的方法,请留言给我哈(笑) :
1 //-----------------------------------
2 // 全局对象和函数
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( );然后就是我们的游戏初始化过程:
1 //-----------------------------------
2 // 程序入口点
3 //-----------------------------------
4
5 void main( void )
6 {
7 // 初始化游戏
8
9 _game.initialize( );
10
11 // 游戏初始化后进入介绍界面
12
13 _game.setGameState( intro_game );
14
15 // 运行游戏
16
17 while( true )
18 {
19 _game.update( );
20 _game.render( );
21 }
22
23 // 销毁游戏
24
25 _game.shutdown( );
26 }最后,重头戏到了,我们每一个游戏状态对象,只管负责自己的更新和渲染,如果需要通知游戏对象进行状态切换,那么可以看看下面代码 :
1 class CIntroGameState : public IGameState
2 {
3 update( )
4 {
5 // 如果在播放游戏介绍画面时, 用户按下了 Esc 按键
6
7 if( ESC_key pressed )
8 {
9 // 切换到游戏主菜单状态
10
11 getGame( )->setGameState( main_menu );
12 }
13 }
14 };
15
16 class CMainMenuGameState : public IGameState
17 {
18 update( )
19 {
20 // 如果在游戏主菜单里面, 用户点击了系统设置按钮
21
22 if( sys_setting_button clicked )
23 {
24 // 切换到系统设置状态
25
26 getGame( )->setGameState( sys_setting );
27 }
28 }
29 };
30
31 class CSysMenuGameState : public IGameState
32 {
33 // ......
34 };---------------------------------------------------------------------------------
OK,这些代码,应该不需要太多的描述了,看起来也很容易懂 。
最后,请大家不要吝啬自己的技术,把自己用过的管理游戏状态或者游戏对象的方法都说出来,大家互相学习学习哈,因为如果我们死死将知识揣在口袋里面,那么那些没有掌握到这些知识的人,又非常迫切需要这些知识的人,就会非常着急,甚至会退缩,这样子,我们就当真成了罪人咯嘻嘻 。


喜欢
顶
难过
囧
围观
无聊


