01状态机介绍游戏中的状态机一般是有限状态机,简称FSM(finitestatemachine),简称状态机,表示有限数量的状态和行为,如转移和动作在这些状态之间。数学模型。状态机的每个状态至少需要以下三个操作:Startup:从其他状态进入该状态时,需要进行的初始化操作;update:该状态运行时执行的更新操作;清理:退出该状态时,需要进行的清理操作。状态需要的变量:Next:表示状态退出后要转移到的下一个状态;Persist:状态切换时需要传递的数据;Complete:表示状态是否结束,状态机根据这个值来判断过渡状态。游戏界面状态机的状态转换图如下,箭头表示可能的状态转换方向:(注意有一个转换不好画:超时状态可以转换为GameOver状态。)这些状态的含义比较简单,如下贴游戏界面截图。主菜单:主菜单,启动程序进入该状态,可以使用上下键选择玩家1或玩家2,按回车键开始游戏。载入画面:游戏开始前的载入画面。Gamerunning:游戏运行状态,代码实现中为Level类。Gameover:当角色死亡且生命数为0时,进入该状态。超时:在游戏中,超时会达到这个状态。这类似于GameOver,因此不会截取屏幕截图。02状态机代码实现因为本文的目的是游戏界面的状态机实现,所以特地写了一个state_demo.py文件,方便大家更方便的查看代码。游戏启动代码从pygame的初始化开始,设置屏幕大小为c.SCREEN_SIZE(800,600)。所有常量都保存在单独的constants.py中。将osimportpygame作为pgimport常量导入为cpg.init()c.SCREEN_SIZE)SCREEN_RECT=SCREEN.get_rect()load_all_gfx函数在指定目录下搜索所有匹配后缀的图片,用pg.image.load函数加载,保存到图形集中。GFX将所有找到的图片保存在resources/graphics目录下,后面获取各种图形时会用到。defload_all_gfx(directory,colorkey=(255,0,255),accept=('.png','.jpg','.bmp','.gif')):graphics={}forpicinos.listdir(directory)):name,ext=os.path.splitext(pic)ifext.lower()inaccept:img=pg.image.load(os.path.join(directory,pic))ifimg.get_alpha():img=img.convert_alpha()else:img=img.convert()img.set_colorkey(colorkey)graphics[name]=imgreturngraphicsGFX=load_all_gfx(os.path.join("resources","graphics"))这里是demo入口函数首先创建一个保存所有状态的state_dict设置,调用setup_states函数设置启动状态为MAIN_MENU。if__name__=='__main__':game=Control()state_dict={c.MAIN_MENU:Menu(),c.LOAD_SCREEN:LoadScreen(),c.LEVEL:Level(),c.GAME_OVER:GameOver(),c.TIME_OUT:TimeOut()}game.setup_states(state_dict,c.MAIN_MENU)game.main()状态类首先定义了一个状态基类,根据上面提到的状态所需的三个操作(启动,更新,清理)。以上三个变量(next、persist、```jsdone)定义在init函数中,start_time和current_time用于记录时间。类State():definit(self):self.start_time=0.0self.current_time=0.0self.done=Falseself.next=Noneself.persist={}@abstractmethoddefstartup(self,current_time,persist):'''抽象方法'''defcleanup(self):self.done=Falsereturnself.persist@abstractmethoddefupdate(sefl,surface,keys,current_time):'''抽象方法'''看一个状态的具体情况classLoadScreen实现了,该状态的显示效果如图3所示,startup函数保存了预期的persist,设置next为Level状态类,start_time保存了进入该状态的开始时间。初始化一个Infoclass,专门用来显示界面信息。update函数根据该状态下的运行时间(current_time-self.start_time)来决定显示什么以及是否结束该状态(self.done=True)。类LoadScreen(State):def__init__(self):State.__init__(self)self.time_list=[2400,2600,2635]defstartup(self,current_time,persist):self.start_time=current_timeself.persist=persistself.game_info=self.persistself.next=self.set_next_state()info_state=self.set_info_state()self.overhead_info=Info(self.game_info,info_state)defset_next_state(self):returnc.LEVELdefset_info_state(self):返回c.LOAD_SCREENdefupdate(self,surface,keys,current_time):if(current_time-self.start_time)
