怎么用python做超级玛丽_如何用 Python 实现超级玛丽的界面和状态机?

作者 | marble_xu责编 | 郭芮出品 | CSDN博客小时候的经典游戏,代码参考了github上的项目Mario-Level-1(https://github.com/justinmeister/Mario-Level-1),使用pygame来实现,从中学习到了横版过关游戏实现中的一些处理方法。原项目实现了超级玛丽的第一个小关。在原项目的基础上,游戏使用json文件来保存每一个关卡的数据...
摘要由CSDN通过智能技术生成

作者 | marble_xu

责编 | 郭芮

出品 | CSDN博客

小时候的经典游戏,代码参考了github上的项目Mario-Level-1(https://github.com/justinmeister/Mario-Level-1),使用pygame来实现,从中学习到了横版过关游戏实现中的一些处理方法。原项目实现了超级玛丽的第一个小关。在原项目的基础上,游戏使用json文件来保存每一个关卡的数据,将数据和代码解耦合,目前已开发4个小关,后续关卡的扩展也很方便,只需要添加json文件和地图图片,支持新的怪物就行。游戏还支持进入水管,到新的子地图。这篇文章是要介绍下游戏中的几个界面显示和界面之前如何转换,所以特意写了一个demo程序,完整的游戏代码在下面的github链接(https://github.com/marblexu/PythonSuperMario)中下载。

状态机介绍

游戏中的状态机一般都是有限状态机,简写为FSM(Finite State Machine),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。状态机的每一个状态至少需要有下面三个操作:Startup:当从其他状态进入这个状态时,需要进行的初始化操作;

Update :在这个状态运行时进行的更新操作;

Cleanup:当从这个状态退出时,需要进行的清除操作。

状态需要的变量:next: 表示这个状态退出后要转到的下一个状态;

persist:在状态间转换时需要传递的数据;

done:表示这个状态是否结束,状态机会根据这个值来决定转换状态。

游戏界面状态机的状态转换图如下,箭头表示可能的状态转换方向:(注意有个转换不太好画出来:Time Out状态可以转换到Game Over状态。)

图1

这几个状态的意思比较简单,下面把游戏界面的截图发一下。Main Menu:主菜单,启动程序就进入这个状态,可以用UP和DOWN键选择player 1或player 2,按回车键开启游戏。

图2Load Screen:游戏开始前的加载界面。

图3Game Run:游戏运行时的状态,在代码实现中是Level类。

图4Game Over:人物死亡且生命数目为0时到这个状态。

图5Time Out:在游戏中时间超时会到这个状态,这个和Game Over类似,就不截图了。

状态机代码实现

因为这篇文章的目的是游戏界面的状态机实现,所以专门写了一个state_demo.py文件,让大家可以更加方便的看代码。游戏启动代码开始是 pygame的初始化,设置屏幕大小为c.SCREEN_SIZE(800, 600)。所有的常量都保存在单独的constants.py中。

import os

import pygame as pg

import constants 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()

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

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

def load_all_gfx(directory, colorkey=(255,0,255), accept=('.png', '.jpg', '.bmp', '.gif')):

graphics = {}

for pic in os.listdir(directory):

name, ext = os.path.splitext(pic)

if ext.lower() in accept:

img = pg.image.load(os.path.join(directory, pic))

if img.get_alpha():

img = img.convert_alpha()

else:

img = img.convert()

img.set_colorkey(colorkey)

graphics[name] = img

return graphics

GFX = load_all_gfx(os.path.join("resources","graphics"))

下面是demo的入口函数,先创建了一个保存所有状态的state_dict set,调用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()

状态类

先定义一个State 基类, 按照上面说的状态需要的三个操作分别定义函数(startup, update, cleanup)。在 init 函数中定义了上面说的三个变量(next,persist,done),还有start_time 和 current_time 用于记录时间。

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(self, current_time, persist):

'''abstract method'''

def cleanup(self):

self.done = False

return self.persist

@abstractmethod

def update(sefl, surface, keys, current_time):

'''abstract method'''

看一个状态类LoadScreen的具体实现,这个状态的显示效果如图3。

startup 函数保存了传入的persist,设置 next 为Level 状态类,start_time保存进入这个状态的开始时间。初始化一个Info类,这个就是专门用来显示界面信息的。update 函数根据在这个状态已运行的时间(current_time - self.start_time),决定显示内容和是否结束状态(self.done = True)。

class LoadScreen(State):

def __init__(self):

State.__init__(self)

self.time_list = [2400, 2600, 2635]

def startup(self, current_time, persist):

self.start_time = current_time

self.persist = 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):

return c.LEVEL

def set_info_state(self):

return c.LOAD_SCREEN

def update(self, surface, keys, current_time):

if (current_time - self.start_time) < self.time_list[0]:

surface.fill(c.BLACK)

self.overhead_info.update(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))

