首页 > 编程语言 >【Python游戏开发】用Python实现一个简易的超级玛丽游戏!

【Python游戏开发】用Python实现一个简易的超级玛丽游戏!

时间:2024-09-06 13:52:21浏览次数:11  
标签:障碍物 游戏 Python self 玛丽 超级玛丽 窗体 pygame image

在这里插入图片描述

前言

  • 小时候最喜欢玩的小游戏就是超级玛丽了,有刺激有又技巧,通关真的很难,救下小公主还被抓走了,唉,心累,最后还是硬着头皮继续闯,终于要通关了,之后再玩还是没有那么容易,哈哈,不知道现在能不能通关,今天就来实现一下,制作一个简易版的超级玛丽游戏

如果你正在学习Python并且缺少项目练习可以试试我这100个Python实战源码练习点击 领取呀!


1.需求分析

具备功能
  1. 播放与停止背景音乐
  2. 随机生成管道与导弹障碍
  3. 显示积分
  4. 跳跃躲避障碍
  5. 碰撞障碍

2.游戏功能结构

玛丽冒险的功能结构主要分为三类,分别为音效、主窗体以及随机出现的障碍物。如下图:


3.游戏业务流程

根据该游戏的需求分析以及功能结构


4.游戏预览

在这里插入图片描述


5.开发必备

游戏开发运行环境
  1. python3.7 以上
  2. 开发工具 PyCharm
  3. Python 内置模块:itertools、random
  4. 第三方模块:pygame
文件夹组织结构
玛丽冒险游戏的文件夹组织结构主要分为: audio(保存音效文件)和 image (保存图片)

在这里插入图片描述


6.玛丽冒险游戏实现

6.1游戏窗体的实现
在实现游戏窗体时,首先需要定义窗体的宽度与高度,然后通过 ygame 模块中的 init0 方法,实现初始化功能,接下来需要创建循环,在循环中通过 pdate0 函数不断更新窗体,最后需要判断用户是否单击了关闭窗体的按钮,如果单击了“关闭”按钮,将关闭窗体,否则继续循环显示窗体

通过 pygame 模块实现玛丽主窗体具体步骤如下

1.创建文件夹,一个保存音频,一个图片,创建 marie.py 文件
2.导入 pygame 库与 pygame 中的常用库,然后定义窗体宽度与高度

import pygame
from pygame.locals import *
import sys

# 设置游戏窗口的宽度和高度
SCREENWIDTH = 822
SCREENHEIGHT = 199
# 设置游戏帧率
FPS = 60
创建 mainGame0方法,在该方法中首先进行 pygame 的初始化工作,然后创建时间对象用于更新窗体中的画面,再创建窗体实例并设置窗体的标题文字,最后通过循环实现窗体的显示与刷新。
def mainGame():
    score = 0
    over = False
    global SCREEN, FPSCLOCK
    # 初始化pygame库
    pygame.init()
    # 初始化时钟对象
    FPSCLOCK = pygame.time.Clock()
    # 创建窗口对象
    SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
    # 设置窗口标题
    pygame.display.set_caption("玛丽冒险")

    while True:
        # 处理游戏事件
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        # 更新窗口内容
        pygame.display.update()

        # 控制帧率
        FPSCLOCK.tick(FPS)

if __name__ == "__main__":
    mainGame()
6.2地图加载

创建一个名称为 MyMap 的滚动地图类,然后在该类的初始化方法中加载背景图片和定义 X 与 Y 的坐标
class MyMap():
    def __init__(self, x, y):
        self.bg = pygame.image.load("image/bg.png").convert_alpha()
        self.x = x
        self.y = y
在 MyMap 类中创建 map _rolling0 方法,在该方法中根据地图背景图片的 X 坐标判断是否移出窗体,如果移出就给图片设置一个新的坐标点,否则按照每次 5 个像素的跨度向左移动
 def map_rolling(self):
        if self.x < -790:
            self.x = 800
        else:
            self.x -= 5
在 MyMap 类中创建 map update0 方法,在该方法中实现地图无限滚动的效果
 def map_update(self):
        SCREEN.blit(self.bg,(self.x,self.y))
在 mainGame0 方法中,设置标题文字代码的下面创建两个背景图片的对象
 bg1 = MyMap(0,0)
    bg2 = MyMap(800,0)
在 mainGame0 方法的循环中,实现无限循环滚动的地图
  if over == False:
                bg1.map_update()
                bg1.map_rolling()
                bg2.map_update()
                bg2.map_rolling()
