PyGame游戏编程

news2024/12/28 4:14:31
  • Python非常受欢迎的一个原因是它的应用领域非常广泛,其中就包括游戏开发。而是用Python进行游戏开发的首选模块就是PyGame。

1. 初识Pygame

  • PyGame是跨平台Python模块,专为电子游戏设计,包含图像、声音等,创建在SDL(Simple DirectMedia Layer)基础上,允许实时电子游戏研发而不会被低级语言,如C语言或是更低级的汇编语言束缚。基于这样一个设想,所有需要的游戏功能和理念(主要是图像方面)都完全简化为游戏逻辑本身,所有的资源结构都可以由高级语言(如Python)提供。

1. 安装Pygame

  • PyGame的官方网址是www.pygame.org。在该网址中可以查看PyGame的相关文档。PyGame的安装命令很简单:
pip install pygame
  • 检查模块是否安装成功:
import pygame
pygame.ver
  • 运行结果如下:
    在这里插入图片描述

2. Pygame常用模块

  • Pygame做游戏开发的优势在于不需要过多地考虑底层相关的内容,可以把工作中心放在游戏逻辑上。例如,PyGame中集成了很多和底层相关的模块,如访问显示设备、管理事件、使用字体等。
  • Pygame常用模块如下:
模块名功能
pygame.cdrom访问光驱。
pygame.cursors加载光标。
pygame.display访问显示设备。
pygame.draw绘制形状、线和点。
pygame.event管理事件。
pygame.font使用字体。
pygame.image加载和存储图片。
pygame.joystick使用游戏手柄或类似的东西。
pygame.key读取键盘按键。
pygame.mixer声音。
pygame.mouse鼠标。
pygame.movie播放视频。
pygame.music播放音乐。
pygame.overlay访问高级视频叠加。
pygame.rect管理矩形区域。
pygame.sndarray操作声音数据。
pygame.sprite操作移动图像。
pygame.surface管理图像和屏幕。
pygame.surfarray管理点阵图像数据。
pygame.time管理时间和帧信息。
pygame.transform缩放和移动图像。
  • 使用Pygame的display模块和event模块创建一个PyGame窗口,代码如下:
# -*- coding: utf-8 -*-
import sys         # 导入sys模块
import pygame       # 导入pygame模块


pygame.init()        # 初始化pygame
size = width, height = 320, 240     # 设置窗口尺寸
screen = pygame.display.set_mode(size)    # 显示窗口

# 执行死循环,确保窗口一直显示
while True:
    # 检查事件
    for event in pygame.event.get():    # 遍历所有事件
        if event.type == pygame.QUIT:     # 如果单击关闭窗口,则退出
            sys.exit()
pygame.quit()       # 退出pygame
  • 运行结果如下:
    在这里插入图片描述

2. 制作一个跳跃的小球游戏(Pygame基本使用)

  • 创建一个游戏窗口,然后在窗口内创建一个小球。以一定速度移动小球,当小球碰到游戏窗口的边缘时,小球弹回,继续移动。
    (1)创建一个游戏窗口,宽高设置640*480:
import sys    # 导入sys模块
import pygame    # 导入pygame模块

pygame.init()     # 初始化pygame
size = width,height=640,480     # 设置窗口
screen = pygame.display.set_mode(size)     # 显示窗口
  • 上述代码中,首先导入pygame模块,然后调用init()方法初始化pygame模块。接下来设置窗口的宽和高,最后使用display模块显示窗体。
  • display模块的常用方法:
方法名功能
pygame.display.init初始化display模块。
pygame.display.quit结束display模块。
pygame.display.get_init如果display模块已经被初始化,则返回True。
pygame.display.set_mode初始化一个准备显示的界面。
pygame.display.get_surface获取当前的Surface对象。
pygame.display.flip更新整个待显示的Surface对象到屏幕上。
pygame.display.update更新部分内容显示到屏幕上,如果没有参数则与flip功能相同。
(2)运行上述代码,会出现一个一闪而过的黑色窗口,这是因为程序执行完成后会自动关闭。如果让窗口一直显示,需要使用while True让程序一直执行,此外,还需要设置关闭按钮。代码具体如下:
# -*-coding:utf-8 -*-
import sys    # 导入sys模块
import pygame   # 导入pygame模块

pygame.init()     # 初始化pygame
size = width, height = 640, 480    # 设置窗口
screen = pygame.display.set_mode(size)   # 显示窗口

# 执行死循环,确保窗口一直显示
while True:
    # 检查事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:   # 如果单击关闭窗口,则退出
            sys.exit()
pygame.quit()     # 退出pygame
  • 上述代码中,添加了轮询事件检测。pygame.event.get()能够获取事件队列,使用for…in遍历事件,然后根据type属性判断事件类型。这里的事件处理方式与GUI类似,如event.type等于pygame.GUIT表示检测到关闭pygame窗口事件,pygame.KEYDOWN表示键盘按下事件pygame.MOUSEBUTTONDOWN表示鼠标按下事件等。
    (3)在窗口中添加小球。我们先准备好一张ball.png图片,然后加载该图片,最后将图片显示在窗口中:
# #######################1. 窗口一闪而过
# import sys    # 导入sys模块
# import pygame    # 导入pygame模块
#
# pygame.init()     # 初始化pygame
# size = width,height=640,480     # 设置窗口
# screen = pygame.display.set_mode(size)     # 显示窗口

# ##############################2. 窗口持续
# # -*-coding:utf-8 -*-
# import sys    # 导入sys模块
# import pygame   # 导入pygame模块
#
# pygame.init()     # 初始化pygame
# size = width, height = 640, 480    # 设置窗口
# screen = pygame.display.set_mode(size)   # 显示窗口
#
# # 执行死循环,确保窗口一直显示
# while True:
#     # 检查事件
#     for event in pygame.event.get():
#         if event.type == pygame.QUIT:   # 如果单击关闭窗口,则退出
#             sys.exit()
# pygame.quit()     # 退出pygame

# ######################3. 添加ball的窗口
# -*-coding:utf-8 -*-
import sys    # 导入sys模块
import pygame   # 导入pygame模块

pygame.init()     # 初始化pygame
size = width, height = 640, 480   # 设置窗口
screen  = pygame.display.set_mode(size)   # 显示窗口
color = (0, 0, 0)   # 设置颜色

ball = pygame.image.load("ball.png")    # 加载图片
ballrect = ball.get_rect()    # 获取矩形区域

# 执行死循环,确保窗口一直显示
while True:
    # 检查事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:    # 如果点击关闭窗口,则退出
            sys.exit()
        screen.fill(color)    # 填充颜色
        screen.blit(ball, ballrect)    # 将图片画到窗口上
        pygame.display.flip()    # 更新全部显示
pygame.quit()       # 退出pygame
  • 上述代码使用image模块的load()方法加载图片,返回值ball是一个Surface对象。Surface是用来代表图片的pygame对象,可以对一个Surface对象进行涂画、变形、复制等各种操作。事实上,屏幕也只是一个surface,pygame.display.set_mode就返回一个屏幕Surface对象。如果将ball这个Surface对象画到screen.Surface对象,需要使用blit()方法,最后使用display模块的flip方法更新整个待显示的Surface对象到屏幕上。
  • 运行结果如下:
    在这里插入图片描述
  • Surface对象的常用方法如下:
方法名功能
pygame.Surface.blit将一个图像画到另一个图像上。
pygame.Surface.convert转换图像的像素格式。
pygame.Surface.convert_alpha转换图像的像素格式,包含alpha通道的转换。
pygame.Surface.fill使用颜色填充Surface
pygame.Surface.get_rect获取Surface的矩形区域。

(4)下面该让小球动起来了。ball.get_rect()方法返回值ballrect()方法返回值ballrect是一个Rect对象,该对象有一个move()方法可用于移动矩形。move(x,y)函数有两个参数,第一个参数是X轴移动的距离,第二个参数是Y轴移动的距离。窗体左上角坐标为(0,0),例如move(100,50)。

  • 为实现小球不停地移动,将move()函数添加到while循环内:
# -*- coding:utf-8-*-
import sys
import pygame

pygame.init()      # 初始化pygame
size = width, height = 640, 480    # 设置窗口
screen = pygame.display.set_mode(size)    # 显示窗口
color = (0, 0, 0)    # 设置颜色

ball = pygame.image.load("ball.png")    # 加载图片
ballrect = ball.get_rect()       # 获取矩形区域

speed = [5, 5]     # 设置移动的X轴、Y轴距离
# 执行死循环,确保窗口一直显示
while True:
    # 检查事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:    # 如果单击关闭窗口,则退出
            sys.exit()
    ballrect = ballrect.move(speed)    # 移动小球
    screen.fill(color)    # 填充颜色
    screen.blit(ball, ballrect)     # 将图片画到窗口上
    pygame.display.flip()      # 更新全部显示
pygame.quit()     # 退出pygame

在这里插入图片描述

  • 运行上述代码,小球在屏幕中一闪而过,此时,小球并没有真正消失,而是移动到窗体外了,此时需要添加碰撞检测的功能。当小球与窗体的任一边缘发生碰撞,则改变小球的移动方向:
# -*- coding:utf-8 -*-
import sys    # 导入sys模块
import pygame     # 导入pygame模块

pygame.init()      # 初始化pygame
size = width, height = 640, 480    # 设置窗口
screen = pygame.display.set_mode(size)     # 显示窗口
color = (0, 0, 0)     # 设置窗口背景颜色

ball = pygame.image.load("ball.png")    # 加载图片
ballrect = ball.get_rect()    # 获取矩形区域

speed = [1, 1]      # 设置移动的X轴、Y轴距离
# 执行死循环,确保窗口一直显示
while True:
    # 检查事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:     # 如果单击关闭窗口,则退出
            sys.exit()
    ballrect = ballrect.move(speed)     # 移动小球
    # 碰到左右边缘
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    # 碰到上下边缘
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]
    screen.fill(color)      # 填充颜色
    screen.blit(ball, ballrect)     # 将图片画到窗口上
    pygame.display.flip()     # 更新全部显示

