飞机大战小游戏
目录
飞机大战小游戏
1.概述
1.1 开发环境及技术
1.2 实现功能描述
1.2.1主要的工作内容
1.2.2 实现功能
1.2.3 功能完善
1.2.4 参考项目
2.项目介绍
2.1 项目内容介绍
2.2 项目介绍
2.2.1 项目代码逻辑
2.2.2 涉及到的知识
2.2.3 遇到的问题
2.3 最终运行效果编辑
3.附件
3.1 Bullet。py
3.2 enemy.py
3.3 hero.py
3.4 settings.py
3.5 supply.py
3.6 main.py
摘要
在数字娱乐时代,小游戏因其简单、直观且易于上手的特点,深受广大玩家的喜爱。其中,飞机大战游戏作为一种经典的游戏类型,凭借其紧张刺激的战斗场景和多样的游戏元素,一直深受玩家们的喜爱。为了满足这一市场需求,决定设计一款基于pygame的飞机大战小游戏。
Python作为一种高级编程语言,具有简洁、易读、可扩展性强等特点,被广泛应用于各个领域。近年来,随着游戏开发技术的不断发展,Python在游戏开发领域的应用也日益广泛。pygame作为Python的一个开源游戏开发库,为开发者提供了丰富的游戏开发工具和资源,使得开发者能够更加便捷地开发出高质量的游戏。
本研究的目的是通过开发一款基于pygame的飞机大战小游戏,进一步探索Python在游戏开发领域的应用。同时,本研究的意义在于为其他开发者提供一种简单、易行的游戏开发方法,推动Python在游戏开发领域的发展。
本研究的主要内容是开发一款基于pygame的飞机大战小游戏。具体研究内容包括:游戏设计、游戏实现、游戏测试与优化等。本研究采用的方法包括文献综述、案例分析、实践操作等。首先,通过文献综述了解游戏开发的基本原理和pygame库的使用方法;其次,通过案例分析学习经典的游戏设计模式;最后,通过实践操作完成游戏的开发。
本研究的目标是开发出一款简单、易玩、具有挑战性的飞机大战小游戏。具体目标包括:实现基本的游戏场景、飞机和敌机的基本移动和射击功能、分数统计和生命值管理功能等。预期成果包括:实现上述功能的完整游戏代码、一份详细的开发文档、以及针对游戏的测试报告和优化建议。
1.概述
1.1 开发环境及技术
本研究使用的是Windows11操作系统,Python版本为3.9。开发工具选择的是PyCharm,版本为2021.2.1。
- Pygame是一个开源的游戏开发库,提供了丰富的游戏开发工具和资源,可以帮助开发者更加便捷地开发出高质量的游戏。
- random是Python的内置库,用于生成随机数。在飞机大战游戏中,随机数可以用于生成敌机、子弹等元素。
- sys模块是Python的标准库之一,它提供了与解释器相关的功能。
- time模块是Python中用于处理时间的内建库。它自带了很多方法,可以将不同的时间类型进行相互转换。
- settings库通常用于配置应用程序的各种设置。它是一个Python模块,可以用于存储各种配置信息,如数据库连接、应用程序的路径、密码等等。settings库通常包含一系列的配置选项,每个选项都是一个变量,可以设置不同的值。这些选项可以根据需要进行设置,也可以在程序运行时动态地更改。
1.2 实现功能描述
1.2.1主要的工作内容
(1)游戏设计:确定游戏的基本规则、界面设计、音效等。这包括定义游戏的玩法、目标、难度设置,以及创建游戏的视觉和音频效果。
(2)编程:编写游戏的核心逻辑,包括飞机移动、射击、敌机生成、碰撞检测等。这是实现游戏功能的关键步骤,需要处理游戏中的各种逻辑和物理计算。
(3)图形和音效:制作游戏所需的图像和音效,如飞机、子弹、敌机、爆炸声等。这需要设计和制作游戏的视觉效果以及音效,使游戏更具吸引力。
(4)测试:确保游戏的稳定性和可玩性。这包括检查游戏是否存在漏洞、错误或性能问题,以及测试游戏的平衡性和难度设置。
(5)优化:调整游戏性能,提高游戏的流畅度。这可能包括优化代码、减少加载时间、提高渲染效率等。
(6)用户界面设计:设计易于使用的界面,使玩家能够轻松控制游戏。这包括按钮的位置、大小和颜色,以及任何其他用户界面元素的设计。
1.2.2 实现功能
(1)飞机移动:玩家可以通过键盘或触摸屏控制飞机在屏幕上左右移动,躲避敌机的攻击。
(2)射击功能:玩家可以发射子弹,射击敌机,击中敌机后可以获得分数。
敌机生成和移动:敌机在屏幕上随机生成,并向玩家的飞机移动,增加了游戏的挑战性和趣味性。
(3)碰撞检测:当飞机与敌机或子弹碰撞时,游戏结束或得分增加,确保了游戏的公平性和可玩性。
(4)得分和生命值显示:游戏实时显示玩家的得分和生命值,使玩家能够了解自己的游戏进度和当前状态。
(5)音效和视觉效果:游戏具有音效和视觉效果,如射击音效、爆炸效果等,增加了游戏的吸引力和沉浸感。
1.2.3 功能完善
(1)爆炸效果:当子弹接触到敌机时,增加爆炸效果,使游戏更加生动和刺激。
(2)Boss 敌机:增加 Boss 敌机,这些敌机具有更高的生命值和攻击力,使游戏更具挑战性。同时,显示 Boss 敌机的血量,让玩家更好地了解战斗状况。
(3)敌机发射子弹:对于一部分敌机,增加敌机发射子弹的功能,增加游戏的复杂性和策略性。
(4)道具敌机:增加道具敌机,这些敌机在被击杀后会掉落道具,玩家可以收集这些道具来获得特殊能力或增益效果。
(5)背景音乐和击杀音乐:增加游戏的背景音乐和击杀敌机时的音效,提升游戏的沉浸感和娱乐性。
(6)游戏难度:根据玩家的技能水平,调整敌机的数量、速度和攻击频率,以提供更具挑战性的游戏体验。
(7)游戏模式:添加新的游戏模式,例如限时模式、生存模式或合作模式等,提供多样化的玩法。
(8)社交功能:集成社交功能,允许玩家与好友对战或合作完成任务,增加游戏的互动性和竞技性。
(9)游戏成就:设立游戏成就系统,激励玩家完成特定任务或挑战,增加游戏的目标和挑战性。
1.2.4 参考项目
Pygame库:Pygame是一个用于制作视频游戏的Python库。它可以用来创建飞机大战小游戏的图形和音效,并且具有广泛的使用和社区支持。.
Unity引擎:Unity是一个流行的游戏开发引擎,可以用来创建飞机大战小游戏的3D效果和复杂的游戏机制。Unity提供了丰富的资源、工具和文档,可以帮助开发者快速构建游戏。
游戏设计教程和文档:可以参考在线游戏设计教程和文档,以获取关于飞机大战小游戏游戏机制、界面设计、音效等方面的指导。这些资源可以帮助开发者了解游戏设计的最佳实践和理论。
2.项目介绍
2.1 项目内容介绍
基于pygame的飞机大战小游戏是一个经典的游戏,玩家需要控制一架飞机在屏幕上移动,并射击敌机。下面是一个简单的基于pygame的飞机大战小游戏的概述:
(1)游戏初始化:
导入pygame库和其他必要的模块。设置游戏窗口大小、标题和其他选项。加载所需的图像、音效和字体文件。
(2)游戏主循环:
初始化游戏状态、时钟和精灵组等。进入游戏主循环,处理游戏事件(如键盘按键、鼠标点击等)。
(3)游戏逻辑:
玩家控制:根据玩家的输入,控制飞机的移动。
射击:检测玩家的射击按键,发射子弹并击中敌机。
敌机生成和移动:在屏幕上随机生成敌机,并向玩家的飞机移动。
碰撞检测:检测飞机与敌机或子弹的碰撞,处理游戏结束或得分增加。
(4)游戏渲染:
绘制游戏背景、飞机、子弹、敌机等精灵,更新游戏界面,包括得分、生命值等显示元素。
(5)游戏音效和视觉效果:
加载并播放背景音乐和音效,使用适当的颜色和动画效果,增加游戏的吸引力和沉浸感
(6)游戏优化和改进:
根据玩家反馈和测试结果,优化游戏性能、提高渲染效率、调整难度,添加新的游戏功能和元素,如道具、特殊效果等,以增加游戏的可玩性和挑战性。
2.2 项目介绍
2.2.1 项目代码逻辑
1.对项目结构进行截图并描述。
图1 项目结构
描述:
- bullet.py、enemy.py、hero.py、main.py是游戏文件,这是游戏的主要代码文件,通常包含游戏的主循环、逻辑、渲染等核心功能。
- sound是音效和音乐,存放游戏的音效和背景音乐文件。
- image是图像资源,存放游戏所需的图像文件,如飞机、子弹、敌机等。
- record.txt是文档和说明,包含游戏的文档、说明和帮助文件。
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 |
游戏主程序对象 |
整合所有模块的功能,驱动游戏的进行 |
2.2.2 涉及到的知识
(1)书本知识涉及有:
- 基础语法:包括变量、数据类型(如整数、浮点数、字符串、列表、元组、字典和集合)、控制流语句(如if-else, for, while)等。
- 函数:如何定义函数、函数的参数传递、局部变量与全局变量、函数返回值等。
- 文件操作:如何打开、读取、写入和关闭文件,以及文件路径的处理等。
- 异常处理:使用try-except语句来处理程序中可能出现的错误或异常。
- 迭代器和生成器:使用迭代器遍历数据集合,以及使用生成器创建自己的迭代器对象。
- 装饰器:用于修改或增强函数或方法的行为的特殊类型的函数。
- 模块和包:除了模块的导入,还有如何创建自己的模块和包,以及模块间的相互引用等。
- 多线程与多进程:如何处理并发任务,包括线程和进程的基本概念、同步机制等。
(2)新知识涉及有:
pygame库:首先,你需要熟悉pygame库的基本使用。pygame是一个用于制作2D游戏的Python库,它提供了丰富的图像、声音、事件处理等功能,可以帮助你快速构建游戏。
2.2.3 遇到的问题
1.问题:pygame库安装失败。
解决过程:首先,确保Python和pip已经正确安装。然后,使用pip install pygame命令尝试安装。如果仍然失败,可以考虑使用虚拟环境,或者检查网络连接和代理设置。
2. 问题:加载的图像显示不正常。
解决过程:首先,检查图像文件路径是否正确。其次,确保图像文件的格式是pygame支持的。如果图像仍然显示不正常,可以尝试使用图像编辑软件打开并重新保存图像文件,或者调整pygame的图像加载参数。
3. 问题:音效和背景音乐无法播放。
解决过程:首先,检查音效和音乐文件的路径是否正确。其次,确保文件的格式是pygame支持的。如果仍然无法播放,可以尝试使用不同的音频文件,或者调整pygame的音频设置。
2.3 最终运行效果
图2 运行结果
描述:
(1)游戏开始时,玩家将看到一个简单的菜单界面
(2)玩家需要控制飞机移动并射击敌机,同时躲避敌机的攻击。
(3)游戏界面下方将显示玩家生命值。当玩家击中敌机时,分数将增加;当玩家的生命值减少到零时,游戏将结束。
(4)在游戏过程中,玩家可以获得补给品,以提高战斗力。
(5)随着关卡的深入,敌机会变得更加强大,移动速度更快。玩家需要不断提升自己的技能和策略来应对挑战。
3.附件
3.1 Bullet。py
# 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
3.2 enemy.py
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)
3.3 hero.py
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,并重置其位置到屏幕底部中心
3.4 settings.py
import pygame
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
FPS = 60
FILE_PATH = ""
3.5 supply.py
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
3.6 main.py
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))
源码放到了我的网盘:飞机大战源码文章来源:https://www.toymoban.com/news/detail-798029.html
因为有一些音效、图片不想放在blog里了。文章来源地址https://www.toymoban.com/news/detail-798029.html
到了这里,关于Python课程设计 飞机大战小游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!