6.3玛丽的跳跃功能
在实现玛丽的跳跃功能时,首先需要指定玛丽的固定坐标,也就是默认显示在地图上的固定位置,然后判断是否按下了键盘中的(空格)键,如果按下了就开启玛丽的跳跃开关,让玛丽以 5 个像素的距离向上移动。当玛丽到达窗体顶部的边缘时,再让玛丽以 5 个像素的距离向下移动,回到地面后关闭跳跃的开关。玛丽跳跃功能的业务流程如图

导入选代工具,创建一个名称为 Marie 的玛丽类,然后在该类的初始化方法中,首先定义玛丽跳跃时所需要的变量,然后加载玛丽跑动的三张图片,最后加载玛丽跳跃时的音效并设置玛丽默认显示的坐标位置
from itertools import cycle

# 玛丽类
class Marie():
    def __init__(self):
        # 初始化角色矩形对象
        self.rect = pygame.Rect(0, 0, 0, 0)
        # 角色跳跃状态,默认为False
        self.jumpState = False
        # 角色跳跃高度
        self.jumpHeight = 130
        # 角色最低y坐标
        self.lowest_y = 140
        # 角色已经跳跃的高度
        self.jumpValue = 0

        # 角色动作图片索引
        self.marieIndex = 0
        # 产生循环的角色动作图片索引值生成器
        self.marieIndexGen = cycle([0, 1, 2])

        # 角色动作图片元组
        self.adventure_img = (
            pygame.image.load("image/adventure1.png").convert_alpha(),
            pygame.image.load("image/adventure2.png").convert_alpha(),
            pygame.image.load("image/adventure3.png").convert_alpha(),
        )

        # 角色跳跃音频
        self.jump_audio = pygame.mixer.Sound("audio/jump.wav")
        # 设置角色矩形对象的大小为第一张动作图片的大小
        self.rect.size = self.adventure_img[0].get_size()

        # 角色初始位置
        self.x = 50
        self.y = self.lowest_y
        self.rect.topleft = (self.x, self.y)
在 Marie 类中创建 move 方法,在该方法中判断如果玛丽的跳跃开关开启时,再判断玛丽是否在地面上,如果满足这两个条件玛丽就以 5 个像素的距离向上移动。当玛丽到达窗体顶部时以 5 个像素的距离向下移动,当玛丽回到地面后关闭跳跃开关
# 玛丽移动
    def move(self):
        if self.jumpState:
            # 如果角色的y坐标大于等于最低y坐标,设置跳跃值为-5
            if self.rect.y >= self.lowest_y:
                self.jumpValue = -5

            # 如果角色的y坐标小于等于最低y坐标减去跳跃高度,设置跳跃值为5
            if self.rect.y <= self.lowest_y - self.jumpHeight:
                self.jumpValue = 5

            # 修改角色的y坐标
            self.rect.y += self.jumpValue

            # 如果角色的y坐标大于等于最低y坐标,设置跳跃状态为False
            if self.rect.y >= self.lowest_y:
                self.jumpState = False
在 Marie 类中创建 draw marie0 方法,在该方法中首先匹配玛丽跑步的动图,然后进行玛丽的绘
 #绘制玛丽
    def draw_marie(self):
        marieIndex = next(self.marieIndexGen)
        SCREEN.blit(self.adventure_img[marieIndex],(self.x,self.rect.y))
在 mainGame()方法中,创建地图对象的代码下面创建玛丽对象
marie = Marie()
在 mainGame0 方法的 while 循环中,判断关闭窗体的下面判断是否按下了键盘中的 space>(空格)键,如果按下了就开启玛丽跳跃开关并播放跳跃音效
if event.type == KEYDOWN and event.key == K_SPACE:
    # 如果玛丽的y坐标大于等于最低y坐标,播放跳跃音频,调用跳跃方法
    if marie.rect.y >= marie.lowest_y:
        marie.jump_audio.play()
        marie.jump()
在 mainGame0 方法中,绘制地图的代码下面实现玛丽的移动与绘制功能
  marie.move()
                marie.draw_marie()
6.4随机出现障碍
在实现障碍物的出现时,首先需要考虑到障碍物的大小以及障碍物不能相同,如果每次出现的障碍物都是相同的那么该游戏将失去了游戏的乐趣。所以需要加载两个大小不同的障碍物图片,然后随机抽选并显示,还需要通过计算来设置出现一个障碍并将障碍物显示在窗体当中的时间间隔

在这里插入图片描述

