Python技术栈

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 502|回复: 11

[学习资料] 如何用Python实现超级玛丽的界面和状态机?

[复制链接]

12

主题

15

帖子

70

积分

注册会员

Rank: 2

积分
70
发表于 2019-12-25 13:04:31 | 显示全部楼层 |阅读模式
本帖最后由 珍宝珠 于 2019-12-25 13:23 编辑

状态机代码实现

因为这篇文章的目的是游戏界面的状态机实现,所以专门写了一个state_demo.py文件,让大家可以更加方便的看代码。

游戏启动代码
开始是pygame的初始化,设置屏幕大小为c.SCREEN_SIZE(800,600)。所有的常量都保存在单独的constants.py中。

[mw_shl_code = python,true] import os
导入pygame as pg
导入常量as c

pg.init()
pg.event.set_allowed([pg.KEYDOWN,pg.KEYUP,pg.QUIT])
pg.display.set_caption(c。 ORIGINAL_CAPTION)
SCREEN = pg.display.set_mode(c.SCREEN_SIZE)
SCREEN_RECT = SCREEN.get_rect()
[/ mw_shl_code]

load_all_gfx函数查找指定目录下所有符合后缀名的图片,使用pg.image.load函数加载,保存在图形集中。

GFX保存在资源/图形目录找到的所有图片,后面获取各种图形时会用到。

[mw_shl_code =蟒,真] DEF load_all_gfx(目录,设置colorkey =(255,0,255),接受=( 'PNG。', '.JPG', '.BMP', '.gif注意')):
    图形= {}
    为os.listdir(目录)中的图片:
        名称,ext = os.path.splitext(pic)
        如果接受中的ext.lower():
            img = pg.image.load(os.path.join(目录,图片))
            如果img.get_alpha():
                img = img.convert_alpha()
            其他:
                img = img.convert()
                img.set_colorkey(colorkey)
            graphics [name] = img
    返回图形

GFX = load_all_gfx(os.path.join(“ resources”, “图形”))
[/ mw_shl_code]

下面是demo的入口函数,先创建了一个保存所有状态的state_dict设置,调用setup_states函数设置启动状态是MAIN_MENU。

[mw_shl_code = python,true]如果__name __ =='__ main__':
    游戏= 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()
[/ mw_shl_code]