pygame.quit()     # 退出pygame
  • 上述代码中,添加了碰撞检测功能。如果球碰到左右边缘,则更改X轴数据为负数;如果碰到上下边缘,则改Y轴数据为负数。
  • 运行结果如下:
    在这里插入图片描述
    (6)运行上述代码发现好像有多个小球在飞快移动,这是因为运行上述代码的时间非常短,导致肉眼错觉,因此需要添加一个“时钟”来控制程序运行时间。用pygame的time模块控制。使用pygame时钟前,必须先创建一个Clock对象的一个实例,然后在while循环中设置多长时间运行一次。代码如下:
# -*- coding:utf-8 -*-
import sys    # 导入sys模块
import pygame    # 导入pygame模块

pygame.init()     # 初始化pygame
size = width, height = 640, 480    # 设置窗口
screen = pygame.display.set_mode(size)    # 显示窗口
color = (0, 0, 0)    # 设置颜色

ball = pygame.image.load("ball.png")    # 加载图片
ballrect = ball.get_rect()   # 获取矩形区域

speed = [5, 5]     # 设置移动的X轴、Y轴距离
clock = pygame.time.Clock()     # 设置时钟
# 执行死循环,确保窗口一直显示
while True:
    clock.tick(60)    # 每秒执行60次
    # 检查事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:     # 如果单击关闭窗口,则退出
            sys.exit()
    ballrect = ballrect.move(speed)    # 移动小球
    # 碰到左右边缘
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    # 碰到上下边缘
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]
    screen.fill(color)     # 填充颜色
    screen.blit(ball, ballrect)     # 将图片画到窗口上
    screen.blit(ball, ballrect)     # 将图片画到窗口上
    pygame.display.flip()    # 更新全部显示
pygame.quit()      # 退出pygame
  • 至此,就完成了跳跃的小球游戏。
  • 运行效果如下:
    在这里插入图片描述

3. 开发Flappy Bird游戏

  • 游戏的素材可以从该网站上找自己喜欢的:https://www.aigei.com/s?tab=file&type=2d&q=flappy+bird&page=3#resContainer
  • 也可以使用我下载的:
    在这里插入图片描述

1. 游戏简介

  • Flappy Bird是一款鸟类飞行游戏,由越南河内独立游戏开发者阮哈东(DongNguyen)开发。在Flappy Bird这款游戏中,玩家只需要用一根手指来操控,单击触摸手机屏幕,小鸟就会往上飞,不断地单击就会不断地往高处飞。放松手指,则会快速下降。所以玩家要控制小鸟一直向前飞行,然后注意躲避途中高低不平的管子。如果小鸟碰到了障碍物,游戏就会结束。每当小鸟飞过一组管道,玩家就会获得一分。

2. 游戏分析

  • 在Flappy Bird中,主要有两个对象:小鸟和管道。可以创建Bird类和Pineline类来分别表示这两个对象。小鸟可以通过上下移动来躲避管道,所以在Bird类中创建一个birdUpdate()方法,实现小鸟的上下移动。为了体现小鸟向前飞行的特征,可以让管道一直向左侧移动,这样在窗口中就好像小鸟在向前飞行。所以,在Pineline类中也创建了一个updatePipline()方法,实现管道的向左移动。此外,还创建了3个函数:createMap()函数用于绘制地图;checkDead()函数用于判断小鸟的生命状态;getResult()函数用于获取最终分数。最后在主逻辑中实例化类并调用相关方法,实现相应功能。

3. 搭建主框架

  • 通过前面分析,我们可以搭建起Flappy Bird游戏的主框架。Flappy Bird游戏有两个对象:小鸟和管道。先来创建这两个类,类中的具体方法可以先使用pass语句替代。然后创建一个绘制地图的函数createMap()。最后,在主逻辑中绘制背景图片。关键代码如下:
import pygame
import sys
import random


class Bird(object):
    """定义一个鸟类"""
    def __init__(self):
        """定义初始化方法"""
        pass

    def birdUpdate(self):
        pass


class Pipeline(object):
    """定义一个管道类"""
    def __init__(self):
        """定义初始化方法"""
        pass

    def updatePipeline(self):
        """水平移动"""
        pass


def createMap(screen, background):
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))     # 填充颜色
    screen.blit(background, (0, 0))    # 填入到背景
    pygame.display.update()    # 更新显示


if __name__ == "__main__":
    """主程序"""
    pygame.init()     # 初始化pygame
    size = width, height = 400, 720    # 设置窗口
    screen = pygame.display.set_mode(size)    # 显示窗口
    clock = pygame.time.Clock()    # 设置时钟
    Pipeline = Pipeline()     # 实例化管道类
    Bird = Bird()    # 实例化鸟类
    while True:
        clock.tick(60)     # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
        background = pygame.image.load("assets/background.png")     # 加载背景图片
        createMap(screen, background)    # 绘制地图
    pygame.quit()    # 退出

  • 运行结果如下:
    在这里插入图片描述

4. 创建小鸟类

  • 下面创建小鸟类。该类需要初始化很多参数,所以定义一个__init__()方法,用来初始化各种参数,包括鸟飞行的几种状态、飞行的速度、跳跃的高度等。然后定义birdUpdate()方法,该方法用于实现小鸟的跳跃和坠落。接下来,在主逻辑的轮询事件中添加键盘按下事件或鼠标单击事件,如按下鼠标,使小鸟上升等。最后,在createMap()方法中显示小鸟的图像。
    请添加图片描述
    请添加图片描述
    请添加图片描述
