欢迎来到得力文库 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
得力文库 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    如何用Python实现超级玛丽的界面和状态机?.docx

    • 资源ID:73269322       资源大小:23.19KB        全文页数:22页
    • 资源格式: DOCX        下载积分:14.8金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要14.8金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    如何用Python实现超级玛丽的界面和状态机?.docx

    如何用Python实现超级玛丽的界面和状态机?|marble_xu编辑|郭芮来源|CSDNboke小时候的经典游戏代码参考了github上的工程Mario-Level-1s:/github/justinmeister/Mario-Level-1使用pygame来实现从中学习到了横版过关游戏实现中的一些处理方法。原工程实现了超级玛丽的第一个小关。在原工程的根底上游戏使用json文件来保存每一个关卡的数据将数据以及代码解耦合目前已开发4个小关后续关卡的扩展也很方便只需要添加json文件以及地图图片支持新的怪物就行。游戏还支持进入水管到新的子地图。这篇文章是要介绍下游戏中的几个界面显示以及界面之间怎样转换所以特意写了一个demo程序完好的游戏代码在下面的github链接s:/github/marblexu/PythonSuperMario中下载。状态机介绍游戏中的状态机一般都是有限状态机简写为FSMFiniteStateMachine简称状态机是表示有限个状态和在这些状态之间的转移以及动作等行为的数学模型。状态机的每一个状态至少需要有下面三个操作Startup当从其他状态进入这个状态时需要进展的初始化操作Update在这个状态运行时进展的更新操作Cleanup当从这个状态退出时需要进展的去除操作。状态需要的变量next:表示这个状态退出后要转到的下一个状态persist在状态间转换时需要传递的数据done表示这个状态是否完毕状态时机根据这个值来决定转换状态。游戏界面状态机的状态转换图如下箭头表示可能的状态转换方向注意有个转换不太好画出来TimeOut状态可以转换到GameOver状态。图1这几个状态的意思比拟简单下面把游戏界面的截图发一下。MainMenu主菜单启动程序就进入这个状态可以用UP以及DOWN键选择player1或者player2按回车键开启游戏。图2LoadScreen游戏开场前的加载界面。图3GameRun游戏运行时的状态在代码实现中是Level类。图4GameOver人物死亡且生命数目为0时到这个状态。图5TimeOut在游戏中时间超时会到这个状态这个以及GameOver类似就不截图了。状态机代码实现因为这篇文章的目的是游戏界面的状态机实现所以专门写了一个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)SCREENpg.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.path.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函数设置起始状态是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函数中定义了上面讲的三个变量nextpersistdone还有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,keys,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_list2400,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):returnc.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_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.game_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),(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,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_string,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_image(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是怎样在界面上显示的。create_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的四个顶点的坐标。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,letterinenumerate(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.fps60self.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.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_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.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_CAPTIONSuperMarioBrosGAME_TIME_OUT5#COLORS#RGBBLACK(0,0,0)SIZE_MULTIPLIER2.5BRICK_SIZE_MULTIPLIER2.69BACKGROUND_MULTIPLER2.679GROUND_HEIGHTSCREEN_HEIGHT-62#STATESFORENTIREGAMEMAIN_MENUmainmenuLOAD_SCREENloadscreenTIME_OUTtimeoutGAME_OVERgameoverLEVELlevel#MAINMENUCURSORSTATESPLAYER11PLAYERGAMEPLAYER22PLAYERGAME#GAMEINFODICTIONARYKEYSCOIN_TOTALcointotalSCOREscoreTOP_SCOREtopscoreLIVESlivesCURRENT_TIMEcurrenttimeLEVEL_NUMlevelnumPLAYER_NAMEplayernamePLAYER_MARIOmarioPLAYER_LUIGIluigiITEM_SHEETitem_objectsstate_demo.py上面讲的状态类状态机类都放在这里。importosimportpygameaspgfromabcimportABC,abstractmethodimportconstantsascclassState():def_init_(self):self.start_time0.0self.current_time0.0self.doneFalseself.nextNoneself.persistabstractmethoddefstartup(self,current_time,persist):abstractmethoddefcleanup(self):self.doneFalsereturnself.persistabstractmethoddefupdate(sefl,surface,keys,current_time):abstractmethodclassMenu(State):def_init_(self):State._init_(self)persistc.COIN_TOTAL:0,c.SCORE:0,c.LIVES:3,c.TOP_SCORE:0,c.CURRENT_TIME:0.0,c.LEVEL_NUM:1,c.PLAYER_NAME:c.PLAYER_MARIOself.startup(0.0,persist)defstartup(self,current_time,persist):self.nextc.LOAD_SCREENself.persistpersistself.game_infopersistself.overhead_infoInfo(self.game_info,c.MAIN_MENU)self.setup_background()self.setup_player()self.setup_cursor()defsetup_background(self):self.backgroundGFXlevel_1self.background_rectself.background.get_rect()self.backgroundpg.transform.scale(self.background,(int(self.background_rect.width*c.BACKGROUND_MULTIPLER),int(self.background_rect.height*c.BACKGROUND_MULTIPLER)self.viewportSCREEN.get_rect(bottomSCREEN_RECT.bottom)self.image_dictimageget_image(GFXtitle_screen,1,60,176,88,(255,0,220),c.SIZE_MULTIPLIER)rectimage.get_rect()rect.x,rect.y(170,100)self.image_dictGAME_NAME_BOX(image,rect)defsetup_player(self):self.player_listplayer_rect_info(178,32,12,16),(178,128,12,16)forrectinplayer_rect_info:imageget_image(GFXmario_bros,*rect,c.BLACK,2.9)rectimage.get_rect()rect.x,rect.bottom110,c.GROUND_HEIGHTself.player_list.append(image,rect)self.player_index0defsetup_cursor(self):self.cursorpg.sprite.Sprite()self.cursor.imageget_image(GFXc.ITEM_SHEET,24,160,8,8,c.BLACK,3)rectself.cursor.image.get_rect()rect.x,rect.y(220,358)self.cursor.rectrectself.cursor.statec.PLAYER1defupdate(self,surface,keys,current_time):self.current_timecurrent_timeself.game_infoc.CURRENT_TIMEself.current_timeself.player_imageself.player_listself.player_index0self.player_rectself.player_listself.player_index1self.update_cursor(keys)self.overhead_info.update(self.game_info)surface.blit(self.background,self.viewport,self.viewport)surface.blit(self.image_dictGAME_NAME_BOX0,self.image_dictGAME_NAME_BOX1)surface.blit(self.player_image,self.player_rect)surface.blit(self.cursor.image,self.cursor.rect)self.overhead_info.draw(surface)defupdate_cursor(self,keys):ifself.cursor.statec.PLAYER1:self.cursor.rect.y358ifkeyspg.K_DOWN:self.cursor.statec.PLAYER2self.player_index1self.game_infoc.PLAYER_NAMEc.PLAYER_LUIGIelifself.cursor.statec.PLAYER2:self.cursor.rect.y403ifkeyspg.K_UP:self.cursor.statec.PLAYER1self.player_index0self.game_infoc.PLAYER_NAMEc.PLAYER_MARIOifkeyspg.K_RETURN:self.doneTrueclassLoadScreen(State):def_init_(self):State._init_(self)self.time_list2400,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):returnc.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_time)self.time_list2:surface.fill(106,150,252)else:self.doneTrueclassGameOver(LoadScreen):def_init_(self):LoadScreen._init_(self)self.time_list3000,3200,3235defset_next_state(self):returnc.MAIN_MENUdefset_info_state(self):returnc.GAME_OVERclassTimeOut(LoadScreen):def_init_(self):LoadScreen._init_(self)self.time_list2400,2600,2635defset_next_state(self):ifself.persistc.LIVES0:returnc.GAME_OVERelse:returnc.LOAD_SCREENdefset_info_state(self):returnc.TIME_OUTclassLevel(State):def_init_(self):State._init_(self)defstartup(self,current_time,persist):self.game_infopersistself.persistself.game_infoself.playerNoneself.overhead_infoInfo(self.game_info,c.LEVEL)self.setup_background()defsetup_background(self):self.backgroundGFXlevel_1self.bg_rectself.background.get_rect()self.backgroundpg.transform.scale(self.background,(int(self.bg_rect.width*c.BACKGROUND_MULTIPLER),int(self.bg_rect.height*c.BACKGROUND_MULTIPLER)self.bg_rectself.background.get_rect()self.levelpg.Surface(self.bg_rect.w,self.bg_rect.h).convert()self.viewportSCREEN.get_rect(bottomself.bg_rect.bottom)defupdate(self,surface,keys,current_time):self.game_infoc.CURRENT_TIMEself.current_timecurrent_timeself.overhead_info.update(self.game_info,self.player)ifself.overhead_info.time0:self.update_game_info()self.doneTrueself.draw(surface)defupdate_game_info(self):self.persistc.LIVES-1ifself.persistc.LIVES0:self.nextc.GAME_OVERelifself.overhead_info.time0:self.nextc.TIME_OUTelse:self.nextc.LOAD_SCREENdefdraw(self,surface):self.level.blit(self.background,self.viewport,self.viewport)surface.blit(self.level,(0,0),self.viewport)self.overhead_info.draw(surface)classCharacter(pg.sprite.Sprite):def_init_(self,image):pg.sprite.Sprite._init_(self)self.imageimageself.rectself.image.get_rect()classInfo():def_init_(self,game_info,state):self.coin_totalgame_infoc.COIN_TOTALself.total_livesgame_infoc.LIVESself.statestateself.game_infogame_infoself.create_font_image_dict()self.create_info_labels()self.create_state_labels()self.flashing_coinFlashCoin(280,53)defcreate_font_image_dict(self):self.image_dictimage_listimage_rect_list#0-9(3,230,7,7),(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,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_string,image_rect_list):self.image_dictcharacterget_image(GFXtext_images,*image_rect,(92,148,252),2.9)defcreate_info_labels(self):self.score_textself.coin_count_textself.mario_labelself.world_labelself.time_labelself.stage_labelself.create_label(self.score_text,000000,75,55)self.create_label(self.coin_count_text,*00,300,55)self.create_label(self.mario_label,MARIO,75,30)self.create_label(self.world_label,WORLD,450,30)self.create_label(self.time_label,TIME,625,30)self.create_label(self.stage_label,1-1,472,55)self.info_labelsself.score_text,self.coin_count_text,self.mario_label,self.world_label,self.time_label,self.stage_labeldefcreate_state_labels(self):ifself.statec.MAIN_MENU:self.create_main_menu_labels()elifself.statec.LOAD_SCREEN:self.create_player_image()self.create_load_screen_labels()elifself.statec.LEVEL:self.create_level_labels()elifself.statec.GAME_OVER:self.create_game_over_labels()elifself

    注意事项

    本文(如何用Python实现超级玛丽的界面和状态机?.docx)为本站会员(安***)主动上传,得力文库 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知得力文库 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于得利文库 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

    © 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

    黑龙江省互联网违法和不良信息举报
    举报电话:0468-3380021 邮箱:hgswwxb@163.com  

    收起
    展开