如何用Python实现超级玛丽的界面和状态机?.docx
《如何用Python实现超级玛丽的界面和状态机?.docx》由会员分享,可在线阅读,更多相关《如何用Python实现超级玛丽的界面和状态机?.docx(22页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、如何用Python实现超级玛丽的界面和状态机?|marble_xu编辑|郭芮来源|CSDNboke小时候的经典游戏代码参考了github上的工程Mario-Level-1s:/github/justinmeister/Mario-Level-1使用pygame来实现从中学习到了横版过关游戏实现中的一些处理方法。原工程实现了超级玛丽的第一个小关。在原工程的根底上游戏使用json文件来保存每一个关卡的数据将数据以及代码解耦合目前已开发4个小关后续关卡的扩展也很方便只需要添加json文件以及地图图片支持新的怪物就行。游戏还支持进入水管到新的子地图。这篇文章是要介绍下游戏中的几个界面显示以及界面之间怎
2、样转换所以特意写了一个demo程序完好的游戏代码在下面的github链接s:/github/marblexu/PythonSuperMario中下载。状态机介绍游戏中的状态机一般都是有限状态机简写为FSMFiniteStateMachine简称状态机是表示有限个状态和在这些状态之间的转移以及动作等行为的数学模型。状态机的每一个状态至少需要有下面三个操作Startup当从其他状态进入这个状态时需要进展的初始化操作Update在这个状态运行时进展的更新操作Cleanup当从这个状态退出时需要进展的去除操作。状态需要的变量next:表示这个状态退出后要转到的下一个状态persist在状态间转换时需要
3、传递的数据done表示这个状态是否完毕状态时机根据这个值来决定转换状态。游戏界面状态机的状态转换图如下箭头表示可能的状态转换方向注意有个转换不太好画出来TimeOut状态可以转换到GameOver状态。图1这几个状态的意思比拟简单下面把游戏界面的截图发一下。MainMenu主菜单启动程序就进入这个状态可以用UP以及DOWN键选择player1或者player2按回车键开启游戏。图2LoadScreen游戏开场前的加载界面。图3GameRun游戏运行时的状态在代码实现中是Level类。图4GameOver人物死亡且生命数目为0时到这个状态。图5TimeOut在游戏中时间超时会到这个状态这个以及G
4、ameOver类似就不截图了。状态机代码实现因为这篇文章的目的是游戏界面的状态机实现所以专门写了一个state_demo.py文件让大众可以更加方便的看代码。游戏启动代码开场是pygame的初始化设置屏幕大小为c.SCREEN_SIZE(800,600)。所有的常量都保存在单独的constants.py中。importosimportpygameaspgimportconstantsascpg.init()pg.event.set_allowed(pg.KEYDOWN,pg.KEYUP,pg.QUIT)pg.display.set_caption(c.ORIGINAL_CAPTION)SCRE
5、ENpg.display.set_mode(c.SCREEN_SIZE)SCREEN_RECTSCREEN.get_rect()load_all_gfx函数查找指定目录下所有符合后缀名的图片使用pg.image.load函数加载保存在graphicsset中。GFX保存在resources/graphics目录找到的所有图片后面获取各种图形时会用到。defload_all_gfx(directory,colorkey(255,0,255),accept(.png,.jpg,.bmp,.gif):graphicsforpicinos.listdir(directory):name,extos.p
6、ath.splitext(pic)ifext.lower()inaccept:imgpg.image.load(os.path.join(directory,pic)ifimg.get_alpha():imgimg.convert_alpha()else:imgimg.convert()img.set_colorkey(colorkey)graphicsnameimgreturngraphicsGFXload_all_gfx(os.path.join(resources,graphics)下面是demo的入口函数先创立了一个保存所有状态的state_dictset调用setup_states函
7、数设置起始状态是MAIN_MENU。if_name_main_:gameControl()state_dictc.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()状态类先定义一个State基类,按照上面讲的状态需要的三个操作分别定义函数(startup,update,cleanup)。在init函数中定义了上面讲的三个变量nextper
8、sistdone还有start_time以及current_time用于记录时间。classState():def_init_(self):self.start_time0.0self.current_time0.0self.doneFalseself.nextNoneself.persistabstractmethoddefstartup(self,current_time,persist):abstractmethoddefcleanup(self):self.doneFalsereturnself.persistabstractmethoddefupdate(sefl,surface,k
9、eys,current_time):abstractmethod看一个状态类LoadScreen的详细实现这个状态的显示效果如图3。startup函数保存了传入的persist设置next为Level状态类start_time保存进入这个状态的开场时间。初始化一个Info类这个就是专门用来显示界面信息的。update函数根据在这个状态已运行的时间(current_time-self.start_time)决定显示内容以及是否完毕状态self.doneTrue。classLoadScreen(State):def_init_(self):State._init_(self)self.time_l
10、ist2400,2600,2635defstartup(self,current_time,persist):self.start_timecurrent_timeself.persistpersistself.game_infoself.persistself.nextself.set_next_state()info_stateself.set_info_state()self.overhead_infoInfo(self.game_info,info_state)defset_next_state(self):returnc.LEVELdefset_info_state(self):re
11、turnc.LOAD_SCREENdefupdate(self,surface,keys,current_time):if(current_time-self.start_time)self.time_list0:surface.fill(c.BLACK)self.overhead_info.update(self.game_info)self.overhead_info.draw(surface)elif(current_time-self.start_time)self.time_list1:surface.fill(c.BLACK)elif(current_time-self.start
12、_time)self.time_list2:surface.fill(106,150,252)else:self.doneTrueInfo类下面介绍Info类界面的显示大局部都是由它来完成init函数中create_info_labels函数创立通用的信息create_state_labels函数对于不同的状态会初始化不同的信息。classInfo():def_init_(self,game_info,state):self.coin_totalgame_infoc.COIN_TOTALself.total_livesgame_infoc.LIVESself.statestateself.ga
13、me_infogame_infoself.create_font_image_dict()self.create_info_labels()self.create_state_labels()self.flashing_coinFlashCoin(280,53)create_font_image_dict函数从之前加载的图片GFXtext_images中截取字母以及数字对应的图形保存在一个set中在后面创立文字时会用到。defcreate_font_image_dict(self):self.image_dictimage_listimage_rect_list#0-9(3,230,7,7),
14、(12,230,7,7),(19,230,7,7),(27,230,7,7),(35,230,7,7),(43,230,7,7),(51,230,7,7),(59,230,7,7),(67,230,7,7),(75,230,7,7),#A-Z(83,230,7,7),(91,230,7,7),(99,230,7,7),(107,230,7,7),(115,230,7,7),(123,230,7,7),(3,238,7,7),(11,238,7,7),(20,238,7,7),(27,238,7,7),(35,238,7,7),(44,238,7,7),(51,238,7,7),(59,238,
15、7,7),(67,238,7,7),(75,238,7,7),(83,238,7,7),(91,238,7,7),(99,238,7,7),(108,238,7,7),(115,238,7,7),(123,238,7,7),(3,246,7,7),(11,246,7,7),(20,246,7,7),(27,246,7,7),(48,246,7,7),#-*(68,249,6,2),(75,247,6,6)character_string0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-*forcharacter,image_rectinzip(character_str
16、ing,image_rect_list):self.image_dictcharacterget_image(GFXtext_images,*image_rect,(92,148,252),2.9)get_image函数从一个大的Surfacesheet中按照areax,y,width,height截取出局部图片放入Surfaceimage对应的起始位置00并按照scale参数调整大小。pygame的blit函数介绍如下pg.Surface.blit(source,dest,areaNone,special_flags0)-Rectdrawoneimageontoanotherdefget_i
17、mage(sheet,x,y,width,height,colorkey,scale):imagepg.Surface(width,height)rectimage.get_rect()image.blit(sheet,(0,0),(x,y,width,height)image.set_colorkey(colorkey)imagepg.transform.scale(image,(int(rect.width*scale),int(rect.height*scale)returnimage看一下create_info_labels函数中其中一个字符串MARIO是怎样在界面上显示的。creat
18、e_label函数参数(x,y)表示字符串在界面上的起始位置从self.image_dict中根据字符获取对应的Surface对象。set_label_rects函数会设置字符串中每一个Surface对象rect的(x,y)值。pygame.Rect对象中常用的成员变量(xy),表示这个Surface的左上角的位置。top,bottom表示Surface在y轴上最上边以及最下边的值所以top以及y值是一样的left,right:表示Surface在x轴上最左边以及最右边的值所以left以及x值是一样的下面的坐标图可以看到在左上角是整个屏幕的原点(0,0),图中标识了长方形rect的四个顶点的坐
19、标。defcreate_info_labels(self):.self.mario_label.self.create_label(self.mario_label,MARIO,75,30)defcreate_label(self,label_list,string,x,y):forletterinstring:label_list.append(Character(self.image_dictletter)self.set_label_rects(label_list,x,y)defset_label_rects(self,label_list,x,y):fori,letterinenum
20、erate(label_list):letter.rect.xx(letter.rect.width3)*i)letter.rect.yyifletter.imageself.image_dict-:letter.rect.y7letter.rect.x2Control类Control是状态机类main函数是游戏的主循环setup_states函数设置游戏启动时运行的状态。classControl():def_init_(self):self.screenpg.display.get_surface()self.doneFalseself.clockpg.time.Clock()self.fp
21、s60self.current_time0.0self.keyspg.key.get_pressed()self.state_dictself.state_nameNoneself.stateNonedefsetup_states(self,state_dict,start_state):self.state_dictstate_dictself.state_namestart_stateself.stateself.state_dictself.state_namedefmain(self):whilenotself.done:self.event_loop()self.update()pg
22、.display.update()self.clock.tick(self.fps)event_loop函数负责监听输入键盘输入以及退出按钮slef.keys保存键盘输入。update函数会检测状态的done值调用状态的更新函数。假如检测到当前状态完毕就调用flip_state函数进展旧状态的清理操作并转换到下一个状态。defupdate(self):self.current_timepg.time.get_ticks()ifself.state.done:self.flip_state()self.state.update(self.screen,self.keys,self.current
23、_time)defflip_state(self):previous,self.state_nameself.state_name,self.state.nextpersistself.state.cleanup()self.stateself.state_dictself.state_nameself.state.startup(self.current_time,persist)defevent_loop(self):foreventinpg.event.get():ifevent.typepg.QUIT:self.doneTrueelifevent.typepg.KEYDOWN:self
24、.keyspg.key.get_pressed()elifevent.typepg.KEYUP:self.keyspg.key.get_pressed()完好代码有两个文件constants.py以及state_demo.pyconstants.py保存了所有的字符串定义以及常量。constants.pyGAME_TIME_OUT表示游戏的超时时间这边为了demo演示设成了5秒实际是300秒。SCREEN_HEIGHT600SCREEN_WIDTH800SCREEN_SIZE(SCREEN_WIDTH,SCREEN_HEIGHT)ORIGINAL_CAPTIONSuperMarioBrosGA
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 何用 Python 实现 超级 玛丽 界面 状态机
限制150内