import pygame
import sys
import random
# 素材参考地址:https://www.aigei.com/s?q=flappy+bird&type=2d


class Bird(object):
    """定义一个鸟类"""
    def __init__(self):
        """定义初始化方法"""
        self.birdRect = pygame.Rect(65, 50, 50, 50)    # 鸟的矩形
        # 定义鸟的3种状态列表
        self.birdStatus = [pygame.image.load("assets/1.png"),
                           pygame.image.load("assets/2.png"),
                           pygame.image.load("assets/dead.png")]
        self.status = 0   # 默认飞行状态
        self.birdX = 120   # 鸟所在X轴坐标
        self.birdY = 350    # 鸟所在Y轴坐标,即上下飞行高度
        self.jump = False      # 默认情况小鸟自动降落
        self.jumpSpeed = 10    # 跳跃高度
        self.gravity = 5    # 重力
        self.dead = False     # 默认小鸟生命状态为活着

    def birdUpdate(self):
        if self.jump:
            # 小鸟跳跃
            self.jumpSpeed -= 1    # 速度递减,上升越来越慢
            self.birdY -= self.jumpSpeed    # 鸟Y轴坐标减小,小鸟上升
        else:
            # 小鸟坠落
            self.gravity += 0.2     # 重力递增,下降越来越快
            self.birdY += self.gravity      # 鸟Y轴坐标增加,小鸟下降
        self.birdRect[1] = self.birdY    # 更改Y轴位置


class Pipeline(object):
    """定义一个管道类"""
    def __init__(self):
        """定义初始化方法"""
        pass

    def updatePipeline(self):
        """水平移动"""
        pass


def createMap(screen, background):
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))     # 填充颜色
    screen.blit(background, (0, 0))    # 填入到背景
    # 显示小鸟
    if Bird.dead:     # 撞管道状态
        Bird.status = 2
    elif Bird.jump:    # 起飞状态
        Bird.status = 1
    screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX, Bird.birdY))    # 设置小鸟的坐标
    Bird.birdUpdate()     # 鸟移动
    pygame.display.update()    # 更新显示


if __name__ == "__main__":
    """主程序"""
    pygame.init()     # 初始化pygame
    size = width, height = 400, 720    # 设置窗口
    screen = pygame.display.set_mode(size)    # 显示窗口
    clock = pygame.time.Clock()    # 设置时钟
    Pipeline = Pipeline()     # 实例化管道类
    Bird = Bird()    # 实例化鸟类
    while True:
        clock.tick(60)     # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
                Bird.jump = True     # 跳跃
                Bird.gravity = 5    # 重力
                Bird.jumpSpeed = 10     # 跳跃速度
        background = pygame.image.load("assets/background.png")     # 加载背景图片
        createMap(screen, background)    # 绘制地图
    pygame.quit()    # 退出


  • 上述代码在Bird类中设置了birdStatus属性,该属性是一个鸟类图片的列表,列表中显示鸟类的3种飞行状态,根据小鸟的不同状态加载相应的图片。在birdUpdate()方法中,为了达到较好的动画效果,使用jumpSpeed和gravity两个属性逐渐变化。运行上述代码,在窗体内创建一只鸟,默认情况下小鸟会一直下降。当单击一下鼠标或按一下键盘,小鸟会跳跃一下,高度上升。运行效果如下图:

在这里插入图片描述

5. 创建管道类

  • 创建完鸟类之后,我们来创建管道类。同样,在_init_()方法中初始化各种参数,包括设置管道的坐标,加载上下管道图片等。然后在updatePipline()方法中,定义管道向左移动的速度,并且当管道移出屏幕时重新绘制下一组管道。最后,在createMap()函数中显示管道。关键代码如下:
import pygame
import sys
import random
# 素材参考地址:https://www.aigei.com/s?q=flappy+bird&type=2d


class Bird(object):
    """定义一个鸟类"""
    def __init__(self):
        """定义初始化方法"""
        self.birdRect = pygame.Rect(65, 50, 50, 50)    # 鸟的矩形
        # 定义鸟的3种状态列表
        self.birdStatus = [pygame.image.load("assets/1.png"),
                           pygame.image.load("assets/2.png"),
                           pygame.image.load("assets/dead.png")]
        self.status = 0   # 默认飞行状态
        self.birdX = 120   # 鸟所在X轴坐标
        self.birdY = 350    # 鸟所在Y轴坐标,即上下飞行高度
        self.jump = False      # 默认情况小鸟自动降落
        self.jumpSpeed = 10    # 跳跃高度
        self.gravity = 5    # 重力
        self.dead = False     # 默认小鸟生命状态为活着

    def birdUpdate(self):
        if self.jump:
            # 小鸟跳跃
            self.jumpSpeed -= 1    # 速度递减,上升越来越慢
            self.birdY -= self.jumpSpeed    # 鸟Y轴坐标减小,小鸟上升
        else:
            # 小鸟坠落
            self.gravity += 0.2     # 重力递增,下降越来越快
            self.birdY += self.gravity      # 鸟Y轴坐标增加,小鸟下降
        self.birdRect[1] = self.birdY    # 更改Y轴位置


