0


python小游戏之超级玛丽进阶版(1~4关)。好玩到爆炸~【内附github源码,及其详细备注】

文章目录


前言

哈喽!大家好,这里是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制作超级玛丽,好玩到飞起!

地址:https://www.bilibili.com/video/BV1x24y1o7xN/?spm_id_from=333.999.0.0&vd_source=fb2219609a4ef30c028c05ca593238e9

总结

本项目参考B站up主教程,完整代码已上传github,持续更新优化,需要的小伙伴自取:https://github.com/cwt2022/Mario
对游戏感兴趣的小伙伴儿赶紧自己动手造一个吧~~
有问题的小伙伴可以在评论区留言,大家一起学习共同进步!
在这里插入图片描述

标签: python 游戏 pygame

本文转载自: https://blog.csdn.net/weixin_44201690/article/details/126718886
版权归原作者 cwt成长日记 所有, 如有侵权,请联系我们删除。

“python小游戏之超级玛丽进阶版(1~4关)。好玩到爆炸~【内附github源码,及其详细备注】”的评论:

还没有评论