状态类
先定义一个状态基类,按照上面说的状态需要的三个操作分别定义函数(启动,更新,清理)。在init函数中定义了上面说的三个变量(next,persist,``` class State():def init(self):self.start_time = 0.0 self.current_time = 0.0 self.done = False self.next = None self.persist = {}

@abstractmethod def startup(自我,当前时间,持续):'''抽象方法'''

def cleanup(self):self.done = False返回self.persist

@abstractmethod def更新(sefl,surface,keys,current_time):'''抽象方法'''

看一个状态类LoadScreen的具体实现,这个状态的显示效果样式3。startup函数保存了预期的persist,设置下一个为Level状态类,start_time保存进入该状态的开始时间。初始化一个Infoclass,这个就是专门用来显示界面信息的。更新函数根据在这个状态已运行的时间(current_time-self.start_time),决定显示内容和正确结束状态(self.done = True)。[mw_shl_code = python,true]类LoadScreen(状态):
   def __init __(self):
       状态.__ init __(self)
       self.time_list = [2400,2600,2635]

   def startup(self,current_time,persist):
       self.start_time = current_time
       self.persist =持续的
       self。 game_info = self.persist
       self.next = self.set_next_state()

       info_state = self.set_info_state()
       self.overhead_info = Info(self.game_info,info_state)

   def set_next_state(self):
       返回c。LEVEL

   def set_info_state(自身):
       返回c.LOAD_SCREEN

   def更新(self,surface,keys,current_time):
       if(current_time-self.start_time)<self.time_list [0]:
           surface.fill(c.BLACK)
           self.overhead_info。更新(self.game_info)
           self.overhead_info.draw(surface)
       elif(current_time-self.start_time)<self.time_list [1]:
           surface.fill(c.BLACK)
       elif(current_time-self.start_time)<self.time_list [2]:
           surface.fill((106,150,252))
       否则:
self.done = True.Done = True

信息类
下面介绍的信息类,界面的显示大部分都是由它来完成,初始化函数中create_info_labels函数创建通用的信息,create_state_labels函数对于不同的状态,会初始化不同的信息。

[mw_shl_code = python,true]类Info():
   def __init __(自我,game_info,状态):
       self.coin_total = game_info [c.COIN_TOTAL]
       self.total_lives = game_info [c.LIVES]
       self.state =状态
       self。 game_info = game_info

       self.create_font_image_dict()
       self.create_info_labels()
       self.create_state_labels()
       self.flashing_coin = FlashCoin(280,53)
[/ mw_shl_code] [/ mw_shl_code]

create_font_image_dict函数从之前加载的图片GFX ['text_images']中,截取字母和数字对应的图形,保存在一个设置中,在后面创建文字时会用到。

[mw_shl_code = python,true] def create_font_image_dict(self):
    self.image_dict = {}
    image_list = []

    image_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_string ='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-*'

    表示字符,zip中的image_rect(character_string,image_rect_list):
        self.image_dict [character] = get_image(GFX ['text_images'],
                                        * image_rect,(
92,148,252 ),2.9)[/ mw_shl_code]

get_image函数从一个大的表面工作表中按照面积(x,y,宽度,高度)截取的部分图片插入表面图像对应的起始位置(0,0),并按比例参数调整大小。

pygame的blit函数介绍如下:

[mw_shl_code = python,true] pg.Surface.blit(source,dest,area = None,special_flags = 0)-> Rect
    将一个图像绘制到另一个
def get_image(sheet,x,y,width,height,colorkey,scale) :
       image = pg.Surface([width,height])
       rect = image.get_rect()

       image.blit(sheet,(0,0),(x,y,width,height))
       image.set_colorkey(colorkey)
       image = pg.transform.scale(image,
                                  (int(rect.width * scale),
                                   int(rect.height * scale)))
       返回图像
[/ mw_shl_code]

看一下create_info_labels函数中其中一个字符串'MARIO'是如何在界面上显示的。

create_label函数参数(x,y)表示在界面上的起始位置,从self.image_dict中根据字符获取对应的表面对象。set_label_rects函数会设置字符串中每一个表面对象rect的(x,y)值。

[mw_shl_code = python,true] pygame.Rect对象中常用的成员变量(x,y),表示此Surface的左上角的位置。top
,bottom:表示Surface在y轴上最上边和最下边的值,所以top和y值是一样的
左,右:表示表面在x轴上最左边和最右边的值,所以left和x值是一样的
[/ mw_shl_code]

下面的坐标图可以看到,在左上角是整个屏幕的原点(0,0),图示标识了附件矩形的四个顶点的坐标。

[mw_shl_code = python,true] def create_info_labels(self):
        ...
        self.mario_label = []
        ...
        self.create_label(self.mario_label,'MARIO',

    75,30 )def create_label(self,label_list,字符串, x,y):
        用于字符串中的字母:
            label_list.append(Character(self.image_dict [letter]))
        self.set_label_rects(label_list,x,y)

    def set_label_rects(self,label_list,x,y):
        用于i,字母在枚举(label_list):
            letter.rect.x = X +((letter.rect.width + 3)* I)
            letter.rect.y = Y
            如果letter.image == self.image_dict [ ' - ']:
                信.rect.y + = 7
                letter.rect.x + = 2
[/ mw_shl_code]

控制类Control是状态机类,主要功能是游戏的主循环,setup_states功能设置游戏启动时运行的状态。

[mw_shl_code = python,true] class Control():
   def __init __(self):
       self.screen = pg.display.get_surface()
       self.done = False
       self.clock = pg.time.Clock()
       self.fps = 60
       self.current_time = 0.0
       self.keys = pg.key.get_pressed()
       self.state_dict = {}
       self.state_name = None
       self.state = None

   def setup_states(self,state_dict,start_state):
       self.state_dict = state_dict
       self.state_name = start_state
       self.state = self.state_dict [self.state_name]

   def main(self):
       而不是self.done:
           self.event_loop()
           self.update()
           pg.display.update()
           self.clock.tick(self.fps)[/ mw_shl_code]

event_loop函数负责监听输入(键盘输入和退出按钮),slef.keys保存键盘输入。

如果检测到当前状态结束,就调用滚动状态函数进行旧状态的清理操作,并转换到下一个状态。更新函数会检测状态的完成值,调用状态的更新函数。

[mw_shl_code = python,true] def update(self):
     self.current_time = pg.time.get_ticks()
     如果self.state.done:
         self.flip_state()
     self.state.update(self.screen,self.keys, self.current_time)

def flip_state(self):
     前一个,self.state_name = self.state_name,self.state.next
     持久化= self.state.cleanup()
     self.state = self.state_dict [self.state_name]
     self.state。 startup(self.current_time,persist)

def event_loop(self):
     用于pg.event.get()中的事件:
         if event.type == pg.QUIT:
             self.done =真
         elif event.type == pg.KEYDOWN:
             self.keys = pg.key.get_pressed()
         elif event.type == pg.KEYUP:
             self.keys = pg.key.get_pressed()[/ mw_shl_code]

代码完整
有两个文件constants.py状语从句:state_demo.py,constants.py保存了所有的字符串定义和常量。constants.pyGAME_TIME_OUT表示游戏的超时时间,这边为了演示,设置成5秒,实际是300秒。

阅读报纸获取完整代码:https//developer.aliyun.com/ask/267501?utm_content = g_1000095974

Python 总 群
回复

使用道具 举报

0

主题

8

帖子

26

积分

新手上路

Rank: 1

积分
26
发表于 2019-12-25 13:04:31 | 显示全部楼层
请给我推荐一款专为新手用的Python开发工具,谢谢!
Python 总 群
回复

使用道具 举报

0

主题

5

帖子

20

积分

新手上路

Rank: 1

积分
20
发表于 2019-12-25 13:05:14 | 显示全部楼层
学习下
Python 总 群
回复

使用道具 举报

0

主题

6

帖子

22

积分

新手上路

Rank: 1

积分
22
发表于 2019-12-25 13:17:53 | 显示全部楼层
占坑编辑ing
Python 总 群
回复

使用道具 举报

3

主题

10

帖子

39

积分

新手上路

Rank: 1

积分
39
发表于 2019-12-25 13:23:45 | 显示全部楼层
新人求带!python小白一枚!
Python 总 群
回复

使用道具 举报

0

主题

4

帖子

18

积分

新手上路

Rank: 1

积分
18
发表于 2019-12-25 13:27:38 | 显示全部楼层
python新人求脸熟...
Python 总 群
回复

使用道具 举报

0

主题

6

帖子

22

积分

新手上路

Rank: 1

积分
22
发表于 2019-12-25 13:28:16 | 显示全部楼层
python新人求脸熟...
Python 总 群
回复

使用道具 举报

0

主题

7

帖子

24

积分

新手上路

Rank: 1

积分
24
发表于 2019-12-25 13:39:58 | 显示全部楼层
前排,哇咔咔
Python 总 群
回复

使用道具 举报

0

主题

5

帖子

20

积分

新手上路

Rank: 1

积分
20
发表于 2019-12-25 13:40:52 | 显示全部楼层
有用python 开发前端web的吗?
Python 总 群
回复

使用道具 举报

0

主题

5

帖子

20

积分

新手上路

Rank: 1

积分
20
发表于 2019-12-25 13:47:35 | 显示全部楼层
哪位兄弟手头有python3做数据分析的资料???
Python 总 群
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


QQ|Archiver|手机版|小黑屋|Python.BBS ( 鲁ICP备18046958号 )

GMT+8, 2020-1-25 23:40 , Processed in 0.197256 second(s), 34 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表