一个多态性的游戏状态机系统

任何一款游戏产品,都需要在几种界面之间进行转换:logo、trailer、main menu、in-game、settings menu等等,并且会在这些转换之间处理资源问题。对于实现这样的转换,不同的游戏做法有所差异,但基本上会实现一个游戏状态机系统。状态机系统在游戏开 发中根深蒂固,以至于该系统应该是游戏引擎不可或缺的一个核心部件。


简单游戏状态机结构


状态机的实现方法有很多。相对简单的有switch-case方法,它通过对游戏状态进行枚举化来进行选择判断。下面的示例代码展示了这一点:

1. enum GameState
2. {
3.         GAME_STATE_LOGO = 0,
4.         GAME_STATE_TRAILER,
5.         GAME_STATE_MAIN_MENU,
6.         GAME_STATE_INGAME,
7.         GAME_STATE_SETTINGS_MENU,
8. };
9. 
10. void gameCycle( int gameState )
11. {
12.         switch( gameState )
13.         {
14.                 case GAME_STATE_LOGO: {...}
15.                 case GAME_STATE_TRAILER: {...}
16.                 case GAME_STATE_MAIN_MENU: {...}
17.                 case GAME_STATE_INGAME: {...}
18.                 case GAME_STATE_SETTINGS_MENU: {...}
19.         }
20. }

复制代码


这就是一个相当简单的游戏状态机系统,实现起来很直接、简洁。我们在几年前的一个Java引擎中就使用了这样的一个状态机系统(当然,实际代码要比这复杂一些,但结构是这样的)。它表现得很好,能够满足大多数的需求——有好几个商业游戏都使用了这个结构。


可是,在那之后,我们在一个新的C++引擎中,却放弃了这种方法。我们的理由主要有以下几点:


1)该方法不是OO的,我们的引擎是完全OO的。
2)该系统难以维护——所有的状态判断都在gameCycle的switch-case中,我们每增加或者修改一个状态,都需要在enum和gameCycle中增加新的代码,这会导致大量的重新编译。
3)大量的状态逻辑被集中到了switch-case中,导致代码臃肿,难以维护。
4)我们希望把每一个game state逻辑交给一个工程师来编写,这让我们很难做到。
5)“switch-case在OO中是一种‘坏味道’”思潮影响。


考虑到上面的几个原因,我们开始探索新的实现方式,然后,我们就有了一个新的、基于多态性的游戏状态机系统。