导入随机数,创建一个名称为 Obstacle 的障碍物类,在该类中定义一个分数,然后在初始化方法中加载障碍物图片、分数图片以及加分音效。创建 0 至 1 的随机数字,根据该数字抽选障碍物是管道还是飞行的导弹,最后根据图片的宽、高创建障碍物矩形的大小并设置障碍物的绘制坐标
class Obstacle():
    score = 1  # 初始化分数变量为1
    move = 5  # 设置移动速度为5
    obstacle_y = 150  # 设置障碍物的y坐标为150

    def __init__(self):
        self.rect = pygame.Rect(0,0,0,0)  # 创建用于碰撞检测的矩形对象
        self.missile = pygame.image.load("image/missile.png").convert_alpha()  # 加载导弹图片
        self.pipe = pygame.image.load("image/pipe.png").convert_alpha()  # 加载管道图片
        self.numbers = (  # 加载数字图片
            pygame.image.load("image/0.png").convert_alpha(),
            pygame.image.load("image/1.png").convert_alpha(),
            pygame.image.load("image/2.png").convert_alpha(),
            pygame.image.load("image/3.png").convert_alpha(),
            pygame.image.load("image/4.png").convert_alpha(),
            pygame.image.load("image/5.png").convert_alpha(),
            pygame.image.load("image/6.png").convert_alpha(),
            pygame.image.load("image/7.png").convert_alpha(),
            pygame.image.load("image/8.png").convert_alpha(),
            pygame.image.load("image/9.png").convert_alpha(),
        )

        self.score_audio = pygame.mixer.Sound("audio/score.wav")  # 加载得分音效

        r = random.randint(0,1)  # 生成随机数0或1

        if r == 0:
            # 如果随机数为0,设置障碍物为导弹,移动速度为15,y坐标为100
            self.image = self.missile
            self.move = 15
            self.obstacle_y = 100
        else:
            # 如果随机数为1,设置障碍物为管道
            self.image = self.pipe

        # 设置障碍物的大小和位置
        self.rect.size = self.image.get_size()
        self.width, self.height = self.rect.size
        self.x = 800  # 设置障碍物的初始位置为屏幕右侧
        self.y = self.obstacle_y
        self.rect.center = (self.x ,self.y)
在 Obstacle 类中首先创建 obstacle move0 方法,用于实现障碍物的移动,然后创建 drawobstacle()方法用于实现绘制障碍物
  #障碍物移动
    def obstacle_move(self):
        self.rect.x -= self.move
 #绘制障碍物
    def draw_obstacle(self):
        SCREEN.blit(self.image,(self.rect.x, self.rect.y))

在 mainGame()方法中,创建定义添加障碍物的时间与障碍物对象列表(玛丽对象的代码下面)

   addObstackeTimer = 0
    list = []
在 mainGame()方法中绘制计算障碍物出现的间隔时间(玛丽对象的代码下面)
if addObstackeTimer >= 100:  # 如果生成障碍物的计时器达到100
    r = random.randint(0, 50)  # 生成一个0到50之间的随机数
    if r > 15:  # 如果随机数大于15
        obstacle = Obstacle()  # 创建一个障碍物对象
        list.append(obstacle)  # 将障碍物对象添加到列表中
addObstackeTimer = 0  # 重置生成障碍物的计时器为0
在 mainGame0 方法中计算循环遍历障碍物并进行障碍物的绘制(障碍物间隔时间代码的下面)
 for i in range(len(list)):
                list[i].obstacle_move()
                list[i].draw_obstacle()
在 mainGame0 方法中更新整个窗体代码的上面,增加障碍物时间
addObstackeTimer += 10   
6.5背景音乐的播放与停止
创建 Music Button 类,在该类中首先初始化背景音乐的音效文件与按钮图片,然后创建 isselect0 方法用于判断鼠标是否在按钮范围内
# 背景音乐按钮
class Music_Button():
    is_open = True  # 背景音乐是否开启的状态标志

    def __init__(self):
        # 加载开启和关闭按钮的图像资源
        self.open_img = pygame.image.load("image/btn_open.png").convert_alpha()
        self.close_img = pygame.image.load("image/btn_close.png").convert_alpha()
        # 加载背景音乐的音频文件
        self.bg_music = pygame.mixer.Sound("audio/bg_music.wav")

    def is_select(self):
        # 获取鼠标的位置
        point_x, point_y = pygame.mouse.get_pos()
        # 获取开启按钮图像的宽度和高度
        w, h = self.open_img.get_size()

        # 判断鼠标是否在按钮范围内
        in_x = point_x > 20 and point_x < 20 + w
        in_y = point_y > 20 and point_y < 20 + h

        return in_x and in_y
mainGame 方法中障碍物对象列表代码的下面,创建背景音乐按钮对象,然后设置按钮默认图片,最后循环播放背景音乐。
  muscic_button = Music_Button()
    btu_img = muscic_button.open_img
    muscic_button.bg_music.play(-1)