class Pipeline(object):
    """定义一个管道类"""
    def __init__(self):
        """定义初始化方法"""
        self.wallx = 400      # 管道所在X轴坐标
        self.pineUp = pygame.image.load("assets/top.png")     # 加载上管道图片
        self.pineDown = pygame.image.load("assets/bottom.png")     # 加载下管道图片

    def updatePipeline(self):
        """管道水平移动方法"""
        self.wallx -= 5      # 管道X轴坐标递减,即管道向左移动
        # 当管道运行到一定位置,即小鸟飞越管道,分数加1,并且管道重置
        if self.wallx < -80:
            self.wallx = 400


def createMap(screen, background):
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))     # 填充颜色
    screen.blit(background, (0, 0))    # 填入到背景

    # 显示管道
    screen.blit(Pipeline.pineUp, (Pipeline.wallx, -300))     # 上管道坐标位置(X,Y)
    screen.blit(Pipeline.pineDown, (Pipeline.wallx, 500))    # 下管道坐标位置(X,Y)
    Pipeline.updatePipeline()      # 管道移动

    # 显示小鸟
    if Bird.dead:     # 撞管道状态
        Bird.status = 2
    elif Bird.jump:    # 起飞状态
        Bird.status = 1
    screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX, Bird.birdY))    # 设置小鸟的坐标
    Bird.birdUpdate()     # 鸟移动

    pygame.display.update()    # 更新显示


if __name__ == "__main__":
    """主程序"""
    pygame.init()     # 初始化pygame
    size = width, height = 400, 720    # 设置窗口
    screen = pygame.display.set_mode(size)    # 显示窗口
    clock = pygame.time.Clock()    # 设置时钟
    Pipeline = Pipeline()     # 实例化管道类
    Bird = Bird()    # 实例化鸟类
    while True:
        clock.tick(60)     # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
                Bird.jump = True     # 跳跃
                Bird.gravity = 5    # 重力
                Bird.jumpSpeed = 10     # 跳跃速度
        background = pygame.image.load("assets/background.png")     # 加载背景图片
        createMap(screen, background)    # 绘制地图
    pygame.quit()    # 退出

  • 上述代码中,在createMap()函数中,设置先显示管道,再显示小鸟。这样做的目的是,当小鸟与管道图像重合的时候,小鸟的图像显示在上层,而管道的图像显示在底层。运行结果如下:
    请添加图片描述

6. 计算得分

  • 当小鸟飞过管道时,玩家得分加1.这里对于飞过管道的逻辑做了简化处理:当管道移动到窗体左侧一定距离后,默认小鸟飞过管道,使分数加1,并显示在屏幕上。在updatePipeline()方法中实现该功能。代码如下:
import pygame
import sys
import random
# 素材参考地址:https://www.aigei.com/s?q=flappy+bird&type=2d




class Bird(object):
    """定义一个鸟类"""
    def __init__(self):
        """定义初始化方法"""
        self.birdRect = pygame.Rect(65, 50, 50, 50)    # 鸟的矩形
        # 定义鸟的3种状态列表
        self.birdStatus = [pygame.image.load("assets/1.png"),
                           pygame.image.load("assets/2.png"),
                           pygame.image.load("assets/dead.png")]
        self.status = 0   # 默认飞行状态
        self.birdX = 120   # 鸟所在X轴坐标
        self.birdY = 350    # 鸟所在Y轴坐标,即上下飞行高度
        self.jump = False      # 默认情况小鸟自动降落
        self.jumpSpeed = 10    # 跳跃高度
        self.gravity = 5    # 重力
        self.dead = False     # 默认小鸟生命状态为活着

    def birdUpdate(self):
        if self.jump:
            # 小鸟跳跃
            self.jumpSpeed -= 1    # 速度递减,上升越来越慢
            self.birdY -= self.jumpSpeed    # 鸟Y轴坐标减小,小鸟上升
        else:
            # 小鸟坠落
            self.gravity += 0.2     # 重力递增,下降越来越快
            self.birdY += self.gravity      # 鸟Y轴坐标增加,小鸟下降
        self.birdRect[1] = self.birdY    # 更改Y轴位置


class Pipeline(object):
    """定义一个管道类"""
    def __init__(self):
        """定义初始化方法"""
        self.wallx = 400      # 管道所在X轴坐标
        self.pineUp = pygame.image.load("assets/top.png")     # 加载上管道图片
        self.pineDown = pygame.image.load("assets/bottom.png")     # 加载下管道图片

    def updatePipeline(self):
        """管道水平移动方法"""
        self.wallx -= 5      # 管道X轴坐标递减,即管道向左移动
        # 当管道运行到一定位置,即小鸟飞越管道,分数加1,并且管道重置
        if self.wallx < -80:
            global score
            score += 1
            self.wallx = 400


