目录
摘要
在数字娱乐时代,小游戏因其简单、直观且易于上手的特点,深受广大玩家的喜爱。其中,飞机大战游戏作为一种经典的游戏类型,凭借其紧张刺激的战斗场景和多样的游戏元素,一直深受玩家们的喜爱。为了满足这一市场需求,决定设计一款基于pygame的飞机大战小游戏。
Python作为一种高级编程语言,具有简洁、易读、可扩展性强等特点,被广泛应用于各个领域。近年来,随着游戏开发技术的不断发展,Python在游戏开发领域的应用也日益广泛。pygame作为Python的一个开源游戏开发库,为开发者提供了丰富的游戏开发工具和资源,使得开发者能够更加便捷地开发出高质量的游戏。
本研究的目的是通过开发一款基于pygame的飞机大战小游戏,进一步探索Python在游戏开发领域的应用。同时,本研究的意义在于为其他开发者提供一种简单、易行的游戏开发方法,推动Python在游戏开发领域的发展。
本研究的主要内容是开发一款基于pygame的飞机大战小游戏。具体研究内容包括:游戏设计、游戏实现、游戏测试与优化等。本研究采用的方法包括文献综述、案例分析、实践操作等。首先,通过文献综述了解游戏开发的基本原理和pygame库的使用方法;其次,通过案例分析学习经典的游戏设计模式;最后,通过实践操作完成游戏的开发。
本研究的目标是开发出一款简单、易玩、具有挑战性的飞机大战小游戏。具体目标包括:实现基本的游戏场景、飞机和敌机的基本移动和射击功能、分数统计和生命值管理功能等。预期成果包括:实现上述功能的完整游戏代码、一份详细的开发文档、以及针对游戏的测试报告和优化建议。
本研究使用的是Windows11操作系统,Python版本为3.9。开发工具选择的是PyCharm,版本为2021.2.1。
(1)游戏设计:确定游戏的基本规则、界面设计、音效等。这包括定义游戏的玩法、目标、难度设置,以及创建游戏的视觉和音频效果。
(2)编程:编写游戏的核心逻辑,包括飞机移动、射击、敌机生成、碰撞检测等。这是实现游戏功能的关键步骤,需要处理游戏中的各种逻辑和物理计算。
(3)图形和音效:制作游戏所需的图像和音效,如飞机、子弹、敌机、爆炸声等。这需要设计和制作游戏的视觉效果以及音效,使游戏更具吸引力。
(4)测试:确保游戏的稳定性和可玩性。这包括检查游戏是否存在漏洞、错误或性能问题,以及测试游戏的平衡性和难度设置。
(5)优化:调整游戏性能,提高游戏的流畅度。这可能包括优化代码、减少加载时间、提高渲染效率等。
(6)用户界面设计:设计易于使用的界面,使玩家能够轻松控制游戏。这包括按钮的位置、大小和颜色,以及任何其他用户界面元素的设计。
(1)飞机移动:玩家可以通过键盘或触摸屏控制飞机在屏幕上左右移动,躲避敌机的攻击。
(2)射击功能:玩家可以发射子弹,射击敌机,击中敌机后可以获得分数。
敌机生成和移动:敌机在屏幕上随机生成,并向玩家的飞机移动,增加了游戏的挑战性和趣味性。
(3)碰撞检测:当飞机与敌机或子弹碰撞时,游戏结束或得分增加,确保了游戏的公平性和可玩性。
(4)得分和生命值显示:游戏实时显示玩家的得分和生命值,使玩家能够了解自己的游戏进度和当前状态。
(5)音效和视觉效果:游戏具有音效和视觉效果,如射击音效、爆炸效果等,增加了游戏的吸引力和沉浸感。
??(1)爆炸效果:当子弹接触到敌机时,增加爆炸效果,使游戏更加生动和刺激。
??(2)Boss 敌机:增加 Boss 敌机,这些敌机具有更高的生命值和攻击力,使游戏更具挑战性。同时,显示 Boss 敌机的血量,让玩家更好地了解战斗状况。
??(3)敌机发射子弹:对于一部分敌机,增加敌机发射子弹的功能,增加游戏的复杂性和策略性。
??(4)道具敌机:增加道具敌机,这些敌机在被击杀后会掉落道具,玩家可以收集这些道具来获得特殊能力或增益效果。
??(5)背景音乐和击杀音乐:增加游戏的背景音乐和击杀敌机时的音效,提升游戏的沉浸感和娱乐性。
??(6)游戏难度:根据玩家的技能水平,调整敌机的数量、速度和攻击频率,以提供更具挑战性的游戏体验。
??(7)游戏模式:添加新的游戏模式,例如限时模式、生存模式或合作模式等,提供多样化的玩法。
??(8)社交功能:集成社交功能,允许玩家与好友对战或合作完成任务,增加游戏的互动性和竞技性。
??(9)游戏成就:设立游戏成就系统,激励玩家完成特定任务或挑战,增加游戏的目标和挑战性。
Pygame库:Pygame是一个用于制作视频游戏的Python库。它可以用来创建飞机大战小游戏的图形和音效,并且具有广泛的使用和社区支持。.
Unity引擎:Unity是一个流行的游戏开发引擎,可以用来创建飞机大战小游戏的3D效果和复杂的游戏机制。Unity提供了丰富的资源、工具和文档,可以帮助开发者快速构建游戏。
游戏设计教程和文档:可以参考在线游戏设计教程和文档,以获取关于飞机大战小游戏游戏机制、界面设计、音效等方面的指导。这些资源可以帮助开发者了解游戏设计的最佳实践和理论。
基于pygame的飞机大战小游戏是一个经典的游戏,玩家需要控制一架飞机在屏幕上移动,并射击敌机。下面是一个简单的基于pygame的飞机大战小游戏的概述:
(1)游戏初始化:
导入pygame库和其他必要的模块。设置游戏窗口大小、标题和其他选项。加载所需的图像、音效和字体文件。
(2)游戏主循环:
初始化游戏状态、时钟和精灵组等。进入游戏主循环,处理游戏事件(如键盘按键、鼠标点击等)。
(3)游戏逻辑:
玩家控制:根据玩家的输入,控制飞机的移动。
射击:检测玩家的射击按键,发射子弹并击中敌机。
敌机生成和移动:在屏幕上随机生成敌机,并向玩家的飞机移动。
碰撞检测:检测飞机与敌机或子弹的碰撞,处理游戏结束或得分增加。
(4)游戏渲染:
绘制游戏背景、飞机、子弹、敌机等精灵,更新游戏界面,包括得分、生命值等显示元素。
(5)游戏音效和视觉效果:
加载并播放背景音乐和音效,使用适当的颜色和动画效果,增加游戏的吸引力和沉浸感
(6)游戏优化和改进:
根据玩家反馈和测试结果,优化游戏性能、提高渲染效率、调整难度,添加新的游戏功能和元素,如道具、特殊效果等,以增加游戏的可玩性和挑战性。
1.对项目结构进行截图并描述。
图1 项目结构
描述:
2.每个代码文件代码内容进行概述?
脚本名称 | 实现逻辑概述 | 备注 |
hero.py | 控制玩家英雄的移动、射击、跳跃等动作 | 飞机可能有不同的动作 |
bullet.py | 处理子弹的生成、移动和销毁 | 子弹移动并可能击中敌人 |
setting.py | 设置游戏的基本参数和配置 | 游戏窗口的大小、音效的开关 |
enemy.py | 控制敌人的生成、移动和销毁 | 敌人从某个位置生成,向玩家移动 |
supply.py | 处理游戏中的补给品或其他增益效果 | 玩家收集补给以增强能力 |
main.py | 游戏的主入口,整合上述所有模块的功能 | 从上述模块中调用必要的功能 |
3.对项目的输入输出进行描述。
启动项:启动游戏窗口,展示游戏的主界面和初始状态
键盘输入:玩家通过键盘上的按键进行操作,如W、A、S、D控制英雄的移动
输出:
游戏界面:显示游戏的主界面,包括玩家的英雄、敌人和子弹等元素的位置和状态。
音效和背景音乐:根据游戏事件播放音效和背景音乐。
分数和生命值显示:实时显示玩家的分数和生命值,以便玩家了解游戏状态。
4.对项目里关键的属性(变量)通过表格展示出来,并标注其含义:
属性 | 含义 | 备注 |
hero | 玩家英雄对象 | 控制英雄的移动、射击等动作 |
bullet | 子弹对象 | 表示玩家的射击行为 |
setting | 游戏设置对象 | 包含游戏的基本参数和配置 |
enemy | 敌人对象 | 控制敌人的生成、移动和销毁 |
supply | 游戏补给品对象 | 表示游戏中可收集的增益效果或资源 |
main | 游戏主程序对象 | 整合所有模块的功能,驱动游戏的进行 |
(1)书本知识涉及有:
(2)新知识涉及有:?
??pygame库:首先,你需要熟悉pygame库的基本使用。pygame是一个用于制作2D游戏的Python库,它提供了丰富的图像、声音、事件处理等功能,可以帮助你快速构建游戏。
1.问题:pygame库安装失败。
解决过程:首先,确保Python和pip已经正确安装。然后,使用pip install pygame命令尝试安装。如果仍然失败,可以考虑使用虚拟环境,或者检查网络连接和代理设置。
2. 问题:加载的图像显示不正常。
解决过程:首先,检查图像文件路径是否正确。其次,确保图像文件的格式是pygame支持的。如果图像仍然显示不正常,可以尝试使用图像编辑软件打开并重新保存图像文件,或者调整pygame的图像加载参数。
3. 问题:音效和背景音乐无法播放。
解决过程:首先,检查音效和音乐文件的路径是否正确。其次,确保文件的格式是pygame支持的。如果仍然无法播放,可以尝试使用不同的音频文件,或者调整pygame的音频设置。
图2 运行结果
描述:
(1)游戏开始时,玩家将看到一个简单的菜单界面
(2)玩家需要控制飞机移动并射击敌机,同时躲避敌机的攻击。
(3)游戏界面下方将显示玩家生命值。当玩家击中敌机时,分数将增加;当玩家的生命值减少到零时,游戏将结束。
(4)在游戏过程中,玩家可以获得补给品,以提高战斗力。
(5)随着关卡的深入,敌机会变得更加强大,移动速度更快。玩家需要不断提升自己的技能和策略来应对挑战。
# import pygame
from settings import *
class Bullet1(pygame.sprite.Sprite):
# Bullet1继承Sprite的所有属性和方法
def __init__(self, position):
# 构造函数,初始化对象的属性
super().__init__()
# 使用super().__init__()调用父类的构造函数
self.image = pygame.image.load(FILE_PATH + "image/bullet1.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = position
self.speed = 12
self.active = True
# 将子弹的状态设置为活动状态
self.mask = pygame.mask.from_surface(self.image)
# 创建一个与图像关联的掩码,用于更精确的碰撞检测,然后存储在self.mask。
def move(self):
self.rect.top -= self.speed
if self.rect.top < 0:
self.active = False
def reset(self, position):
self.rect.left, self.rect.top = position
self.active = True
class Bullet2(pygame.sprite.Sprite):
def __init__(self, position):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/bullet2.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = position
self.speed = 14
self.active = False
self.mask = pygame.mask.from_surface(self.image)
def move(self):
self.rect.top -= self.speed
if self.rect.top < 0:
self.active = False
def reset(self, position):
self.rect.left, self.rect.top = position
self.active = True
from random import *
from settings import *
class SmallEnemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/enemy1.png").convert_alpha()
self.destroy_images = []
self.destroy_images.extend([
pygame.image.load(FILE_PATH + "image/enemy1_down1.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy1_down2.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy1_down3.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy1_down4.png").convert_alpha()
])
self.rect = self.image.get_rect()
# 获取敌人图像的矩形区域
self.speed = 2
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.top = randint(-5 * SCREEN_RECT.height, 0)
# 随机初始化敌人的位置。敌人的左边缘位置在屏幕宽度内随机选择,
# 而顶部位置则在屏幕高度的五倍范围内随机选择
self.mask = pygame.mask.from_surface(self.image)
self.check()
# 调用check方法检查敌人的位置是否需要进行调整
def move(self):
if self.rect.top < SCREEN_RECT.height:
self.rect.top += self.speed
else:
self.reset()
def reset(self):
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.top = randint(-5 * SCREEN_RECT.height, 0)
def check(self):
if self.rect.right >= SCREEN_RECT.width:
self.rect.right = SCREEN_RECT.width
class MidEnemy(pygame.sprite.Sprite):
hp = 8
# 代表敌人的生命值,并且被设置为8
def __init__(self):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/enemy2.png").convert_alpha()
self.image_hit = pygame.image.load(FILE_PATH + "image/enemy2_hit.png").convert_alpha()
self.destroy_images = []
self.destroy_images.extend([
pygame.image.load(FILE_PATH + "image/enemy2_down1.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy2_down2.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy2_down3.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy2_down4.png").convert_alpha()
])
self.rect = self.image.get_rect()
self.speed = 1
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.top = randint(-10 * SCREEN_RECT.height, -SCREEN_RECT.height)
# 随机初始化敌人的位置。敌人的左边缘位置在屏幕宽度内随机选择,
# 而顶部位置则在屏幕高度的 - 10倍到 - 1 倍范围内随机选择(允许敌人从屏幕上方开始移动)。
self.mask = pygame.mask.from_surface(self.image)
self.hit = False
# 敌人是否受到攻击
def move(self):
if self.rect.top < SCREEN_RECT.height:
self.rect.top += self.speed
else:
self.reset()
def reset(self):
self.hp = MidEnemy.hp
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.top = randint(-10 * SCREEN_RECT.height, -SCREEN_RECT.height)
class BigEnemy(pygame.sprite.Sprite):
hp = 20
def __init__(self):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/enemy3_n1.png").convert_alpha()
self.image2 = pygame.image.load(FILE_PATH + "image/enemy3_n2.png").convert_alpha()
self.image_hit = pygame.image.load(FILE_PATH + "image/enemy3_hit.png").convert_alpha()
# 加载敌人受到攻击时的图像
self.destroy_images = []
self.destroy_images.extend([
pygame.image.load(FILE_PATH + "image/enemy3_down1.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy3_down2.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy3_down3.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy3_down4.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy3_down5.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/enemy3_down6.png").convert_alpha()
])
self.rect = self.image.get_rect()
self.speed = 1
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.top = randint(-15 * SCREEN_RECT.height, -5 * SCREEN_RECT.height)
self.mask = pygame.mask.from_surface(self.image)
self.hit = False
def move(self):
if self.rect.top < SCREEN_RECT.height:
self.rect.top += self.speed
else:
self.reset()
def reset(self):
self.active = True
self.hp = BigEnemy.hp
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.top = randint(-15 * SCREEN_RECT.height, -5 * SCREEN_RECT.height)
from settings import *
class Hero(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
# 在子类中调用其父类(超类)的初始化方法
# super().__init__()来调用基类的初始化方法
self.image = pygame.image.load(FILE_PATH + "image/me1.png").convert_alpha()
self.image2 = pygame.image.load(FILE_PATH + "image/me2.png").convert_alpha()
self.destroy_images = []
self.destroy_images.extend([
pygame.image.load(FILE_PATH + "image/me_destroy_1.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/me_destroy_2.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/me_destroy_3.png").convert_alpha(),
pygame.image.load(FILE_PATH + "image/me_destroy_4.png").convert_alpha()
])
self.rect = self.image.get_rect()
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 60
# 底部保持60像素的距离
self.speed = 10
self.active = True
self.invincible = False
self.mask = pygame.mask.from_surface(self.image)
def moveUp(self):
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.rect.top = 0
def moveDown(self):
if self.rect.bottom < SCREEN_RECT.height - 60:
self.rect.top += self.speed
else:
self.rect.bottom = SCREEN_RECT.height - 60
# 向下移动主角。如果主角的底部位置小于屏幕的高度减去60,则增加其底部位置。
# 否则,将其设置为屏幕高度减去60
def moveLeft(self):
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.rect.left = 0
# 向左移动主角。如果主角的左侧位置大于0,则减少其左侧位置。否则,将其设置为0。
def moveRight(self):
if self.rect.right < SCREEN_RECT.width:
self.rect.right += self.speed
else:
self.rect.right = SCREEN_RECT.width
def reset(self):
self.active = True
self.invincible = False
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 60
# 重置主角的状态。将主角的活动状态设置为True
# 无敌状态设置为True,并重置其位置到屏幕底部中心
import pygame
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
FPS = 60
FILE_PATH = ""
import pygame
from settings import *
from random import randint
class BulletSupply(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/bullet_supply.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.bottom = -100
# 设置矩形的底部位置为 - 100,意味着它最初位于屏幕底部下方。
self.speed = 3
self.active = False
self.mask = pygame.mask.from_surface(self.image)
def move(self):
if self.rect.top < SCREEN_RECT.height:
self.rect.top += self.speed
else:
self.active = False
# 如果子弹的顶部在屏幕上(即self.rect.top < SCREEN_RECT.height),
# 则向上移动其位置,使其沿屏幕向上移动。当其到达屏幕顶部时,
# 将self.active设置为False,表示它不再活动
def reset(self):
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.bottom = -100
class BombSupply(pygame.sprite.Sprite):
# 这个类与BulletSupply类相似
def __init__(self):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/bomb_supply.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.bottom = -100
self.speed = 3
self.active = False
self.mask = pygame.mask.from_surface(self.image)
def move(self):
if self.rect.top < SCREEN_RECT.height:
self.rect.top += self.speed
else:
self.active = False
def reset(self):
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.bottom = -100
class LifeSupply(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load(FILE_PATH + "image/life_supply.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.bottom = -100
self.speed = 3
self.active = False
self.mask = pygame.mask.from_surface(self.image)
def move(self):
if self.rect.top < SCREEN_RECT.height:
self.rect.top += self.speed
else:
self.active = False
def reset(self):
self.active = True
self.rect.left = randint(0, SCREEN_RECT.width - self.rect.width)
self.rect.bottom = -100
from sys import exit
from time import sleep
from pygame.constants import USEREVENT
from bullet import *
from enemy import *
from hero import *
from supply import *
pygame.init()
class PlaneGame(object):
def __init__(self):
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# set_mode()函数:这是pygame.display模块中的一个函数,用于创建一个窗口或全屏窗口来显示内容。它接受一个元组参数,表示窗口的尺寸。
pygame.display.set_caption("飞机大战")
self.background = pygame.image.load(FILE_PATH + "image/background.png")
self.clock_ = pygame.time.Clock()
# 创建一个时钟对象,用于控制游戏的速度。
pygame.time.set_timer(self.SUPPLY_NOTICE_TIME, 30 * 1000)
# 设置一个定时器,当定时器到期时(这里是30秒后),
# 它会触发self.SUPPLY_NOTICE_TIME事件。这意味着当游戏运行30秒后,
# 可能会显示一个通知或提示玩家有关补给的消息
sleep(0.5)
pygame.time.set_timer(self.SUPPLY_TIME, 30 * 1000)
# 这里又设置了一个定时器,当游戏运行30秒后,它会触发另一个事件或效果,可能与补给品有关
self.__createEvent()
# 调用一个名为__createEvent 的方法
def startGame(self):
pygame.mixer.music.play(-1)
while True:
self.screen.blit(self.background, (0, 0))
# 在屏幕上绘制背景图像。屏幕的左上角开始
self.screen.blit(self.paused_image, self.paused_rect)
# paused_rect 定义了图像的位置。
self.__handleEvent()
# 调用一个名为__handleEvent 的方法
if self.life_num and not self.paused:
# 检查玩家的生命数量是否大于0并且游戏没有暂停。
self.clock_.tick(FPS)
# 使用pygame的时钟对象来控制游戏的速度
self.__drawEvents()
# 调用一个自定义方法来绘制或显示游戏中的事件或元素。
self.__checkCollide()
# 调用一个自定义方法来检查游戏中的碰撞事件,如子弹击中敌人
pygame.display.update()
# 更新屏幕上的所有绘制操作
if self.life_num == 0:
pygame.mixer.music.stop()
pygame.mixer.stop()
pygame.time.set_timer(self.SUPPLY_TIME, 0)
# 设置一个定时器事件,但参数设置为0意味着定时器将立即触发。
print("Game Over!")
if not self.recording:
# 检查是否已经开始记录分数或其他信息。
self.recording = True
with open("record.txt", "r") as f:
record_score = int(f.read())
if self.score > record_score:
with open("record.txt", "w") as f:
f.write(str(self.score))
exit()
screen = pygame.display.set_mode(SCREEN_RECT.size)
pygame.display.set_caption("飞机大战")
switch_image = True
# 控制图像的切换
delay = 500
# 用于定时或延迟的参数。用于控制某个动作或事件之间的时间间隔
e1_destroy_index = 0
e2_destroy_index = 0
e3_destroy_index = 0
me_destroy_index = 0
# 跟踪敌机的销毁索引
bullet1 = []
# 存储玩家发射的子弹
bullet1_index = 0
BULLET1_NUM = 4
bullet2 = []
bullet2_index = 0
BULLET2_NUM = 8
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
# 定义四种颜色。黑色是由三个0组成,绿色由0和255的绿色组成,红色由255的红色组成,白色由三个255组成。这些常量可能在游戏的图形渲染中使用。
score = 0
score_font = pygame.font.SysFont("Freestyle Script", 36)
paused = False
pause_nor = pygame.image.load(FILE_PATH + "image/pause_nor.png").convert_alpha()
pause_pressed = pygame.image.load(FILE_PATH + "image/pause_pressed.png").convert_alpha()
resume_nor = pygame.image.load(FILE_PATH + "image/resume_nor.png").convert_alpha()
resume_pressed = pygame.image.load(FILE_PATH + "image/resume_pressed.png").convert_alpha()
# 加载暂停和恢复按钮的图像
paused_rect = pause_nor.get_rect()
paused_rect.left, paused_rect.top = SCREEN_RECT.width - paused_rect.width - 10, 10
# 获取暂停按钮的矩形区域并设置其位置
paused_image = pause_nor
# 设置暂停图像的默认图像
level = 1
bomb = pygame.image.load(FILE_PATH + "image/bomb.png").convert_alpha()
bomb_rect = bomb.get_rect()
bomb_font = pygame.font.SysFont("Freestyle Script", 48)
bomb_num = 3
bomb_max = 3
bullet_supply = BulletSupply()
bomb_supply = BombSupply()
life_supply = LifeSupply()
# 用于子弹、炸弹和生命值的供应或生成
SUPPLY_TIME = USEREVENT + 1
# 供应的持续时间
SUPER_BULLET = USEREVENT + 2
# 供应子弹的持续时间
is_super_bullet = False
super_bullet_s = 18
life_num = 3
life_image = pygame.image.load(FILE_PATH + "image/life.png").convert_alpha()
life_rect = life_image.get_rect()
INVINCIBLE_TIME = USEREVENT + 3
# 无敌状态的持续时间
recording = False
# 游戏是否处于录制模式。
SUPPLY_NOTICE_TIME = USEREVENT + 4
# 供应通知的持续时间
supply_notice_font = pygame.font.SysFont("Freestyle Script", 48)
supply_notice = False
supply_notice_end = False
# 显示供应通知
pygame.mixer.init()
pygame.mixer.music.load(FILE_PATH + "sound/game_music.mp3")
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound(FILE_PATH + "sound/bullet.mp3")
bullet_sound.set_volume(0.2)
# 子弹声音
bomb_sound = pygame.mixer.Sound(FILE_PATH + "sound/use_bomb.mp3")
bomb_sound.set_volume(0.2)
# 炸弹声音
supply_sound = pygame.mixer.Sound(FILE_PATH + "sound/out_porp.mp3")
supply_sound.set_volume(0.2)
# 供应声音
get_bomb_sound = pygame.mixer.Sound(FILE_PATH + "sound/get_bomb.mp3")
get_bomb_sound.set_volume(0.2)
# 获得炸弹
get_bullet_sound = pygame.mixer.Sound(FILE_PATH + "sound/bullet.mp3")
get_bullet_sound.set_volume(0.2)
# 获得子弹
double_sound = pygame.mixer.Sound(FILE_PATH + "sound/get_double_laser.mp3")
double_sound.set_volume(0.2)
# 双子弹声音
enemy3_fly_sound = pygame.mixer.Sound(FILE_PATH + "sound/big_spaceship_flying.mp3")
enemy3_fly_sound.set_volume(0.2)
# 敌人飞行的声音
enemy1_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/enemy0_down.mp3")
enemy1_down_sound.set_volume(0.2)
enemy2_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/enemy1_down.mp3")
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/enemy2_down.mp3")
enemy3_down_sound.set_volume(0.2)
# 敌人倒下的声音
me_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/game_over.mp3")
me_down_sound.set_volume(0.2)
# 玩家倒下的声音
upgrade_sound = pygame.mixer.Sound(FILE_PATH + "sound/achievement.mp3")
upgrade_sound.set_volume(0.2)
# 游戏升级
def __createEvent(self):
self.hero = Hero()
# 在方法中创建新的Hero对象
self.hero_group = pygame.sprite.Group(self.hero)
# 创建一个玩家组,并将之前创建的英雄对象添加到这个组中
for i in range(self.BULLET1_NUM):
self.bullet1.append(Bullet1(self.hero.rect.midtop))
# del i
# 这是一个循环,用于创建BULLET1_NUM数量的第一种子弹。
# 每种子弹都是通过调用Bullet1() 类并传递英雄的顶部中心位置来创建的。
# 然后,将新创建的子弹添加到self.bullet1列表中。del i语句是多余的,
# 因为循环结束后,变量i就不再使用了
for i in range(self.BULLET2_NUM // 2):
self.bullet2.append(Bullet2((self.hero.rect.centerx - 33, self.hero.rect.centery)))
self.bullet2.append(Bullet2((self.hero.rect.centerx + 30, self.hero.rect.centery)))
# 这个循环创建了两种位置的第二种子弹,并将它们添加到self.bullet2列表中。
self.enemies = pygame.sprite.Group()
self.small_enemy_group = pygame.sprite.Group()
self.__add_small_enemy(self.small_enemy_group, self.enemies, 15)
# 调用一个静态方法,来添加15个小型敌人到之前创建的两个精灵组中。
self.mid_enemy_group = pygame.sprite.Group()
self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 4)
self.big_enemy_group = pygame.sprite.Group()
self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
@staticmethod
def __add_small_enemy(group1, group2, num):
for i in range(num):
m0 = SmallEnemy()
group1.add(m0)
group2.add(m0)
del i
# 这个静态方法接受两个精灵组和一个数字作为参数。
# 它使用一个循环来创建指定数量的小型敌人,并将这些敌人添加到两个精灵组中。
# del i是多余的,因为在循环结束后,变量i会自动被销毁
@staticmethod
def __add_mid_enemy(group1, group2, num):
for i in range(num):
m1 = MidEnemy()
group1.add(m1)
group2.add(m1)
del i
@staticmethod
def __add_big_enemy(group1, group2, num):
for i in range(num):
m2 = BigEnemy()
group1.add(m2)
group2.add(m2)
del i
@staticmethod
def __inc_speed(target, inc=1):
for i in target:
i.speed += inc
del i
# 遍历target中的所有对象,并将它们的speed属性值增加1。
def __handleEvent(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
# 如果事件类型是退出事件(即用户点击了关闭按钮)
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and self.paused_rect.collidepoint(event.pos):
# 如果按下的是鼠标左键,并且鼠标位置与暂停按钮的矩形区域相交
self.paused = not self.paused
# 切换游戏的暂停状态
if self.paused:
# 如果游戏处于暂停状态
pygame.time.set_timer(self.SUPPLY_TIME, 0)
pygame.time.set_timer(self.SUPPLY_NOTICE_TIME, 0)
# 停止所有计时器
pygame.mixer.music.pause()
pygame.mixer.pause()
# 暂停所有音乐和声效
else:
pygame.time.set_timer(self.SUPPLY_NOTICE_TIME, 30 * 1000)
sleep(0.5)
# 在0.5秒后启动供应通知计时器
pygame.time.set_timer(self.SUPPLY_TIME, 30 * 1000)
# 启动供应计时器
pygame.mixer.music.unpause()
pygame.mixer.unpause()
# 恢复所有音乐和声效
if event.type == pygame.MOUSEMOTION:
# 如果事件类型是鼠标移动事件
if self.paused_rect.collidepoint(event.pos):
# 检查鼠标的位置是否与一个特定的矩形区域(self.paused_rect)相交
if self.paused:
self.paused_image = self.resume_pressed
# 如果游戏处于暂停状态,则将self.paused_image设置为self.resume_pressed。
else:
self.paused_image = self.pause_pressed
else:
# 如果鼠标位置不在矩形区域内
if self.paused:
self.paused_image = self.resume_nor
# 如果游戏处于暂停状态,则将self.paused_image设置为self.resume_nor
else:
self.paused_image = self.pause_nor
if event.type == pygame.KEYDOWN:
# 如果事件类型是键盘按键按下事件
if event.key == pygame.K_SPACE:
# 如果按下的键是空格键
if self.bomb_num:
# 如果玩家有炸弹
self.bomb_num -= 1
# 减少玩家的炸弹数量
self.bomb_sound.play()
# 播放炸弹声效
for each in self.enemies:
if each.rect.bottom > 0:
each.active = False
# 遍历所有的敌人,如果敌人的底部在屏幕上方,则将其标记为不活动状态(可能是炸弹的效果
if event.type == self.SUPPLY_TIME:
# 如果事件类型是供应时间事件
self.supply_sound.play()
self.supply_notice_end = True
# 设置供应通知结束标志为True
self.supply_type = choice([1, 2, 3])
# 使用choice函数从列表[1, 2, 3]中随机选择一个值,
# 并将该值赋给self.supply_type。这可能代表不同类型的供应。
if self.supply_type == 1:
self.bomb_supply.reset()
# *重置`bomb_supply`,可能是恢复玩家的炸弹数量或某种与炸弹相关的供应。
elif self.supply_type == 2:
self.bullet_supply.reset()
# *重置`bullet_supply`,可能是恢复玩家的子弹数量或某种与子弹相关的供应。
else:
if self.life_num < 3:
self.life_supply.reset()
else:
if choice([True, False]):
self.bomb_supply.reset()
else:
self.bullet_supply.reset()
# *首先检查玩家的生命数(`self.life_num`)是否小于3。
# 如果是,则重置`life_supply`;
# 否则,根据一个随机选择决定是重置`bomb_supply` 还是 `bullet_supply`。
self.supply_notice = False
self.supply_notice_end = False
# 将两个标志重置为False,可能是为了准备下一次的供应通知或过程。
if event.type == self.SUPER_BULLET:
self.is_super_bullet = False
# 如果检测到的事件类型是SUPER_BULLET,代码首先将self.is_super_bullet设置为False,
pygame.time.set_timer(self.SUPER_BULLET, 0)
# 使用pygame.time.set_timer()函数重置或停止该事件的计时器。
if event.type == self.INVINCIBLE_TIME:
self.hero.invincible = False
# 无敌状态被关闭。
pygame.time.set_timer(self.INVINCIBLE_TIME, 0)
# 使用pygame.time.set_timer()函数重置或停止该事件的计时器
if event.type == self.SUPPLY_NOTICE_TIME:
self.supply_notice = True
# 供应通知被触发或显示。
if self.level == 1 and self.score >= 50:
self.level = 2
self.upgrade_sound.play()
# 播放升级音效
self.bomb_max += 2
self.__add_small_enemy(self.small_enemy_group, self.enemies, 3)
self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 2)
self.__add_big_enemy(self.big_enemy_group, self.enemies, 1)
# 在敌人组中添加3个小敌机、2个中敌机和1个大敌机
self.__inc_speed(self.small_enemy_group)
# 小敌机的速度增加1
elif self.level == 2 and self.score >= 300:
self.level = 3
self.upgrade_sound.play()
self.super_bullet_s += 2
# 超级子弹的数量增加2
self.bomb_max += 1
# 炸弹的最大数量增加1
self.__add_small_enemy(self.small_enemy_group, self.enemies, 5)
self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 3)
self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
# 向游戏中的敌人组中添加5个小敌机、3个中敌机和2个大敌机
self.__inc_speed(self.small_enemy_group)
# 小型敌机的速度 + 1
self.__inc_speed(self.mid_enemy_group)
# 中型敌机的速度 + 1
elif self.level == 3 and self.score >= 600:
self.level = 4
self.upgrade_sound.play()
self.super_bullet_s += 3
self.bomb_max += 1
self.__add_small_enemy(self.small_enemy_group, self.enemies, 5)
self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 3)
self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
# 小型敌机的速度 + 1
self.__inc_speed(self.small_enemy_group)
# 中型敌机的速度 + 1
self.__inc_speed(self.mid_enemy_group)
elif self.level == 4 and self.score >= 1000:
self.level = 5
self.upgrade_sound.play()
self.super_bullet_s += 4
self.bomb_max += 1
self.__add_small_enemy(self.small_enemy_group, self.enemies, 5)
self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 3)
self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
# 小型敌机的速度 + 1
self.__inc_speed(self.small_enemy_group)
# 中型敌机的速度 + 1
self.__inc_speed(self.mid_enemy_group)
keys_pressed = pygame.key.get_pressed()
if keys_pressed[pygame.K_w] or keys_pressed[pygame.K_UP]:
self.hero.moveUp()
if keys_pressed[pygame.K_s] or keys_pressed[pygame.K_DOWN]:
self.hero.moveDown()
if keys_pressed[pygame.K_a] or keys_pressed[pygame.K_LEFT]:
self.hero.moveLeft()
if keys_pressed[pygame.K_d] or keys_pressed[pygame.K_RIGHT]:
self.hero.moveRight()
if self.bomb_supply.active:
self.bomb_supply.move()
# 调用bomb_supply对象的move方法,更新其在屏幕上的位置。
self.screen.blit(self.bomb_supply.image, self.bomb_supply.rect)
if pygame.sprite.collide_mask(self.bomb_supply, self.hero):
# 使用Pygame的collide_mask函数检查bomb_supply和hero对象是否发生碰撞。
self.get_bomb_sound.play()
if self.bomb_num < self.bomb_max:
# 检查当前拥有的炸弹数量是否小于最大炸弹数量。
self.bomb_num += 1
# 增加当前拥有的炸弹数量
self.bomb_supply.active = False
# 将bomb_supply对象的active属性设置为False,表示该供应物已被使用或消耗。
if self.bullet_supply.active:
self.bullet_supply.move()
# 调用bullet_supply对象的move方法,更新其在屏幕上的位置。
self.screen.blit(self.bullet_supply.image, self.bullet_supply.rect)
if pygame.sprite.collide_mask(self.bullet_supply, self.hero):
# 使用Pygame的collide_mask函数检查bullet_supply和hero对象是否发生碰撞。
self.get_bullet_sound.play()
# 播放一个声音效果
pygame.time.set_timer(self.SUPER_BULLET, self.super_bullet_s * 1000)
# 设置一个定时器,当定时器触发时,它将执行与self.SUPER_BULLET相关的动作。
# 定时器的触发时间由self.super_bullet_s * 1000 决定,
# 其中self.super_bullet_s表示秒数,乘以1000是为了将其转换为毫秒。
self.is_super_bullet = True
# 将is_super_bullet属性设置为True,表示当前子弹是super。
self.bullet_supply.active = False
# 将bullet_supply对象的active属性设置为False,表示该供应物已被使用或消耗
if self.life_supply.active:
self.life_supply.move()
# 调用life_supply对象的move方法,更新其在屏幕上的位置。
self.screen.blit(self.life_supply.image, self.life_supply.rect)
if pygame.sprite.collide_mask(self.life_supply, self.hero):
# 使用Pygame的collide_mask函数检查life_supply和hero对象是否发生碰撞。
self.get_bomb_sound.play()
# 播放一个声音效果
if self.life_num < 3:
# 检查当前的生命值数量是否小于3。如果是,则执行以下代码块
self.life_num += 1
# 增加当前的生命值数量
self.life_supply.active = False
# 将life_supply对象的active属性设置为False,表示该供应物已被使用或消耗。
def __checkCollide(self):
self.enemies_down = pygame.sprite.spritecollide(self.hero, self.enemies, False, pygame.sprite.collide_mask)
# collide_mask来进行更精确的碰撞检测。
if self.enemies_down and not self.hero.invincible:
self.hero.active = False
# 将英雄的状态设置为非活动状态,英雄被击败
self.is_super_bullet = False
# 取消超级子弹的状态
for e in self.enemies_down:
e.active = False
# 将碰撞到的敌人的状态设置为非活动状态,敌人被击败
for b in self.bullets:
# 遍历所有的子弹
if b.active:
b.move()
# 调用子弹的move方法,更新子弹的位置
self.screen.blit(b.image, b.rect)
# 在屏幕上绘制子弹的图像
enemy_hit = pygame.sprite.spritecollide(b, self.enemies, False, pygame.sprite.collide_mask)
# 使用spritecollide函数检测子弹与敌人之间的碰撞。
if enemy_hit:
b.active = False
# 将子弹的状态设置为非活动状态,表示已经击中目标
for e in enemy_hit:
if e not in self.small_enemy_group:
# 如果击中的敌人不属于小型敌人组
e.hit = True
# 设置敌人的hit属性为True,表示敌人被击中
e.hp -= 1
# 减少敌人的生命值
if e.hp == 0:
e.active = False
# 将敌人的状态设置为非活动状态,表示敌人被击败
else:
e.active = False
# 直接将小型敌人的状态设置为非活动状态,表示敌人被击败。
def __drawEvents(self):
if not (self.delay % 10):
# 每10个单位的时间,这个条件只满足一次
self.bullet_sound.play()
# 播放一个子弹的声音效果。
if self.is_super_bullet:
self.bullets = self.bullet2
# 如果处于超级子弹模式,将子弹列表设置为 self.bullet2
self.bullets[self.bullet2_index].reset((self.hero.rect.centerx - 33, self.hero.rect.centery - 5))
# 将一个超级子弹重置到英雄的左侧或右侧的一个特定位置。
self.bullets[self.bullet2_index + 1].reset((self.hero.rect.centerx + 30, self.hero.rect.centery - 5))
# 重置超级子弹的位置
self.bullet2_index = (self.bullet2_index + 2) % self.BULLET2_NUM
# 更新超级子弹的索引,使其在列表中循环。
else:
self.bullets = self.bullet1
self.bullets[self.bullet1_index].reset(self.hero.rect.midtop)
# 重置普通子弹的位置。
self.bullet1_index = (self.bullet1_index + 1) % self.BULLET1_NUM
# 更新普通子弹的索引,使其在列表中循环。
for each in self.big_enemy_group:
if each.active:
# 检查每个敌人对象是否(active)。只有活跃的敌人会被处理
each.move()
# 调用每个活跃敌人的move方法,可能是更新敌人的位置或状态。
if each.hit:
# 检查敌人是否被击中
self.screen.blit(each.image_hit, each.rect)
each.hit = False
# 将敌人的hit属性设置为False,表示敌人现在不再是被击中的状态。
else:
if self.switch_image:
# 检查一个名为switch_image的属性。这个属性决定使用哪个图像来绘制敌人
self.screen.blit(each.image, each.rect)
else:
self.screen.blit(each.image2, each.rect)
# 使用敌人的另一个图像(each.image2)在其当前位置(each.rect)进行绘制
if each.hp != 20:
# 检查每个敌人的生命值(each.hp)是否等于20。
pygame.draw.line(self.screen, self.BLACK,
(each.rect.left, each.rect.top - 5),
(each.rect.right, each.rect.top - 5), 2)
# 使用 pygame的draw.line方法在屏幕上绘制一条线。
# 线的颜色是黑色(self.BLACK),从每个敌人的左边(each.rect.left)到右边(each.rect.right),
# 位置在每个敌人的顶部偏移5个像素(each.rect.top - 5)。线的宽度是2个像素。
hp_remain = each.hp / BigEnemy.hp
if hp_remain > 0.2:
hp_color = self.GREEN
else:
hp_color = self.RED
pygame.draw.line(self.screen, hp_color,
(each.rect.left, each.rect.top - 5),
(each.rect.left + each.rect.width * hp_remain, each.rect.top - 5), 2)
# 使用pygame的draw.line方法在屏幕上绘制一条线,表示敌人的生命值。
# 线的颜色是hp_color,线的起点是每个敌人的左边,终点是敌人宽度的hp_remain倍的位置,线的宽度是2个像素。
if each.rect.bottom == -50:
self.enemy3_fly_sound.play(-1)
else:
if not (self.delay % 5):
# 检查 self.delay除以5的余数是否为0。
if not self.e3_destroy_index:
# 检查self.e3_destroy_index是否为0
self.enemy3_down_sound.play()
# 播放一个声音效果,可能是敌人被击败或销毁时的声音。
self.screen.blit(each.destroy_images[self.e3_destroy_index], each.rect)
self.e3_destroy_index = (self.e3_destroy_index + 1) % 6
# 更新动画帧的索引。这行代码将self.e3_destroy_index加1,然
# 后取模6,这样索引值会在 0到 5之间循环,实现动画帧的循环播放。
if not self.e3_destroy_index:
# 再次检查 self.e3_destroy_index是否为0。
self.enemy3_fly_sound.stop()
# 停止播放敌人的飞行声音效果
self.score += 10
# 将玩家的得分增加10分
each.reset()
# 重置敌人对象的状态,为了准备下一轮的游戏或让敌人重新出现在屏幕上。
for each in self.mid_enemy_group:
if each.active:
# 检查当前敌人对象是否是活跃的(即是否在游戏界面上)。
if each.hit:
self.screen.blit(each.image_hit, each.rect)
each.hit = False
# 将each.hit设置为False,表示该敌人对象现在没有被击
else:
each.move()
# 调用每个活跃敌人的move方法,可能是更新敌人的位置或状态。
self.screen.blit(each.image, each.rect)
# 在屏幕上绘制正常的敌人图像
if each.hp != 8:
# 如果敌人的生命值不等于8。
pygame.draw.line(self.screen, self.BLACK,
(each.rect.left, each.rect.top - 5),
(each.rect.right, each.rect.top - 5),
2)
# 在屏幕上绘制一个黑色的生命值指示线
hp_remain = each.hp / MidEnemy.hp
# 计算敌人生命值的剩余比例
if hp_remain > 0.2:
hp_color = self.GREEN
else:
hp_color = self.RED
pygame.draw.line(self.screen, hp_color,
(each.rect.left, each.rect.top - 5),
(each.rect.left + each.rect.width * hp_remain, each.rect.top - 5),
2)
else:
if not (self.delay % 5):
# 检查self.delay除以5的余数是否为0。
# 如果余数为0,那么条件成立,执行下面的代码块。
if not self.e2_destroy_index:
# 检查self.e2_destroy_index是否为0。
self.enemy2_down_sound.play()
# 播放一个声音效果,可能是敌人被击败或销毁时的声音
self.screen.blit(each.destroy_images[self.e2_destroy_index], each.rect)
# 在游戏屏幕上绘制敌人被销毁的动画图像。
self.e2_destroy_index = (self.e2_destroy_index + 1) % 4
# 更新索引。
if not self.e2_destroy_index:
# 再次检查self.e2_destroy_index是否为0。
self.score += 4
# 将玩家的得分增加4分。
each.reset()
# 重置敌人对象的状态
for each in self.small_enemy_group:
# 这是一个循环,遍历self.small_enemy_group中的每一个元素
if each.active:
each.move()
# 调用每个活跃敌人的move方法,可能是更新敌人的位置或状态。
self.screen.blit(each.image, each.rect)
else:
if not (self.delay % 5):
# 这是一个条件判断。它检查self.delay除以5的余数是否为0。
# 如果余数为0,那么条件成立,执行下面的代码块。
if not self.e1_destroy_index:
# 一个条件判断。检查self.e1_destroy_index是否为0。
# 如果是,执行下面的代码块。
self.enemy1_down_sound.play()
# 播放一个声音效果,可能是敌人被击败或销毁时的声音
self.screen.blit(each.destroy_images[self.e1_destroy_index], each.rect)
# 在游戏屏幕上绘制敌人被销毁的动画图像
self.e1_destroy_index = (self.e1_destroy_index + 1) % 4
# 更新动画帧的索引
if not self.e1_destroy_index:
# 再次检查self.e1_destroy_index是否为0。
self.score += 1
# 将玩家的得分增加1分
each.reset()
# 重置敌人对象的状态
if self.hero.active:
if self.switch_image:
self.screen.blit(self.hero.image, self.hero.rect)
else:
self.screen.blit(self.hero.image2, self.hero.rect)
# 如果self.switch_image为True,则在屏幕上绘制self.hero.image,
# 否则绘制self.hero.image2。blit方法用于在屏幕上的指定位置绘制图像
else:
if not (self.delay % 5):
# 如果主角不活跃,代码将进入这个else块,处理主角的“毁灭”动画或状态。
# 它首先检查self.delay是否能被5整除。
if not self.me_destroy_index:
self.me_down_sound.play()
# 播放一个音效(主角被摧毁的声音)
self.screen.blit(self.hero.destroy_images[self.me_destroy_index], each.rect)
self.me_destroy_index = (self.me_destroy_index + 1) % 4
# 如果self.me_destroy_index为0,则播放一个音效(可能是主角被摧毁的声音)。
# 然后,它在屏幕上绘制“毁灭”动画的当前帧,并更新动画帧的索引。
if not self.me_destroy_index:
self.life_num -= 1
self.hero.reset()
pygame.time.set_timer(self.INVINCIBLE_TIME, 3 * 1000)
# 更新生命值和重置主角:当动画结束时(即self.me_destroy_index再次为0),减少生命值,
# 重置主角,并设置一个无敌时间(可能是让主角在一段时间内不受伤害)。
self.score_text = self.score_font.render("Score : {}".format(self.score), True, self.WHITE)
self.screen.blit(self.score_text, (10, 5))
# 显示得分,使用字体和颜色渲染得分文本,并在屏幕的指定位置绘制它。
self.screen.blit(self.paused_image, self.paused_rect)
# 在屏幕上的指定位置绘制一个暂停图像
self.bomb_text = self.bomb_font.render("{} / {}".format(self.bomb_num, self.bomb_max), True, self.WHITE)
self.text_rect = self.bomb_text.get_rect()
self.screen.blit(self.bomb, (10, SCREEN_RECT.height - 10 - self.bomb_rect.height))
self.screen.blit(self.bomb_text, (20 + self.bomb_rect.width, SCREEN_RECT.height - 5 - self.text_rect.height))
if self.life_num:
for i in range(self.life_num):
# 循环遍历每个生命数量
self.screen.blit(self.life_image,
(SCREEN_RECT.width - 50 - (i * 1) * self.life_rect.width,
SCREEN_RECT.height - 10 - self.life_rect.height))
# 计算图像的x坐标。它从屏幕的右边缘减去50像素,再减去每个生命图像的宽度乘以当前的循环迭代次数(即i的值)。这样,每个生命图像都会从左到右依次排列
# 计算图像的y坐标。它从屏幕的底部减去10像素,再减去生命图像的高度。这样,生命图像就会出现在屏幕的底部附近。
if self.supply_notice and not self.supply_notice_end:
# 是否存在一个补给通知且该通知尚未结束
self.supply_notice_text = self.supply_notice_font.render("supply time!", True, self.WHITE)
self.screen.blit(self.supply_notice_text, (SCREEN_RECT.centerx - 40, 0))
# 将渲染后的补给通知文本绘制到屏幕上,其x坐标为屏幕中心减去40像素,y坐标为0(即屏幕的顶部)。
if not (self.delay % 5):
# 这行代码检查self.delay是否能被5整除。如果不能,执行下面的代码块
self.switch_image = not self.switch_image
# 切换self.switch_image的布尔值。如果它原来是True,则变为False;
# 如果原来是False,则变为True。这通常用于在两个图像或状态之间切换
self.delay -= 1
# 将self.delay的值减1。这通常用于计时或延迟某些操作
if not self.delay:
# 检查self.delay是否为0
self.delay = 500
# 重新设置self.delay的值为500,重置或开始一个新的计时周期
if __name__ == "__main__":
game = PlaneGame()
print("这里是游戏后台")
try:
game.startGame()
# 调用了game对象的startGame方法启动游戏。
except SystemExit:
# 这种异常通常是由于调用了sys.exit()而引发的,用于退出程序。
# 如果发生了SystemExit异常,
# 程序会静默地忽略它,不会输出任何信息也不会终止程序。
pass
except Exception as problem:
# 用于捕获所有其他类型的异常。
print("未知错误:{}".format(problem))
源码放到了我的网盘:飞机大战源码
因为有一些音效、图片不想放在blog里了。