在 mainGame0 方法的 while 循环中,获取单击事件代码的下面实现单击按钮控制背景音乐的播放与停止功能
if event.type == pygame.MOUSEBUTTONUP:
    # 判断是否为鼠标按键抬起事件
    if muscic_button.is_select():
        # 判断鼠标是否在背景音乐按钮范围内
        if muscic_button.is_open:
            # 如果背景音乐当前是开启状态
            btu_img = muscic_button.close_img
            muscic_button.is_open = False
            muscic_button.bg_music.stop()
        else:
            # 如果背景音乐当前是关闭状态
            btu_img = muscic_button.open_img
            muscic_button.is_open = True
            muscic_button.bg_music.play(-1)
在 mainGame()方法中添加障碍物时间代码的下面,绘制背景音乐按钮
SCREEN.blit(btu_img, (20, 20))   
6.6碰撞与积分功能实现
在实现碰撞与积分时,首先需要判断玛丽与障碍物的两个矩形图片是否发生了碰撞,如果发生了碰撞就证明该游戏已经结束,否则判断玛丽是否跃过了障碍物,确认越过后进行加分操作并将分数显示在窗体顶部右侧的位置。

在 Obstacle 类中,draw obstacle0 方法的下面创建 getScore0 方法用于获取分数并播放加分音效,然后创建 showScore() 方法用于在窗体顶部右侧的位置显示分数
def getSocre(self):
    """
    获取分数并重置分数为0
    """
    # 获取当前的分数
    tmp = self.score
    # 如果分数为1,播放分数音效
    if tmp == 1:
        self.score_audio.play()
    # 将分数重置为0
    self.score = 0
    # 返回原来的分数
    return tmp

# 显示分数
def showScore(self, score):
    """
    在游戏界面上显示分数
    """
    # 将分数转换为一个数字列表
    self.scoreDigits = [int(x) for x in list(str(score))]
    # 计算所有数字图像的总宽度
    totalWidth = 0
    for digit in self.scoreDigits:
        totalWidth += self.numbers[digit].get_width()

    # 计算数字图像的起始横坐标
    Xoffset = (SCREENWIDTH - (totalWidth + 30))

    # 遍历分数的每个数字,将对应的数字图像绘制到屏幕上
    for digit in self.scoreDigits:
        # 绘制数字图像到屏幕上,并更新Xoffset的值
        SCREEN.blit(self.numbers[digit], (Xoffset, SCREENHEIGHT * 0.1))
        Xoffset += self.numbers[digit].get_width()
在 mainGame()方法的上面最外层创建 game over()方法,在该方法中首先需要加载与播放撞击的音效,然后获取窗体的宽度与高度,最后加载游戏结束的图片并将该图片显示在窗体的中间位置
def game_over():
    # 播放碰撞音效
    bump_audio = pygame.mixer.Sound("audio/bump.wav")
    bump_audio.play()

    # 获取屏幕的宽度和高度
    screen_w = pygame.display.Info().current_w
    screen_h = pygame.display.Info().current_h

    # 加载游戏结束图片
    over_img = pygame.image.load("image/gameover.png").convert_alpha()

    # 在屏幕上绘制游戏结束图片,位置居中显示在屏幕中央
    SCREEN.blit(over_img, ((screen_w - over_img.get_width()) / 2, (screen_h - over_img.get_height()) / 2))
在 mainGame()方法中,绘制障碍物代码的下面判断玛丽与障碍物是否发生碰撞,如果发生了碰撞则开启游戏结束的开关,并调用游戏结束的方法显示游戏结束的图片,否则判断玛丽是否跃过了障碍物,越过就进行分数的增加并显示当前得分
if pygame.sprite.collide_rect(marie, list[i]):
    # 玛丽与物品发生碰撞
    over = True  # 游戏结束标志设为True
    game_over()  # 显示游戏结束画面
    music_button.bg_music.stop()  # 停止播放背景音乐
else:
    if (list[i].rect.x + list[i].rect.width) < marie.rect.x:
        # 物品已完全移出玛丽的右侧,计入分数
        score += list[i].getSocre()
list[i].showScore(score)
为了实现游戏结束后再次按下键盘上的(空格)键时,重新启动游戏。所以需要在 mainGame0 方法中开启玛丽跳的状态代码的下面判断游戏结束的开关是否开启,如果开启将重新调用 mainGame0)方法重新启动游戏
if over == True:
 mainGame()

图片