def createMap(screen, background, font):
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))     # 填充颜色
    screen.blit(background, (0, 0))    # 填入到背景

    # 显示管道
    screen.blit(Pipeline.pineUp, (Pipeline.wallx, -100))     # 上管道坐标位置(X,Y)
    screen.blit(Pipeline.pineDown, (Pipeline.wallx, 500))    # 下管道坐标位置(X,Y)
    Pipeline.updatePipeline()      # 管道移动

    # 显示小鸟
    if Bird.dead:     # 撞管道状态
        Bird.status = 2
    elif Bird.jump:    # 起飞状态
        Bird.status = 1
    screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX, Bird.birdY))    # 设置小鸟的坐标
    Bird.birdUpdate()     # 鸟移动

    # 显示分数
    screen.blit(font.render("score: " + str(score), -1, (255, 255, 255)), (230, 20))    # 设置颜色及坐标位置

    pygame.display.update()    # 更新显示


if __name__ == "__main__":
    """主程序"""
    pygame.init()     # 初始化pygame
    pygame.font.init()    # 初始化字体
    font = pygame.font.SysFont(None, 50)    # 设置默认字体和大小
    size = width, height = 400, 680    # 设置窗口
    screen = pygame.display.set_mode(size)    # 显示窗口
    clock = pygame.time.Clock()    # 设置时钟
    Pipeline = Pipeline()     # 实例化管道类
    Bird = Bird()    # 实例化鸟类
    score = 0    # 初始化分数
    while True:
        clock.tick(60)     # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
                Bird.jump = True     # 跳跃
                Bird.gravity = 5    # 重力
                Bird.jumpSpeed = 10     # 跳跃速度
        background = pygame.image.load("assets/background.png")     # 加载背景图片
        createMap(screen, background, font)    # 绘制地图
    pygame.quit()    # 退出

  • 运行效果如下:
    请添加图片描述

7. 碰撞检测

  • 当小鸟与管道相碰撞时,小鸟颜色变为灰色,游戏结束,并且显示总分数。在checkDead()函数中通过pygame.Rect()可以分别获取小鸟的矩形区域对象和管道的矩形区域对象,该对象有一个colliderect()方法可以判断俩各个矩形区域是否相碰撞。如果相碰撞,设置Bird.dead属性为True。此外,当小鸟飞出窗体时,也设置Bird.dead属性为True。最后,用两行文字显示总成绩。关键代码如下:
import pygame
import sys
import random
# 素材参考地址:https://www.aigei.com/s?q=flappy+bird&type=2d


class Bird(object):
    """定义一个鸟类"""
    def __init__(self):
        """定义初始化方法"""
        self.birdRect = pygame.Rect(65, 50, 50, 50)    # 鸟的矩形
        # 定义鸟的3种状态列表
        self.birdStatus = [pygame.image.load("assets/1.png"),
                           pygame.image.load("assets/2.png"),
                           pygame.image.load("assets/dead.png")]
        self.status = 0   # 默认飞行状态
        self.birdX = 120   # 鸟所在X轴坐标
        self.birdY = 350    # 鸟所在Y轴坐标,即上下飞行高度
        self.jump = False      # 默认情况小鸟自动降落
        self.jumpSpeed = 10    # 跳跃高度
        self.gravity = 5    # 重力
        self.dead = False     # 默认小鸟生命状态为活着

    def birdUpdate(self):
        if self.jump:
            # 小鸟跳跃
            self.jumpSpeed -= 1    # 速度递减,上升越来越慢
            self.birdY -= self.jumpSpeed    # 鸟Y轴坐标减小,小鸟上升
        else:
            # 小鸟坠落
            self.gravity += 0.2     # 重力递增,下降越来越快
            self.birdY += self.gravity      # 鸟Y轴坐标增加,小鸟下降
        self.birdRect[1] = self.birdY    # 更改Y轴位置


class Pipeline(object):
    """定义一个管道类"""
    def __init__(self):
        """定义初始化方法"""
        self.wallx = 400      # 管道所在X轴坐标
        self.pineUp = pygame.image.load("assets/top.png")     # 加载上管道图片
        self.pineDown = pygame.image.load("assets/bottom.png")     # 加载下管道图片

    def updatePipeline(self):
        """管道水平移动方法"""
        self.wallx -= 5      # 管道X轴坐标递减,即管道向左移动
        # 当管道运行到一定位置,即小鸟飞越管道,分数加1,并且管道重置
        if self.wallx < -80:
            global score
            score += 1
            self.wallx = 400


def createMap(screen, background, font):
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))     # 填充颜色
    screen.blit(background, (0, 0))    # 填入到背景

    # 显示管道
    screen.blit(Pipeline.pineUp, (Pipeline.wallx, -100))     # 上管道坐标位置(X,Y)
    screen.blit(Pipeline.pineDown, (Pipeline.wallx, 500))    # 下管道坐标位置(X,Y)
    Pipeline.updatePipeline()      # 管道移动

    # 显示小鸟
    if Bird.dead:     # 撞管道状态
        Bird.status = 2
    elif Bird.jump:    # 起飞状态
        Bird.status = 1
    screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX, Bird.birdY))    # 设置小鸟的坐标
    Bird.birdUpdate()     # 鸟移动

    # 显示分数
    screen.blit(font.render("score: " + str(score), -1, (255, 255, 255)), (230, 20))    # 设置颜色及坐标位置

    pygame.display.update()    # 更新显示