else:

self.done = True

Info类

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

class Info():

def __init__(self, game_info, state):

self.coin_total = game_info[c.COIN_TOTAL]

self.total_lives = game_info[c.LIVES]

self.state = 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)

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

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,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
写一个超级玛丽游戏需要一定的编程基础和游戏开发经验。下面是一个简单的超级玛丽游戏的实现思路: 1. 导入必要的库,如pygame等。 2. 定义游戏窗口的大小和背景颜色。 3. 加载游戏中需要使用的图片、音效等资源。 4. 定义超级玛丽和其他角色的属性,如位置、速度等。 5. 编写超级玛丽和其他角色的移动函数。 6. 编写碰撞检测函数,检测角色之间的碰撞。 7. 编写主循环,包含游戏的逻辑处理、事件响应、画面绘制等。 下面是一个简单的超级玛丽游戏代码示例: ```python import pygame # 初始化pygame pygame.init() # 设置游戏窗口大小和背景颜色 screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Super Mario") bg_color = (255, 255, 255) # 加载游戏中需要使用的图片、音效等资源 mario_image = pygame.image.load("mario.png") mushroom_image = pygame.image.load("mushroom.png") coin_sound = pygame.mixer.Sound("coin.wav") # 定义超级玛丽和蘑菇的属性 mario_pos = [400, 500] # 超级玛丽的初始位置 mario_speed = 5 # 超级玛丽的移动速度 mushroom_pos = [100, 500] # 蘑菇的初始位置 mushroom_speed = 2 # 蘑菇的移动速度 # 定义超级玛丽和蘑菇的移动函数 def move_mario(): global mario_pos keys = pygame.key.get_pressed() if keys[pygame.K_LEFT] and mario_pos[0] > 0: mario_pos[0] -= mario_speed if keys[pygame.K_RIGHT] and mario_pos[0] < 800 - mario_image.get_width(): mario_pos[0] += mario_speed def move_mushroom(): global mushroom_pos, mushroom_speed mushroom_pos[0] += mushroom_speed if mushroom_pos[0] < 0 or mushroom_pos[0] > 800 - mushroom_image.get_width(): mushroom_speed = -mushroom_speed # 定义碰撞检测函数 def check_collision(): global mushroom_pos if abs(mario_pos[0] - mushroom_pos[0]) < 50 and abs(mario_pos[1] - mushroom_pos[1]) < 50: mushroom_pos[0] = 1000 # 将蘑菇移出屏幕 coin_sound.play() # 加载字体 font = pygame.font.Font(None, 36) # 开始游戏的主循环 while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() # 移动超级玛丽和蘑菇 move_mario() move_mushroom() # 检测碰撞 check_collision() # 绘制游戏界面 screen.fill(bg_color) screen.blit(mario_image, mario_pos) screen.blit(mushroom_image, mushroom_pos) # 显示得分 score_text = font.render("Score: 0", True, (0, 0, 0)) screen.blit(score_text, (10, 10)) # 更新屏幕 pygame.display.update() ``` 这个示例只实现超级玛丽和蘑菇的基本移动和碰撞检测,游戏还需要根据实际需求进行完善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值