总结

  • 最后希望你编程学习上不急不躁,按照计划有条不紊推进,把任何一件事做到极致,都是不容易的,加油,努力!相信自己!

文末福利

  • 最后这里免费分享给大家一份Python全套学习资料,希望能帮到那些不满现状,想提升自己却又没有方向的朋友,也可以和我一起来学习交流呀。

包含编程资料、学习路线图、源代码、软件安装包等!【[点击这里]】领取!

  • ① Python所有方向的学习路线图,清楚各个方向要学什么东西
  • ② 100多节Python课程视频,涵盖必备基础、爬虫和数据分析
  • ③ 100多个Python实战案例,学习不再是只会理论
  • ④ 华为出品独家Python漫画教程,手机也能学习

可以扫描下方二维码领取【保证100%免费

在这里插入图片描述

标签:障碍物,游戏,Python,self,玛丽,超级玛丽,窗体,pygame,image
From: https://blog.csdn.net/m0_75067840/article/details/141952865

相关文章

  • 使用python读取excel数据(详解教程)
    使用Python读取Excel数据通常可以通过pandas库来实现。pandas提供了强大的数据处理功能,并且支持多种数据格式,包括Excel。下面是详细的代码讲解:目录1.安装必要的库2.读取Excel文件3.代码讲解1.导入库:2.指定文件路径和工作表名称:3.读取Excel文件:4.打印数据:......
  • python语言基础(七)--多进程多线程
    多进程,多线程1、多任务概述多个任务同时执行目的节约资源,充分利用CPU资源,提高效率表现形式并发:针对于单核CPU来讲的,如果有多个任务同时请求执行,但是同一瞬间CPU只能执行1个(任务),于是就安排它们交替执行.因为时间间隔非常短(CPU执行速度太快......
  • Python全网最全基础课程笔记(五)——选择结构+Python新特性Match
    本专栏系列为Pythong基础系列,每篇内容非常全面,包含全网各个知识点,非常长,请耐心看完。每天都会更新新的内容,搜罗全网资源以及自己在学习和工作过程中的一些总结,可以说是非常详细和全面。以至于为什么要写的这么详细:自己也是学过Python的,很多新手只是简单的过一篇语法,其实对......
  • Python量化交易股票投资,是百战百胜的吗
    Python股票接口实现查询账户,提交订单,自动交易(1)Python股票程序交易接口查账,提交订单,自动交易(2)炒股真有百战百胜之法?在充满变数的股票市场中,许多投资者都梦寐以求一种能够百战百胜的炒股方法。现实真的如此理想吗?K线图的奥秘K线图的构成与意义K线图由开盘价、收盘价......
  • 计算机毕业设计推荐-基于python的老年人健康检测管理系统【python-爬虫-大数据定制】
    精彩专栏推荐订阅:在下方专栏......
  • 游戏引擎中的物理学 - 线性运动
    文章目录前言1.物理实体粒子刚体软体2.物理术语位移(Displacement)速度(Velocity)加速度(Acceleration)力(Force)质量(Mass)动量(Momentum)3.牛顿运动定律牛顿第一定律惯性摩擦力与阻尼牛顿第二定律牛顿第三定律数值积分显式欧拉法隐式欧拉法半隐式欧拉法维莱特(Verlet)积分法龙格-库塔(Runge-......
  • [Python手撕]两个升序数组的中位数
    classSolution:deffindMedianSortedArrays(self,nums1:List[int],nums2:List[int])->float:nums1_len=len(nums1)nums2_len=len(nums2)deffind(nums1,nums2,k):#time.sleep(1)ifnotnums1:......
  • Python爬虫案例: 跨境电商shopee虾皮指定商品评论采集
    前置:今天分享一个入门级爬虫案例:跨境电商平台虾皮的指定商品评论的采集,对于新手做爬虫练习是一个很不错的选择。如果你是电商工作者也可以利用它节省你宝贵的时间首先安装好要用的py库,requests用于发送请求,pandas用于做数据处理pipinstallrequestspipinstallpandas......
  • Python正则表达式
    常用方法re.compile(pattern):编译正则表达式模式,返回一个模式对象,用于匹配操作。提高匹配效率,适用于多次匹配的情况。match():从字符串开头开始匹配,只有在字符串的开头匹配成功时,才返回匹配对象。常用于验证字符串是否符合某种模式。search():在字符串中搜索第一个匹配的......
  • python中正则模块
    importre#1.findall()匹配字符串中所有符合正则的字符串,并返回一个列表result_list=re.findall(r"\d+","我的手机号是13812345678,我的QQ号是456789123")print(result_list,type(result_list))#['13812345678','456789123']<class'list&#......