def checkDead():
    # 上方管子的矩形位置
    upRect = pygame.Rect(Pipeline.wallx, -100,Pipeline.pineUp.get_width() - 10, Pipeline.pineUp.get_height())
    # 下方管子的矩形位置
    downRect = pygame.Rect(Pipeline.wallx, 500, Pipeline.pineDown.get_width() - 10, Pipeline.pineDown.get_height())
    # 检测小鸟与上下方管子是否碰撞
    if upRect.colliderect(Bird.birdRect) or downRect.colliderect(Bird.birdRect):
        Bird.dead = True
        return True
    else:
        return False


def getResult():
    final_text1 = "Game over"
    final_text2 = "Your final score is: " + str(score)
    ft1_font = pygame.font.SysFont("Arial", 70)      # 设置第一行文字字体
    ft1_surf = ft1_font.render(final_text1, 1, (242, 3, 36))     # 设置第一行文字的颜色
    ft2_font = pygame.font.SysFont("Arial", 50)     # 设置第二行文字字体
    ft2_surf = ft2_font.render(final_text2, 1, (253, 177, 6))    # 设置第二行文字颜色
    # 设置第一行文字显示位置
    screen.blit(ft1_surf, [screen.get_width() / 2 - ft1_surf.get_width() / 2, 100])
    # 设置第二行文字显示位置
    screen.blit(ft2_surf, [screen.get_width() / 2 - ft2_surf.get_width() / 2, 200])

    pygame.display.flip()    # 更新整个待显示的Surface对象到屏幕上


if __name__ == "__main__":
    """主程序"""
    pygame.init()     # 初始化pygame
    pygame.font.init()    # 初始化字体
    font = pygame.font.SysFont(None, 50)    # 设置默认字体和大小
    size = width, height = 400, 680    # 设置窗口
    screen = pygame.display.set_mode(size)    # 显示窗口
    clock = pygame.time.Clock()    # 设置时钟
    Pipeline = Pipeline()     # 实例化管道类
    Bird = Bird()    # 实例化鸟类
    score = 0    # 初始化分数
    while True:
        clock.tick(60)     # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
                Bird.jump = True     # 跳跃
                Bird.gravity = 5    # 重力
                Bird.jumpSpeed = 10     # 跳跃速度
        background = pygame.image.load("assets/background.png")     # 加载背景图片
        if checkDead():   # 检测小鸟生命状态
            getResult()     # 如果小鸟死亡,游戏结束,显示游戏总分数
        else:
            createMap(screen, background, font)    # 绘制地图
    pygame.quit()    # 退出

  • 上述代码的checkDead()方法中,upRect.colliderect(Bird.birdRect)用于检测小鸟的矩形区域是否与上管道的矩形区域相撞,colliderect()函数的参数是另一个矩形区域对象。碰撞后小鸟死亡的情况如下图:

在这里插入图片描述

  • 本实例已经实现了Flappy Bird的基本功能,但还有很多需要完善的地方,如设置游戏的难度,包括设置管道的高度、小鸟的飞行速度等。

4. 小结

  • 主要讲解了如何使用Pygame开发游戏。首先通过一个跳跃的小球游戏来了解Pygame的基本使用方法,然后利用Python逐步开发一个知名游戏Flappy Bird。通过本章的学习,可以掌握Pygame的基础知识,并使用Python面向对象的思维方式开发一个Python小游戏,进一步体会Python编程的乐趣。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

量子前沿 | 单光子,为什么是量子科技的“源头”?

光子盒研究院出品 前言&#xff1a;基础研究是科技创新的基石。鉴于此&#xff0c;光子盒增设“量子前沿”全新栏目&#xff0c;旨在介绍量子科技的一系列基础技术、相关进展及现状前景。 我们对量子信息的兴趣出现在20世纪90年代和21世纪。在该领域的发展过程中&#xff0c;单…

文件上传与PDF报表入门

文件上传与PDF报表入门 理解DataURL的基本使用&#xff0c;实现DataURL的文件上传完成基于七牛云的文件上传 理解 JasperReport生命周期 独立完成 JasperReport的入门案例 图片上传 需求分析 如图所示&#xff0c;实现员工照片上传功能 Data URL DataURL概述 所谓DataURL是指&q…

chatgpt赋能python:Python定义未知长度数组

Python定义未知长度数组 Python是一种受欢迎的编程语言&#xff0c;广泛用于数据分析&#xff0c;人工智能&#xff0c;WEB开发和其他领域。其中一个非常方便的特性是它提供了定义未知长度数组的选项。 在本文中&#xff0c;我们将介绍如何使用Python定义未知长度数组&#x…

四、纹理显示图片

第一部分纹理基础 1)基础概念 在 OpenGLES 开发中&#xff0c;纹理除了用于装饰物体表面&#xff0c;还可以用来作为存储数据的容器。 纹理映射&#xff1a;纹理映射就是通过为图元的顶点坐标指定恰当的纹理坐标&#xff0c;通过纹理坐标在纹理图中选定特定的纹理区域&#…

汽车电子AUTOSAR之Event

