文章目录
前言
哈喽!大家好,这里是cwt的成长日记!
有多少人还记得“超级玛丽”这款经典游戏?
有多少人还记得那个戴帽子、大胡子、穿着背带裤的马里奥!
前段时间给大家更新了超级玛丽的基础版,只包含了第一关的部分功能。此次更新完善了第一关细节,并且更新到第4关。大家可以一口气玩四关喽。
后续关卡细节方面大家可以自由发挥,制作出属于自己独一无二的超级玛丽!!!
一、环境搭建
语言:python3
编译器:pycharm(好用)
#各自官网均可下载
主要模块:pygame (pip install pygame 即可安装该模块)
二、素材包
1.关卡,角色造型、各种道具等
2.各种音乐文件、各种道具等
3.各个关卡相关信息
三、马里奥项目
1.整体框架和细节(更新版)
main.py游戏主入口
source
components成分,部件
-box.py 盒子(游戏中带问号的方格)-brick.py 砖块
def __init__(self,x,y,brick_type,group,color=None,name='brick'):-coin.py 金币
-enemy.py 敌人
-player.py 主角
def __init__(self,name):
pygame.sprite.Sprite.__init__(self)
self.name = name
self.load_data() #加载角色数据,各种造型帧即其各种状态的速度
self.setup_states() #初始化角色各种状态
self.setup_velocities() #设置速率
self.setup_timers() #设置计时器
self.load_images() #载入主角的各种帧造型
def update(self,keys,level):
self.current_time = pygame.time.get_ticks() #以毫秒为单位获取时间
self.handle_states(keys,level) #处理各种状态
self.is_hurt_immune() #判断是否为无敌模式
def handle_states(self,keys,level): #处理各种状态
-powerup.py 强化(游戏中蘑菇)
def create_powerup(centerx,centery,type,flag):"""create powerup based on type and mario state"""if flag ==0:returnMushroom(centerx,centery)
elif flag ==1:returnFireflower(centerx, centery)
elif flag ==2:returnLifeMushroom(centerx, centery)
elif flag ==3:returnStar(centerx, centery)-stuff.py 物品(不起眼的小道具,旗子水管等)
classItem(pygame.sprite.Sprite):
def __init__(self,x,y,w,h,name):'''每个物品都有了隐形的轮廓,方便使用,方便进行碰撞检测,不需要传入图像,因为地图上有这些的图像了'''
pygame.sprite.Sprite.__init__(self)classCheckpoint(Item):'''检查点实际就是一个长方体精灵,碰到之后才会触发下面的事件'''
def __init__(self, x, y, w, h, checkint_type, enemy_groupid=None, name='checkpoint'):
Item.__init__(self,x,y,w,h,name)
self.checkpoint_type = checkint_type
self.enemy_groupid = enemy_groupid
-info.py 游戏信息(显示在屏幕上方的英文字体等)
def __init__(self,state):
self.state = state
self.create_state_lable() #创某阶段特有的文字
self.create_info_labels() #创建各阶段通用性息
self.flash_coin = coin.FlashingCoin() #初始化金币类
def create_state_lable(self): #创造某阶段特有的文字
def create_info_labels(self): #创建各阶段通用性息
def create_lable(self,label,size=40,width_scale=1.25,height_csale=1): #文字生成图片
def update(self): #调用金币类更新类更新方法,实现金币闪烁
def draw(self,surface): #把静态文字,动态金币等信息画上去
states状态
-main_menu.py 主页面(游戏刚进入的主菜单)
-MainMenu()类
def __init__(self): #初始化游戏信息字典
game_info={}
def start(self,game_info,current_time): #使用start函数对该状态进行初始化,
self.current_time=current_time
self.game_info=game_info
self.setup_background() #设置背景底图
self.setup_cursor() #设置光标
self.setup_palyer() #设置游戏角色
self.info=info.Info('main_menu',self.game_info) #初始化该类,设置文字信息
self.finished=False #主页面是否结束(状态机)
self.next ='load_screen'
def update()-load_screen.py 载入页面
def start(self,game_info,current_time):
self.game_info=game_info #获取信息
self.game_info['statue']='load_screen' #修改游戏状态
self.finished= False #告诉程序当前状态未结束
self.next ='level' #下个关卡为level
self.duration=2000 #持续时间
self.timer =0 #定时器
self.info = info.Info('load_screen',self.game_info) #初始化页面信息
def update():
def draw():-level.py 游戏关卡
def start(self,game_info,current_time):
self.current_time=current_time
self.game_info=game_info
self.game_info['statue']='level'
self.finished= False
self.next ='game_over'
self.info=info.Info('level',self.game_info)
#self.flag=plagpole.Flag(470,116)
self.load_map_data() #加载关卡数据
self.setup_background() #设置背景,新建了一个北京大小的图层
self.setup_start_posotions()#新建起始位置的方法
self.setup_player()
self.setup_ground_items() #设置大地,管道,楼梯,加载到精灵组
self.setup_brick_and_box()
self.setup_enemy()
self.setup_checkpoints() #初始化检查点
self.setup_flag()
self.sound=sound.Sound(self)
constants.py 存储游戏常量
sound.py 音效/音乐
set_up.py 启动代码(如设置屏幕宽高,载入素材等)
tools.py 主控,工具代码 (好用的工具,如图片加载工具)
-Game()类,游戏主控.Game().run运行游戏.Game().update更新游戏
def __init__(self,state_dict,start_state):
self.screen=pygame.display.get_surface() #获取当前显示的 Surface 对象,获得屏幕
self.clock=pygame.time.Clock()#创建一个时钟,控制帧率
self.keys=pygame.key.get_pressed() #获取按键状态
self.state_dict=state_dict #获取主菜单的状态字典
self.state=self.state_dict[start_state] #保存传入的状态(初始化该状态的类)
def update(self):-判断游戏当前状态是否结束,如果结束就传入下一个状态,初始化该状态并调用该状态的start()方法,目的是传递游戏数据。没有结束就调用当前状态的更新方法
def run(self):-循环获取事件,监听事件状态(键盘按键)-调用自身update方法
-更新屏幕
-设置游戏帧率(越大越流畅)
-load_graphics(path:图片路径)函数:加载图片 return:graphics{name:img} 本项目加载的是一张大图,大图上有很多小图
-pygame.image.load("图片路径").convert()-get_image(sheet:传入加载后的图片,x:图片在大图的x坐标,y:图片在大图的y坐标,width:图片宽,height:图片高,colorkey:改颜色设置为透明,scale:放大倍速)-load_all_music(directory, accept=('.wav','.mp3','.ogg','.mdi')): #加载音乐
-load_all_sound(directory, accept=('.wav','.mpe','.ogg','.mdi')): #加载按键声
难点:
Mario的位置:由其速度决定,由速度计算出位置
画面跟随:简单解决方法,1.锁定主角移动背景(略显沉闷)
2.主角动,背景也动
-新建一个新图层
-把游戏里的事件正常画在该图层
-把游戏窗口显示的画面渲染到屏幕上
碰撞检测:
常规做法:
-要把所有可能与Mario发生碰撞的物体一一罗列出来,依次做碰撞检测
-python中,可用精灵组加碰撞检测api实现
柱子水管等:
- 从json文件中读出坐标,逐个个实例化
- 创建了一个精灵组,把所有相同类型的放入同一组
- 然后在Mario位置更新函数中进行配置
信息传递:在第一个调用类的初始化函数中初始化game_info,用start函数代替初始化函数初始化类的各种函数,这样start可以反复调用,实现该阶段重置效果
传递到其他类中传入game_info
宝箱顶起4过程:1正常状态,2被顶了下,3微微隆起,4打开破碎
检查点技术:实际就是一个无形的矩形(为了解决Mario不论速度快慢都能见到对应阶段的野怪)bug:mario从右边碰到物体会身体会嵌入一些
精灵组:为了方便碰撞检测和统一操作
mario吃蘑菇变身时只写了x方向检测,注意y方向检车会使mario变成fall状态
2.游戏流程
3.程序入口
#编写者:cwt
#时间:2022/7/420:39
#游戏入口
from source import tools,setup
from source.statues import main_menu,level,load_screen,level2
import pygame
def main():
state_dict ={'main_menu': main_menu.MainMenu(),'load_screen': load_screen.LoadScreen(),'level': level.Level(),'game_over': load_screen.GameDver(),'level2': level.Level2(),'load_level2': load_screen.Load_level2(),'level3': level.Level3(),'load_level3': load_screen.Load_level3(),'level4': level.Level4(),'load_level4': load_screen.Load_level4()}'''test'''
game=tools.Game(state_dict,'main_menu') #初始化游戏主控
# state=main_menu.MainMenu() #初始化主页面
# state = level.Level()
# state = load_screen.LoadScreen()
game.run() #运行游戏
if __name__ =='__main__':main()
4.游戏主控(主要更新了加载音乐和音效的方法)
def load_all_music(directory, accept=('.wav','.mp3','.ogg','.mdi')):
songs ={}for song in os.listdir(directory):
name, ext = os.path.splitext(song)if ext.lower()inaccept:
songs[name]= os.path.join(directory, song)return songs
def load_all_sound(directory, accept=('.wav','.mpe','.ogg','.mdi')):
effects ={}for fx in os.listdir(directory):
name, ext = os.path.splitext(fx)if ext.lower()inaccept:
effects[name]= pygame.mixer.Sound(os.path.join(directory, fx))return effects
5.关卡类(增加第二关第三关第四关)
#编写者:cwt
#时间:2022/7/421:23
#关卡
classLevel:
def start(self,game_info):
self.game_info=game_info
self.finished= False
self.next ='game_over'
self.info=info.Info('level',self.game_info)print(self.flag)
self.load_map_data()
self.setup_background()
self.setup_start_posotions()#新建起始位置的方法
self.setup_player()
self.setup_ground_items()
self.setup_brick_and_box()
self.setup_enemy()
self.setup_checkpoints() #初始化检查点
self.setup_flag()classLevel2(Level):
def __init__(self):
Level.__init__(self)
def load_map_data(self):
file_name ='level_2.json'
file_path = os.path.join('D:/Users/Administrator/PycharmProjects/superMario/source/data/maps/', file_name)withopen(file_path)asf:
self.map_data = json.load(f)
def is_or_not_finished(self,keys):#print(self.player.baoqi,self.player.rect.y)if keys[pygame.K_9]:
self.finished = True
self.next ='load_level3'if self.player.baoqi== True and self.player.rect.y>400:
self.finished=True
self.next ='load_level3'classLevel3(Level):
def __init__(self):
Level.__init__(self)
def load_map_data(self):
file_name ='level_3.json'
file_path = os.path.join('D:/Users/Administrator/PycharmProjects/superMario/source/data/maps/', file_name)withopen(file_path)asf:
self.map_data = json.load(f)
def is_or_not_finished(self,keys):
# print(self.player.baoqi,self.player.rect.y)if keys[pygame.K_9]:
self.finished = True
self.next ='load_level4'if self.player.baoqi == True and self.player.rect.y >400:
self.finished = True
self.next ='load_level4'classLevel4(Level):
def __init__(self):
Level.__init__(self)
def load_map_data(self):
file_name ='level_4.json'
file_path = os.path.join('D:/Users/Administrator/PycharmProjects/superMario/source/data/maps/', file_name)withopen(file_path)asf:
self.map_data = json.load(f)
def setup_flag(self):
self.pole_group = pygame.sprite.Group()
self.flag_group = pygame.sprite.Group()
self.finial_group = pygame.sprite.Group()'''测试用'''for item in[{"x":6470,"y":116,"type":0},{"x":6500,"y":97,"type":1},{"x":6500,"y":137,"type":1},{"x":6500,"y":177,"type":1},{"x":6500,"y":217,"type":1},{"x":6500,"y":257,"type":1},{"x":6500,"y":297,"type":1},{"x":6500,"y":337,"type":1},{"x":6500,"y":377,"type":1},{"x":6500,"y":417,"type":1},{"x":6500,"y":450,"type":1},{"x":6500,"y":97,"type":2}]:
# for item in self.map_data['flagpole']:
x, y, type = item['x'], item['y'], item['type']if type ==0:
self.flag_group.add(plagpole.Flag(x, y))
elif type ==1:
self.pole_group.add(plagpole.Pole(x, y))else:
self.finial_group.add(plagpole.Finial(x, y))
def is_or_not_finished(self,keys):
# print(self.player.baoqi,self.player.rect.y)if keys[pygame.K_8]:
self.player.hurt_imune =True #伤害免疫
if keys[pygame.K_7]:
self.player.hurt_imune = False # 伤害免疫
if keys[pygame.K_9]:
self.finished = True
self.next ='load_screen'if self.player.baoqi == True and self.player.rect.y >400:
self.finished = True
self.next ='load_screen'
6.增加角色按键音效
classSound(object):"""Handles all sound for the game"""
def __init__(self, level):"""Initialize the class"""
self.sound_dict = setup.SOUND
self.music_dict = setup.MUSIC
self.level =level
# self.overhead_info = overhead_info
# self.game_info = overhead_info.game_info
self.set_music_mixer()
def set_music_mixer(self):"""Sets music for level"""if self.level.player.dead:
pg.mixer.music.load(self.music_dict['death'])
pg.mixer.music.play()
self.state = c.GAME_OVERelse:
pg.mixer.music.load(self.music_dict['main_theme'])
pg.mixer.music.play()
self.state = c.NORMAL
def update(self, game_info, mario):"""Updates sound object with game info"""
self.game_info = game_info
self.mario = mario
self.handle_state()
def handle_state(self):"""Handles the state of the soundn object"""#print('444')if self.state == c.NORMAL:if self.mario.dead:
self.play_music('death', c.MARIO_DEAD)
def play_music(self, key, state):"""Plays new music"""
pg.mixer.music.load(self.music_dict[key])
pg.mixer.music.play()
self.state = state
def stop_music(self):"""Stops playback"""
pg.mixer.music.stop()
四、成果展示
1.游戏主页面
2.进入游戏
3.顶出蘑菇
4.大mario顶出顶碎砖块,顶出鲜花
5.火焰马里奥发射火球
6.视频效果
python制作超级玛丽,好玩到飞起!
总结
本项目参考B站up主教程,完整代码已上传github,持续更新优化,需要的小伙伴自取:https://github.com/cwt2022/Mario
对游戏感兴趣的小伙伴儿赶紧自己动手造一个吧~~
有问题的小伙伴可以在评论区留言,大家一起学习共同进步!
版权归原作者 cwt成长日记 所有, 如有侵权,请联系我们删除。