上文AUTOSAR基础篇之DTC中提到event是故障监控的基本单元&#xff0c;本文将从event的使能条件&#xff08;Enable Condition&#xff09;、上报方式、去抖动策略&#xff08;Debouncing Strategy&#xff09;、优先级&#xff08;Priority&#xff09;、Displacement、依赖关系…

解决SpringBoot配置文件项目重启出现乱码的情况

近日&#xff0c;在创建了SpringBoot项目后往配置文件中写了相关的系统配置&#xff0c;并且在上面加了中文注释&#xff0c;但是在重启项目或开机重启后遇到了注释乱码的情况&#xff0c;查询了各种相关资料&#xff0c;得以解决 发现问题 首先看到我在这个application.prope…

Golang每日一练(leetDay0089) 滑动窗口最大值、中位数

目录 239. 滑动窗口最大值 Sliding Window Maximum &#x1f31f;&#x1f31f;&#x1f31f; 480. 滑动窗口中位数 Sliding Window Median &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专…

chatgpt赋能python:Python安装FBProphet:绝佳的时间序列预测工具

Python安装FBProphet&#xff1a;绝佳的时间序列预测工具 随着时间序列数据应用场景的不断增加&#xff0c;越来越多的数据科学家和工程师开始使用FBProphet进行时间序列预测。FBProphet是由Facebook开发的一种开源预测工具&#xff0c;它使用先进的统计方法进行时间序列分析&…

案例40:基于Springboot疫苗预约系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Day_41顺序查找与折半查找

目录 一. 顺序查找和折半查找的实现 1. 顺序查找 1.1 一般线性表的顺序查找 1.2 有序表的顺序查找 2. 折半查找 二. 代码实现 1. 内部节点 2. 类的构造函数 3. 顺序查找 4. 折半查找 三. 代码展示 四. 数据测试 五. 小结 一. 顺序查找和折半查找的实现 1. 顺序查找…

chatgpt赋能python:Python定义错误:什么是Python定义错误

Python定义错误&#xff1a;什么是Python定义错误 Python是一种强大的编程语言&#xff0c;被广泛用于各种领域&#xff0c;例如Web开发&#xff0c;数据分析&#xff0c;机器学习等。然而&#xff0c;即使是最有经验的Python开发人员也会犯一些常见的错误&#xff0c;其中之一…

在线教育机构的视频如何做防下载和防盗录?

在线教育平台付费课程、企业内训的培训课程&#xff0c;这类视频课程内容是如何做防下载和防盗录的&#xff1f; 1.AI隐形溯源水印 这个功能能够将水印隐藏在视频中&#xff0c;不会影响观看体验&#xff0c;但却能够帮助企业很好的视频版权保护。更重要的是&#xff0c;对于盗…

【ArcGIS Pro二次开发】(34):从字符串中提取中文、英文、数字与特殊符号

这是一个基于字段计算的工具。 有时候我们会遇到一些混杂着各种中文、英文、数字、特殊符号的文字&#xff0c;这个工具的目的是从这些复杂文字中提取出想要的特定文字。 比如说从CAD测绘图中可以读取到类似【混3】、【砖2】的文字&#xff0c;如果想要从中提取出层数或结构&…

chatgpt赋能python:Python宏变量——简介

Python宏变量——简介 Python是一种高级编程语言&#xff0c;具有易学易用、简洁清晰等优点。但我们在编写代码的时候&#xff0c;有时需要用到常量或者宏定义&#xff0c;这就需要用到宏变量。在Python中&#xff0c;宏变量是一种常见的编程方法&#xff0c;本文将详细介绍Py…

chatgpt赋能python:Python安装后怎么使用?

Python安装后怎么使用&#xff1f; Python是一种高级编程语言&#xff0c;被广泛用于Web开发、数据分析、人工智能和自动化等领域。下面我们将介绍安装Python后如何使用它。 步骤1 - 安装Python 首先&#xff0c;从官方网站下载并安装Python。在安装过程中&#xff0c;您可以…

chatgpt赋能python:Python中的构造方法是什么?

Python中的构造方法是什么&#xff1f; 当你开始学习 Python 编程时&#xff0c;你可能经常听到 “构造方法” 这个词。那么&#xff0c;什么是构造方法&#xff1f;为什么它在 Python 中很重要&#xff1f;本文将为您揭示构造方法的概念以及它们在 Python 中的作用。 什么是…

案例36:基于Springboot药店管理系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

chatgpt赋能python:Python程序员必知的Geany配置技巧

Python程序员必知的Geany配置技巧 如果你是一名Python程序员&#xff0c;并且正在寻找一个简单易用的代码编辑器&#xff0c;那么Geany是一个非常不错的选择。Geany是一款轻量级的集成开发环境&#xff08;IDE&#xff09;&#xff0c;除了Python&#xff0c;还支持许多其他编…

chatgpt赋能python:Python安装完后如何打开

Python安装完后如何打开 Python是一种高级的、解释性、交互式的编程语言&#xff0c;已经成为了广泛的编程应用领域中不可或缺的一部分&#xff0c;如网络编程、数据科学和人工智能等。Python的安装对于学习、开发和应用Python技术非常重要&#xff0c;但安装了Python后如何打…

案例38:基于Springboot电影评论网站开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…