1.游戏介绍
1.1 游戏的基本设定
- 敌方共有大中小3款飞机,分别为高中低三中速度,自己还可以设置一个游戏等级窗口,来改变自己刚开始进入游戏时难度等级;
- 子弹的射程并非全屏,而大概是屏幕长度的80%;
- 消灭飞机需要1发子弹,中飞机需要8发子弹,大飞机需要20发子弹;
1.2 对游戏做的改进
- 为中飞机和打飞机增加了血槽的显示,这样我们可以直观的知道敌机快被消灭了没有;
- 我方有三次机会,每次被敌人消灭后,新诞生的飞机有3秒钟的安全期
2.背景相关信息添加
2.1 添加飞机大战的基本信息
from pygame.locals import *
from random import *
import tkinter as tk # 制作GUI界面库
import pygame
import math
import sys
pygame.init() # 初始化
pygame.mixer.init() # 混音器初始化
clock = pygame.time.Clock() # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3") # 设置背景音乐
pygame.mixer.music.set_volume(1) # 设置音量
# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3") # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3") # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3") # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3") # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3") # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3") # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3") # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3") # 按键音效
myself_down_sound.set_volume(0.2)
"""图片文件路径"""
background_image = "image/background.png" # 背景图的路径
bullet1_image = "image/bullet1.png" # 第一种子弹图
enemy1_image = "image/enemy1.png" # 小敌机图片
enemy2_image = "image/enemy2.png" # 中敌机图片
enemy3_n1_image = "image/enemy3.png" # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png" # 大敌机图片2
me1_image = "image/hero1.png" # 自身飞机第一张图片
me2_image = "image/hero2.png" # 自身飞机第二张图片
# 设置背景
bg_size = width, height = 430, 700 # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size) # 这是背景大小
background = pygame.image.load(background_image).convert_alpha() # 画背景
pygame.mixer.music.play(-1) # 播放背景音乐,-1 表示无限循环播放
def main():
while True:
for event in pygame.event.get(): # 键盘操作
if event.type == QUIT:
sys.exit()
screen.blit(background, (0, 0)) # 绘制背景
pygame.display.flip() # 不停的刷新画面,不停的绘画
clock.tick(60) # 设置帧率
if __name__ == "__main__":
# 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
try:
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass
3.我方战机
3.1 设置我方战机类
创建一个名为 myplane 的模块,然后把我方飞机的所有属性和方法定义在里边
######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite): # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, bg_size,me1_image,me2_image):
self.image1 = pygame.image.load(me1_image).convert_alpha() # 第一张飞机图片
self.image2 = pygame.image.load(me2_image).convert_alpha() # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
self.rect = self.image1.get_rect() # 获得飞机图片的尺寸
self.width, self.height = bg_size[0], bg_size[1] # 设置飞机允许活动地点
self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
(self.height - self.rect.height - 20)] # 注意括号设置我方飞机出现的位置
self.speed = 10 # 设置飞机出现的速度
def moveup(self): # 飞机向上飞的函数
if self.rect.top > 0: # 如果我方飞机没有飞出 上方边界
self.rect.top -= 10 # 那么我方飞机朝上飞10个像素
else: # 飞出 上方边界
self.rect.top = 0 # 锁定在0的位置,不再发生变化
def movedown(self): # 飞机向下飞的函数
if self.rect.bottom < (self.height - 20): # 如果我方飞机没有飞出 上方边界
self.rect.bottom += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.bottom = (self.height - 20) # 锁定在底边界上方60的位置,不再发生变化
def moveleft(self): # 飞机向左飞的函数
if self.rect.left > 0: # 如果我方飞机没有飞出 左方边界
self.rect.left -= 10 # 那么我方飞机朝下左10个像素
else: # 飞出 左方边界
self.rect.left = 0 # 锁定在左边界的位置,不再发生变化
def moveright(self): # 飞机向下飞的函数
if self.rect.right < self.width: # 如果我方飞机没有飞出 上方边界
self.rect.right += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.right = self.width # 锁定在底边界的位置,不再发生变化
3.2 显示我方战机
在main函数的while循环上面生成我方飞机类
me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
在while循环里面,绘制背景的下面绘制我方战机
# 绘制飞机
screen.blit(me.image2, me.rect) # 绘制第一张飞机图
3.3 控制我方飞机移动
1、通过检测事件消息,检测到如果有 KEYDOWN 或者 KEYUP 事件,我们就知道是用户按下了键盘按键。(这是我们之前常用的一种方法)
2、调用 key 模块里的 get_pressed() 方法,会返回一个序列,该序列包含键盘上所有按键的布尔类型的值,如果这个值是True 的话,表示该按键被按下。
写在退出按键下面即可
# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]: # 如果按下上键或者↑
me.moveup() # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]: # 如果按下下键或者↓
me.movedown() # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]: # 如果按下左键或者←
me.moveleft() # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]: # 如果按下右键或者→
me.moveright() # 飞船向右飞行
3.4 切换我方飞机造型
为了增加我方飞机的动态效果,我们可以通过两张图片(me1,png 和 me2.png)的切换来实现飞机冒烟的效果
设置两个变量switch_image,delay
switch_image 为True 画第一张飞机图
switch_image 为False 画第二张飞机图
delay为延时变量
写在while循环的上面
switch_image = True # 用于切换战机图片
delay = 100 # 用于延时
写在绘制背景的下面
# 绘制我方飞机
if switch_image: # 2如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
# 切换图片
if delay % 5 == 0:
switch_image = not switch_image
delay -= 1
if delay==0:
delay = 100
3.5 目前所写代码
from pygame.locals import *
from random import *
import tkinter as tk # 制作GUI界面库
import pygame
import math
import sys
pygame.init() # 初始化
pygame.mixer.init() # 混音器初始化
clock = pygame.time.Clock() # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3") # 设置背景音乐
pygame.mixer.music.set_volume(1) # 设置音量
# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3") # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3") # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3") # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3") # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3") # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3") # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3") # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3") # 按键音效
myself_down_sound.set_volume(0.2)
"""图片文件路径"""
background_image = "image/background.png" # 背景图的路径
bullet1_image = "image/bullet1.png" # 第一种子弹图
enemy1_image = "image/enemy1.png" # 小敌机图片
enemy2_image = "image/enemy2.png" # 中敌机图片
enemy3_n1_image = "image/enemy3.png" # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png" # 大敌机图片2
me1_image = "image/hero1.png" # 自身飞机第一张图片
me2_image = "image/hero2.png" # 自身飞机第二张图片
# 设置背景
bg_size = width, height = 430, 700 # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size) # 这是背景大小
background = pygame.image.load(background_image).convert_alpha() # 画背景
pygame.mixer.music.play(-1) # 播放背景音乐,-1 表示无限循环播放
######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite): # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, bg_size,me1_image,me2_image):
self.image1 = pygame.image.load(me1_image).convert_alpha() # 第一张飞机图片
self.image2 = pygame.image.load(me2_image).convert_alpha() # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
self.rect = self.image1.get_rect() # 获得飞机图片的尺寸
self.width, self.height = bg_size[0], bg_size[1] # 设置飞机允许活动地点
self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
(self.height - self.rect.height - 20)] # 注意括号设置我方飞机出现的位置
self.speed = 10 # 设置飞机出现的速度
def moveup(self): # 飞机向上飞的函数
if self.rect.top > 0: # 如果我方飞机没有飞出 上方边界
self.rect.top -= 10 # 那么我方飞机朝上飞10个像素
else: # 飞出 上方边界
self.rect.top = 0 # 锁定在0的位置,不再发生变化
def movedown(self): # 飞机向下飞的函数
if self.rect.bottom < (self.height - 20): # 如果我方飞机没有飞出 上方边界
self.rect.bottom += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.bottom = (self.height - 20) # 锁定在底边界上方60的位置,不再发生变化
def moveleft(self): # 飞机向左飞的函数
if self.rect.left > 0: # 如果我方飞机没有飞出 左方边界
self.rect.left -= 10 # 那么我方飞机朝下左10个像素
else: # 飞出 左方边界
self.rect.left = 0 # 锁定在左边界的位置,不再发生变化
def moveright(self): # 飞机向下飞的函数
if self.rect.right < self.width: # 如果我方飞机没有飞出 上方边界
self.rect.right += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.right = self.width # 锁定在底边界的位置,不再发生变化
def main():
me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
switch_image = True # 用于切换战机图片
delay = 100 # 用于延时
while True:
for event in pygame.event.get(): # 键盘操作
if event.type == QUIT:
sys.exit()
# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]: # 如果按下上键或者↑
me.moveup() # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]: # 如果按下下键或者↓
me.movedown() # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]: # 如果按下左键或者←
me.moveleft() # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]: # 如果按下右键或者→
me.moveright() # 飞船向右飞行
screen.blit(background, (0, 0)) # 绘制背景
# 绘制我方飞机
if switch_image: # 2如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
# 切换图片
if delay % 5 == 0:
switch_image = not switch_image
delay -= 1
if delay==0:
delay = 100
pygame.display.flip() # 不停的刷新画面,不停的绘画
clock.tick(60) # 设置帧率
if __name__ == "__main__":
# 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
try:
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass
4.敌方战机
敌机分为小中大三个尺寸,它们的速度一次就是快中慢(越小越快),在页面上方,我们就需要随机创建一些敌机,可以通过在页面外部上方5个屏幕高度范围内随机生成一个敌机以保证不让敌机在一排出现。
4.1 小飞机
写在我方战机类的下面
####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite): #定义小敌机类,继承自动画精灵
def __init__(self,bg_size,enemy1_image):
pygame.sprite.Sprite.__init__(self)
self.enemy1 = pygame.image.load(enemy1_image).convert_alpha() # 载入小敌机图片
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成小敌机的活动范围
self.rect = self.enemy1.get_rect() #获得低级敌机的尺寸
# 在窗口的5倍之上的距离中产生飞机
self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height , 0)]
self.speed = 1 # 设置小敌机移动的速度
def move(self): # 小敌机的移动函数
if self.rect.top < self.height: #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else: #如果小飞机已经超出窗口的下边界框
self.reset() #重置小飞机
def reset(self): #重置小飞机函数
# 在窗口的5倍之上的距离中产生飞机
self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height, 0)]
4.2 中飞机
写在小敌机类下面
# 中敌机
class MiddleEnemy(pygame.sprite.Sprite): #定义中敌机,继承自动画精灵
def __init__(self,bg_size,enemy2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy2 = pygame.image.load(enemy2_image).convert_alpha() #载入中级敌机图片
self.width,self.height = bg_size[0], bg_size[1] #获取生成低级敌机的活动范围
self.rect = self.enemy2.get_rect() #获得低级敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置中敌机移动的速度
def move(self) : #小敌机的移动函数
if self.rect.top < self.height : #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else : #如果小飞机已经超出窗口的下边界框
self.reset() #重置中飞机
def reset(self): #重置中飞机函数
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
4.3 大敌机
写在中敌机类下面
# 大敌机
class BigEnemy(pygame.sprite.Sprite): #定义大敌机类,继承自动画精灵
def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha() # 载入大敌机图片1
self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha() # 载入大敌机图片2
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成大敌机的活动范围
self.rect = self.enemy3_n1.get_rect() #获得大敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置大敌机移动的速度
def move(self) : #大敌机的移动函数
if self.rect.top < self.height : #如果大飞机的底超出窗口的下边框
self.rect.top += self.speed #大飞机向下移动他的速度
else : #如果大飞机已经超出窗口的下边界框
self.reset() #重置大飞机
def reset(self): #重置大飞机函数
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
4.4 实例化敌机
# 生成敌方飞机 定义精灵组,把生成的飞机放到这里
enemies = pygame.sprite.Group() # 生成整个飞机组
smallenemies = pygame.sprite.Group() # 生成小飞机组
add_smallenemies(smallenemies, enemies, 20) # 生成小型飞机
middleenemies = pygame.sprite.Group() # 生成中飞机组
add_middleenemies(middleenemies, enemies, 10) # 生成中型飞机
bigenemies = pygame.sprite.Group() # 生成大飞机组
add_bigenemies(bigenemies, enemies, 4) # 生成大型飞机
创建实例化三种敌机生成函数
def add_smallenemies(group1, group2, num):
for i in range(num):
e1 = SmallEnemy(bg_size, enemy1_image)
group1.add(e1)
group2.add(e1)
def add_middleenemies(group1, group2, num):
for i in range(num):
e2 = MiddleEnemy(bg_size, enemy2_image)
group1.add(e2)
group2.add(e2)
def add_bigenemies(group1, group2, num):
for i in range(num):
e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
group1.add(e3)
group2.add(e3)
4.5 绘制显示敌机
可以给大飞机添加音效设置
switch_image为True显示大飞机图片1
switch_image为False显示大飞机图片2
写在绘制背景的下面
# 绘制大型敌机
for each in bigenemies:
each.move()
if switch_image:
screen.blit(each.enemy3_n1, each.rect)
else:
screen.blit(each.enemy3_n2, each.rect)
# 即将出现在画面中,播放音效
if each.rect.bottom > -50:
enemy3_fly_sound.play()
# 绘制中型敌机:
for each in middleenemies:
each.move()
screen.blit(each.enemy2, each.rect)
# 绘制小型敌机:
for each in smallenemies:
each.move()
screen.blit(each.enemy1, each.rect)
4.6 目前所写代码
from pygame.locals import *
from random import *
import tkinter as tk # 制作GUI界面库
import pygame
import math
import sys
pygame.init() # 初始化
pygame.mixer.init() # 混音器初始化
clock = pygame.time.Clock() # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3") # 设置背景音乐
pygame.mixer.music.set_volume(1) # 设置音量
# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3") # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3") # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3") # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3") # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3") # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3") # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3") # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3") # 按键音效
myself_down_sound.set_volume(0.2)
"""图片文件路径"""
background_image = "image/background.png" # 背景图的路径
bullet1_image = "image/bullet1.png" # 第一种子弹图
enemy1_image = "image/enemy1.png" # 小敌机图片
enemy2_image = "image/enemy2.png" # 中敌机图片
enemy3_n1_image = "image/enemy3.png" # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png" # 大敌机图片2
me1_image = "image/hero1.png" # 自身飞机第一张图片
me2_image = "image/hero2.png" # 自身飞机第二张图片
# 设置背景
bg_size = width, height = 430, 700 # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size) # 这是背景大小
background = pygame.image.load(background_image).convert_alpha() # 画背景
pygame.mixer.music.play(-1) # 播放背景音乐,-1 表示无限循环播放
######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite): # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, bg_size,me1_image,me2_image):
self.image1 = pygame.image.load(me1_image).convert_alpha() # 第一张飞机图片
self.image2 = pygame.image.load(me2_image).convert_alpha() # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
self.rect = self.image1.get_rect() # 获得飞机图片的尺寸
self.width, self.height = bg_size[0], bg_size[1] # 设置飞机允许活动地点
self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
(self.height - self.rect.height - 20)] # 注意括号设置我方飞机出现的位置
self.speed = 10 # 设置飞机出现的速度
def moveup(self): # 飞机向上飞的函数
if self.rect.top > 0: # 如果我方飞机没有飞出 上方边界
self.rect.top -= 10 # 那么我方飞机朝上飞10个像素
else: # 飞出 上方边界
self.rect.top = 0 # 锁定在0的位置,不再发生变化
def movedown(self): # 飞机向下飞的函数
if self.rect.bottom < (self.height - 20): # 如果我方飞机没有飞出 上方边界
self.rect.bottom += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.bottom = (self.height - 20) # 锁定在底边界上方60的位置,不再发生变化
def moveleft(self): # 飞机向左飞的函数
if self.rect.left > 0: # 如果我方飞机没有飞出 左方边界
self.rect.left -= 10 # 那么我方飞机朝下左10个像素
else: # 飞出 左方边界
self.rect.left = 0 # 锁定在左边界的位置,不再发生变化
def moveright(self): # 飞机向下飞的函数
if self.rect.right < self.width: # 如果我方飞机没有飞出 上方边界
self.rect.right += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.right = self.width # 锁定在底边界的位置,不再发生变化
####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite): #定义小敌机,继承自动画精灵
def __init__(self,bg_size,enemy1_image):
pygame.sprite.Sprite.__init__(self)
self.enemy1 = pygame.image.load(enemy1_image).convert_alpha() # 载入小敌机图片
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成小敌机的活动范围
self.rect = self.enemy1.get_rect() #获得低级敌机的尺寸
# 在窗口的5倍之上的距离中产生飞机
self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height , 0)]
self.speed = 2 # 设置小敌机移动的速度
def move(self): # 小敌机的移动函数
if self.rect.top < self.height: #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else: #如果小飞机已经超出窗口的下边界框
self.reset() #重置小飞机
def reset(self): #重置小飞机函数
# 在窗口的5倍之上的距离中产生飞机
self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height, 0)]
class MiddleEnemy(pygame.sprite.Sprite): #定义中敌机,继承自动画精灵
def __init__(self,bg_size,enemy2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy2 = pygame.image.load(enemy2_image).convert_alpha() #载入中级敌机照片
self.width,self.height = bg_size[0], bg_size[1] #获取生成低级敌机的活动范围
self.rect = self.enemy2.get_rect() #获得低级敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置中敌机移动的速度
def move(self) : #小敌机的移动函数
if self.rect.top < self.height : #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else : #如果小飞机已经超出窗口的下边界框
self.reset() #重置中飞机
def reset(self): #重置中飞机函数
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
# 大敌机
class BigEnemy(pygame.sprite.Sprite): #定义大敌机类,继承自动画精灵
def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha() # 载入大敌机图片1
self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha() # 载入大敌机图片2
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成大敌机的活动范围
self.rect = self.enemy3_n1.get_rect() #获得大敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置大敌机移动的速度
def move(self) : #大敌机的移动函数
if self.rect.top < self.height : #如果大飞机的底超出窗口的下边框
self.rect.top += self.speed #大飞机向下移动他的速度
else : #如果大飞机已经超出窗口的下边界框
self.reset() #重置大飞机
def reset(self): #重置大飞机函数
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
def add_smallenemies(group1, group2, num):
for i in range(num):
e1 = SmallEnemy(bg_size, enemy1_image)
group1.add(e1)
group2.add(e1)
def add_middleenemies(group1, group2, num):
for i in range(num):
e2 = MiddleEnemy(bg_size, enemy2_image)
group1.add(e2)
group2.add(e2)
def add_bigenemies(group1, group2, num):
for i in range(num):
e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
group1.add(e3)
group2.add(e3)
def main():
me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
switch_image = True # 用于切换战机图片
delay = 100 # 用于延时
# 生成敌方飞机 定义精灵组,把生成的飞机放到这里
enemies = pygame.sprite.Group() # 生成整个飞机组
smallenemies = pygame.sprite.Group() # 生成小飞机组
add_smallenemies(smallenemies, enemies, 20) # 生成小型飞机
middleenemies = pygame.sprite.Group() # 生成中飞机组
add_middleenemies(middleenemies, enemies, 10) # 生成中型飞机
bigenemies = pygame.sprite.Group() # 生成大飞机组
add_bigenemies(bigenemies, enemies, 4) # 生成大型飞机
while True:
for event in pygame.event.get(): # 键盘操作
if event.type == QUIT:
sys.exit()
# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]: # 如果按下上键或者↑
me.moveup() # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]: # 如果按下下键或者↓
me.movedown() # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]: # 如果按下左键或者←
me.moveleft() # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]: # 如果按下右键或者→
me.moveright() # 飞船向右飞行
screen.blit(background, (0, 0)) # 绘制背景
# 绘制大型敌机
for each in bigenemies:
each.move()
if switch_image:
screen.blit(each.enemy3_n1, each.rect)
else:
screen.blit(each.enemy3_n2, each.rect)
# 即将出现在画面中,播放音效
if each.rect.bottom > -50:
enemy3_fly_sound.play()
# 绘制中型敌机:
for each in middleenemies:
each.move()
screen.blit(each.enemy2, each.rect)
# 绘制小型敌机:
for each in smallenemies:
each.move()
screen.blit(each.enemy1, each.rect)
# 绘制我方飞机
if switch_image: # 2如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
# 切换图片
if delay % 5 == 0:
switch_image = not switch_image
delay -= 1
if delay == 0:
delay = 100
pygame.display.flip() # 不停的刷新画面,不停的绘画
clock.tick(60) # 设置帧率
if __name__ == "__main__":
# 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
try:
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass
5.碰撞检测
5.1 为何碰撞检测
当敌方飞机和我方飞机发生碰撞时,两方应该是玉石俱焚的,所以在完成之前的基础操作后,现在要为每一个类增加撞击时发生的惨烈画面,具体情况如下:
enemy1:
enemy2:
enemy3:
me:
5.2 添加飞机爆炸图片
我方战机
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
])
5.3 判断飞机生存状态
接下来我们要为每一个类添加 active 属性,该属性表示飞机是死是活,也就是说:
当该属性为 True 时,我们就让飞机显示正常的飞行状态,
当该属性为 False 时,表示该飞机已经遇难了,我们就要依次显示 坠机的画面,显示完之后,调用该类的 resert() 方法。
为每个飞机类添加 active 属性
self.active = True # 表示飞机生存状态
大中小敌机需要在reset()函数上多添加一次
5.4 飞机爆炸状态显示
设置图片状态索引
# 中弹图片索引
e1_destroy_index = 0
e2_destroy_index = 0
e3_destroy_index = 0
me_destroy_index = 0
大飞机毁灭状态添加
for each in bigenemies:
if each.active: # 如果大型敌机为生存状态
each.move()
if switch_image:
screen.blit(each.enemy3_n1, each.rect)
else:
screen.blit(each.enemy3_n2, each.rect)
# 即将出现在画面中,播放音效
if each.rect.bottom > -50:
enemy3_fly_sound.play()
else: # 毁灭
if not (delay % 3): # 设置两张照片转换的时间延时
# 只需要播放一次
if e3_destroy_index == 0:
enemy3_down_sound.play()
screen.blit(each.destroy_images[e3_destroy_index], each.rect)
e3_destroy_index = (e3_destroy_index + 1) % 6 # 循环播放爆炸图片
if e3_destroy_index == 0:
enemy3_fly_sound.stop() # 关闭声音
each.reset()
中飞机毁灭状态添加
# 绘制中型敌机:
for each in middleenemies:
if each.active:
each.move()
screen.blit(each.enemy2, each.rect)
else:
# 毁灭
if not (delay % 3):
if e2_destroy_index == 0:
enemy2_down_sound.play()
screen.blit(each.destroy_images[e2_destroy_index], each.rect)
e2_destroy_index = (e2_destroy_index + 1) % 4 # 循环播放爆炸图片
if e2_destroy_index == 0:
each.reset()
小飞机毁灭状态添加
# 绘制小型敌机:
for each in smallenemies:
if each.active:
each.move()
screen.blit(each.enemy1, each.rect)
else:
# 毁灭
if not(delay%3):
if e1_destroy_index == 0:
enemy1_down_sound.play()
screen.blit(each.destroy_images[e1_destroy_index], each.rect)
e1_destroy_index = (e1_destroy_index + 1)%4 # 循环播放爆炸图片
if e1_destroy_index == 0:
each.reset()
设置变量running
running 为True,表示游戏正常运行
running 为False,表示游戏结束
running = True # 游戏执行状态
while running:
我方飞机毁灭状态添加
# 绘制我方飞机
if me.active:
if switch_image: # 如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
else:
# 毁灭
if not (delay % 3):
if me_destroy_index == 0:
me_down_sound.play()
screen.blit(me.destroy_images[me_destroy_index], me.rect)
me_destroy_index = (me_destroy_index + 1) % 4 # 循环播放爆炸图片
if me_destroy_index == 0:
print("Game Over")
running = False
5.5 检测是否发生碰撞
写在我方飞机的上面
# 检测我方飞机和其他飞机发生碰撞 spritecollide矩形区域
enemies_down = pygame.sprite.spritecollide(me, enemies, False)
if enemies_down:
me.active = False
for e in enemies_down:
e.active = False
5.6 完美碰撞检测
给类添加上mask属性,之后可以按照完美碰撞( 检测透明部分)
# 我方飞机
self.mask = pygame.mask.from_surface(self.image1)
# 小敌机
self.mask = pygame.mask.from_surface(self.enemy1)
# 中敌机
self.mask = pygame.mask.from_surface(self.enemy2)
# 大敌机
self.mask = pygame.mask.from_surface(self.enemy3_n1)
from pygame.locals import *
from random import *
import traceback
import tkinter as tk # 制作GUI界面库
import pygame
import math
import sys
pygame.init() # 初始化
pygame.mixer.init() # 混音器初始化
clock = pygame.time.Clock() # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3") # 设置背景音乐
pygame.mixer.music.set_volume(1) # 设置音量
# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3") # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3") # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3") # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3") # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3") # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3") # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3") # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3") # 按键音效
myself_down_sound.set_volume(0.2)
"""图片文件路径"""
background_image = "image/background.png" # 背景图的路径
bullet1_image = "image/bullet1.png" # 第一种子弹图
enemy1_image = "image/enemy1.png" # 小敌机图片
enemy2_image = "image/enemy2.png" # 中敌机图片
enemy3_n1_image = "image/enemy3.png" # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png" # 大敌机图片2
me1_image = "image/hero1.png" # 自身飞机第一张图片
me2_image = "image/hero2.png" # 自身飞机第二张图片
# 设置背景
bg_size = width, height = 430, 700 # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size) # 这是背景大小
background = pygame.image.load(background_image).convert_alpha() # 画背景
pygame.mixer.music.play(-1) # 播放背景音乐,-1 表示无限循环播放
######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite): # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, bg_size,me1_image,me2_image):
self.me1_image = me1_image
self.me2_image = me2_image
self.image1 = pygame.image.load(me1_image).convert_alpha() # 第一张飞机图片
self.image2 = pygame.image.load(me2_image).convert_alpha() # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
self.rect = self.image1.get_rect() # 获得飞机图片的尺寸
self.width, self.height = bg_size[0], bg_size[1] # 设置飞机允许活动地点
self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
(self.height - self.rect.height - 20)] # 注意括号设置我方飞机出现的位置
self.speed = 10 # 设置飞机出现的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.image1) # 给类添加上mask属性,之后可以按照完美碰撞
def moveup(self): # 飞机向上飞的函数
if self.rect.top > 0: # 如果我方飞机没有飞出 上方边界
self.rect.top -= 10 # 那么我方飞机朝上飞10个像素
else: # 飞出 上方边界
self.rect.top = 0 # 锁定在0的位置,不再发生变化
def movedown(self): # 飞机向下飞的函数
if self.rect.bottom < (self.height - 20): # 如果我方飞机没有飞出 上方边界
self.rect.bottom += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.bottom = (self.height - 20) # 锁定在底边界上方60的位置,不再发生变化
def moveleft(self): # 飞机向左飞的函数
if self.rect.left > 0: # 如果我方飞机没有飞出 左方边界
self.rect.left -= 10 # 那么我方飞机朝下左10个像素
else: # 飞出 左方边界
self.rect.left = 0 # 锁定在左边界的位置,不再发生变化
def moveright(self): # 飞机向下飞的函数
if self.rect.right < self.width: # 如果我方飞机没有飞出 上方边界
self.rect.right += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.right = self.width # 锁定在底边界的位置,不再发生变化
####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite): #定义小敌机,继承自动画精灵
def __init__(self,bg_size,enemy1_image):
pygame.sprite.Sprite.__init__(self)
self.enemy1 = pygame.image.load(enemy1_image).convert_alpha() # 载入小敌机图片
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成小敌机的活动范围
self.rect = self.enemy1.get_rect() #获得低级敌机的尺寸
# 在窗口的5倍之上的距离中产生飞机
self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height , 0)]
self.speed = 2 # 设置小敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([\
pygame.image.load("image/enemy1_down1.png").convert_alpha(), \
pygame.image.load("image/enemy1_down2.png").convert_alpha(), \
pygame.image.load("image/enemy1_down3.png").convert_alpha(), \
pygame.image.load("image/enemy1_down4.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy1) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): # 小敌机的移动函数
if self.rect.top < self.height: #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else: #如果小飞机已经超出窗口的下边界框
self.reset() #重置小飞机
def reset(self): #重置小飞机函数
self.active = True # 表示飞机生存状态
# 在窗口的5倍之上的距离中产生飞机
self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height, 0)]
class MiddleEnemy(pygame.sprite.Sprite): #定义中敌机,继承自动画精灵
def __init__(self,bg_size,enemy2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy2 = pygame.image.load(enemy2_image).convert_alpha() #载入中级敌机照片
self.width,self.height = bg_size[0], bg_size[1] #获取生成低级敌机的活动范围
self.rect = self.enemy2.get_rect() #获得低级敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置中敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/enemy2_down1.png").convert_alpha(), \
pygame.image.load("image/enemy2_down2.png").convert_alpha(), \
pygame.image.load("image/enemy2_down3.png").convert_alpha(), \
pygame.image.load("image/enemy2_down4.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy2) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): #中敌机的移动函数
if self.rect.top < self.height : #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else : #如果小飞机已经超出窗口的下边界框
self.reset() #重置中飞机
def reset(self): #重置中飞机函数
self.active = True # 表示飞机生存状态
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
# 大敌机
class BigEnemy(pygame.sprite.Sprite): #定义大敌机类,继承自动画精灵
def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha() # 载入大敌机图片1
self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha() # 载入大敌机图片2
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成大敌机的活动范围
self.rect = self.enemy3_n1.get_rect() #获得大敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置大敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/enemy3_down1.png").convert_alpha(), \
pygame.image.load("image/enemy3_down2.png").convert_alpha(), \
pygame.image.load("image/enemy3_down3.png").convert_alpha(), \
pygame.image.load("image/enemy3_down4.png").convert_alpha(), \
pygame.image.load("image/enemy3_down5.png").convert_alpha(), \
pygame.image.load("image/enemy3_down6.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy3_n1) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): #大敌机的移动函数
if self.rect.top < self.height : #如果大飞机的底超出窗口的下边框
self.rect.top += self.speed #大飞机向下移动他的速度
else: #如果大飞机已经超出窗口的下边界框
self.reset() #重置大飞机
def reset(self): #重置大飞机函数
self.active = True # 表示飞机生存状态
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
def add_smallenemies(group1, group2, num):
for i in range(num):
e1 = SmallEnemy(bg_size, enemy1_image)
group1.add(e1)
group2.add(e1)
def add_middleenemies(group1, group2, num):
for i in range(num):
e2 = MiddleEnemy(bg_size, enemy2_image)
group1.add(e2)
group2.add(e2)
def add_bigenemies(group1, group2, num):
for i in range(num):
e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
group1.add(e3)
group2.add(e3)
def main():
me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
switch_image = True # 用于切换战机图片
delay = 100 # 用于延时
# 生成敌方飞机 定义精灵组,把生成的飞机放到这里
enemies = pygame.sprite.Group() # 生成整个飞机组
smallenemies = pygame.sprite.Group() # 生成小飞机组
add_smallenemies(smallenemies, enemies, 20) # 生成小型飞机
middleenemies = pygame.sprite.Group() # 生成中飞机组
add_middleenemies(middleenemies, enemies, 10) # 生成中型飞机
bigenemies = pygame.sprite.Group() # 生成大飞机组
add_bigenemies(bigenemies, enemies, 4) # 生成大型飞机
# 中弹图片索引
e1_destroy_index = 0
e2_destroy_index = 0
e3_destroy_index = 0
me_destroy_index = 0
running = True # 游戏执行状态
while running:
for event in pygame.event.get(): # 键盘操作
if event.type == QUIT:
sys.exit()
# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]: # 如果按下上键或者↑
me.moveup() # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]: # 如果按下下键或者↓
me.movedown() # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]: # 如果按下左键或者←
me.moveleft() # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]: # 如果按下右键或者→
me.moveright() # 飞船向右飞行
screen.blit(background, (0, 0)) # 绘制背景
# 绘制大型敌机
for each in bigenemies:
if each.active: # 如果大型敌机为生存状态
each.move()
if switch_image:
screen.blit(each.enemy3_n1, each.rect)
else:
screen.blit(each.enemy3_n2, each.rect)
# 即将出现在画面中,播放音效
if each.rect.bottom > -50:
enemy3_fly_sound.play()
else: # 毁灭
if not (delay % 3): # 设置两张照片转换的时间延时
# 只需要播放一次
if e3_destroy_index == 0:
enemy3_down_sound.play()
screen.blit(each.destroy_images[e3_destroy_index], each.rect)
e3_destroy_index = (e3_destroy_index + 1) % 6 # 循环播放爆炸图片
if e3_destroy_index == 0:
enemy3_fly_sound.stop() # 关闭声音
each.reset()
# 绘制中型敌机:
for each in middleenemies:
if each.active:
each.move()
screen.blit(each.enemy2, each.rect)
else:
# 毁灭
if not (delay % 3):
if e2_destroy_index == 0:
enemy2_down_sound.play()
screen.blit(each.destroy_images[e2_destroy_index], each.rect)
e2_destroy_index = (e2_destroy_index + 1) % 4 # 循环播放爆炸图片
if e2_destroy_index == 0:
each.reset()
# 绘制小型敌机:
for each in smallenemies:
if each.active:
each.move()
screen.blit(each.enemy1, each.rect)
else:
# 毁灭
if not(delay%3):
if e1_destroy_index == 0:
enemy1_down_sound.play()
screen.blit(each.destroy_images[e1_destroy_index], each.rect)
e1_destroy_index = (e1_destroy_index + 1)%4 # 循环播放爆炸图片
if e1_destroy_index == 0:
each.reset()
# 检测我方飞机和其他飞机发生碰撞 spritecollide矩形区域, pygame.sprite.collide_mask检测边缘碰撞
enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
if enemies_down:
me.active = False
for e in enemies_down:
e.active = False
# 绘制我方飞机
if me.active:
if switch_image: # 如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
else:
# 毁灭
if not (delay % 3):
if me_destroy_index == 0:
me_down_sound.play()
screen.blit(me.destroy_images[me_destroy_index], me.rect)
me_destroy_index = (me_destroy_index + 1) % 4 # 循环播放爆炸图片
if me_destroy_index == 0:
print("Game Over")
running = False
# 切换图片
if delay % 5 == 0:
switch_image = not switch_image
delay -= 1
if delay == 0:
delay = 100
pygame.display.flip() # 不停的刷新画面,不停的绘画
clock.tick(60) # 设置帧率
if __name__ == "__main__":
# 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
try:
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass
6.设置子弹
6.1 添加子弹类
写在敌机类的下面
########################### 子弹 ################################
class Bullet1(pygame.sprite.Sprite): #定义子弹类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, position,bullet1_image):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(bullet1_image).convert_alpha() # 加载子弹1图
self.rect = self.image.get_rect() # 获得子弹1图的尺寸
self.rect.left, self.rect.top = position # 把飞机的位置传给子弹
self.speed = 15 # 子弹运动的速度
self.avtive = True # 用来表示这颗子弹是或否失效
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
6.2 生成子弹
写在生成飞机下面
# 生成普通子弹
bullet1 = []
bullet1_index = 0
bullet_num = 4
for i in range(bullet_num):
bullet1.append(Bullet1(me.rect.midtop, bullet1_image)) # midtop表示顶部
6.3 设置子弹发射频率
# 发射子弹 每10桢绘制一次子弹
if not (delay % 10):
bullet1[bullet1_index].reset(me.rect.midtop)
bullet1_index = (bullet1_index + 1) % bullet_num
6.4 检测子弹是否击中敌机
for b in bullet1: # 对于列表中的的所有子弹
if b.active: # 如果子弹有效
b.move() # 子弹移动
screen.blit(b.image, b.rect) # 把子弹绘制在背景上
# 将所有与子弹发生碰撞的敌方飞机都加入到组中
enemies_hit = pygame.sprite.spritecollide(b, enemies, False,\
collided=pygame.sprite.collide_mask)
if enemies_hit: # 如果有敌机与子弹相碰
for e in enemies_hit: # 对于所有相撞的敌机
e.active = False # 将他们的状态设置为死亡
6.5 目前所写代码
from pygame.locals import *
from random import *
import traceback
import tkinter as tk # 制作GUI界面库
import pygame
import math
import sys
pygame.init() # 初始化
pygame.mixer.init() # 混音器初始化
clock = pygame.time.Clock() # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3") # 设置背景音乐
pygame.mixer.music.set_volume(1) # 设置音量
# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3") # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3") # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3") # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3") # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3") # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3") # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3") # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3") # 按键音效
myself_down_sound.set_volume(0.2)
"""图片文件路径"""
background_image = "image/background.png" # 背景图的路径
bullet1_image = "image/bullet1.png" # 第一种子弹图
enemy1_image = "image/enemy1.png" # 小敌机图片
enemy2_image = "image/enemy2.png" # 中敌机图片
enemy3_n1_image = "image/enemy3.png" # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png" # 大敌机图片2
me1_image = "image/hero1.png" # 自身飞机第一张图片
me2_image = "image/hero2.png" # 自身飞机第二张图片
# 设置背景
bg_size = width, height = 430, 700 # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size) # 这是背景大小
background = pygame.image.load(background_image).convert_alpha() # 画背景
pygame.mixer.music.play(-1) # 播放背景音乐,-1 表示无限循环播放
######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite): # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, bg_size,me1_image,me2_image):
self.me1_image = me1_image
self.me2_image = me2_image
self.image1 = pygame.image.load(me1_image).convert_alpha() # 第一张飞机图片
self.image2 = pygame.image.load(me2_image).convert_alpha() # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
self.rect = self.image1.get_rect() # 获得飞机图片的尺寸
self.width, self.height = bg_size[0], bg_size[1] # 设置飞机允许活动地点
self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
(self.height - self.rect.height - 20)] # 注意括号设置我方飞机出现的位置
self.speed = 10 # 设置飞机出现的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.image1) # 给类添加上mask属性,之后可以按照完美碰撞
def moveup(self): # 飞机向上飞的函数
if self.rect.top > 0: # 如果我方飞机没有飞出 上方边界
self.rect.top -= 10 # 那么我方飞机朝上飞10个像素
else: # 飞出 上方边界
self.rect.top = 0 # 锁定在0的位置,不再发生变化
def movedown(self): # 飞机向下飞的函数
if self.rect.bottom < (self.height - 20): # 如果我方飞机没有飞出 上方边界
self.rect.bottom += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.bottom = (self.height - 20) # 锁定在底边界上方60的位置,不再发生变化
def moveleft(self): # 飞机向左飞的函数
if self.rect.left > 0: # 如果我方飞机没有飞出 左方边界
self.rect.left -= 10 # 那么我方飞机朝下左10个像素
else: # 飞出 左方边界
self.rect.left = 0 # 锁定在左边界的位置,不再发生变化
def moveright(self): # 飞机向下飞的函数
if self.rect.right < self.width: # 如果我方飞机没有飞出 上方边界
self.rect.right += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.right = self.width # 锁定在底边界的位置,不再发生变化
####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite): #定义小敌机,继承自动画精灵
def __init__(self,bg_size,enemy1_image):
pygame.sprite.Sprite.__init__(self)
self.enemy1 = pygame.image.load(enemy1_image).convert_alpha() # 载入小敌机图片
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成小敌机的活动范围
self.rect = self.enemy1.get_rect() #获得低级敌机的尺寸
# 在窗口的5倍之上的距离中产生飞机
self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height , 0)]
self.speed = 2 # 设置小敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([\
pygame.image.load("image/enemy1_down1.png").convert_alpha(), \
pygame.image.load("image/enemy1_down2.png").convert_alpha(), \
pygame.image.load("image/enemy1_down3.png").convert_alpha(), \
pygame.image.load("image/enemy1_down4.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy1) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): # 小敌机的移动函数
if self.rect.top < self.height: #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else: #如果小飞机已经超出窗口的下边界框
self.reset() #重置小飞机
def reset(self): #重置小飞机函数
self.active = True # 飞机碰撞时写
# 在窗口的5倍之上的距离中产生飞机
self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height, 0)]
class MiddleEnemy(pygame.sprite.Sprite): #定义中敌机,继承自动画精灵
def __init__(self,bg_size,enemy2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy2 = pygame.image.load(enemy2_image).convert_alpha() #载入中级敌机照片
self.width,self.height = bg_size[0], bg_size[1] #获取生成低级敌机的活动范围
self.rect = self.enemy2.get_rect() #获得低级敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置中敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/enemy2_down1.png").convert_alpha(), \
pygame.image.load("image/enemy2_down2.png").convert_alpha(), \
pygame.image.load("image/enemy2_down3.png").convert_alpha(), \
pygame.image.load("image/enemy2_down4.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy2) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): #中敌机的移动函数
if self.rect.top < self.height : #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else : #如果小飞机已经超出窗口的下边界框
self.reset() #重置中飞机
def reset(self): #重置中飞机函数
self.active = True # 飞机碰撞时写
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
# 大敌机
class BigEnemy(pygame.sprite.Sprite): #定义大敌机类,继承自动画精灵
def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha() # 载入大敌机图片1
self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha() # 载入大敌机图片2
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成大敌机的活动范围
self.rect = self.enemy3_n1.get_rect() #获得大敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置大敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/enemy3_down1.png").convert_alpha(), \
pygame.image.load("image/enemy3_down2.png").convert_alpha(), \
pygame.image.load("image/enemy3_down3.png").convert_alpha(), \
pygame.image.load("image/enemy3_down4.png").convert_alpha(), \
pygame.image.load("image/enemy3_down5.png").convert_alpha(), \
pygame.image.load("image/enemy3_down6.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy3_n1) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): #大敌机的移动函数
if self.rect.top < self.height : #如果大飞机的底超出窗口的下边框
self.rect.top += self.speed #大飞机向下移动他的速度
else: #如果大飞机已经超出窗口的下边界框
self.reset() #重置大飞机
def reset(self): #重置大飞机函数
self.active = True # 飞机碰撞时写
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
########################### 子弹 ################################
class Bullet1(pygame.sprite.Sprite): #定义子弹类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, position, bullet1_image):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(bullet1_image).convert_alpha() # 加载子弹1图
self.rect = self.image.get_rect() # 获得子弹1图的尺寸
self.rect.left, self.rect.top = position # 把飞机的位置传给子弹
self.speed = 15 # 子弹运动的速度
self.active = True # 用来表示这颗子弹是或否失效
self.mask = pygame.mask.from_surface(self.image) # 给类添加上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
def add_smallenemies(group1, group2, num):
for i in range(num):
e1 = SmallEnemy(bg_size, enemy1_image)
group1.add(e1)
group2.add(e1)
def add_middleenemies(group1, group2, num):
for i in range(num):
e2 = MiddleEnemy(bg_size, enemy2_image)
group1.add(e2)
group2.add(e2)
def add_bigenemies(group1, group2, num):
for i in range(num):
e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
group1.add(e3)
group2.add(e3)
def main():
me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
switch_image = True # 用于切换战机图片
delay = 100 # 用于延时
# 生成敌方飞机 定义精灵组,把生成的飞机放到这里
enemies = pygame.sprite.Group() # 生成整个飞机组
smallenemies = pygame.sprite.Group() # 生成小飞机组
add_smallenemies(smallenemies, enemies, 20) # 生成小型飞机
middleenemies = pygame.sprite.Group() # 生成中飞机组
add_middleenemies(middleenemies, enemies, 10) # 生成中型飞机
bigenemies = pygame.sprite.Group() # 生成大飞机组
add_bigenemies(bigenemies, enemies, 4) # 生成大型飞机
# 生成普通子弹
bullet1 = []
bullet1_index = 0
bullet_num = 4
for i in range(bullet_num):
bullet1.append(Bullet1(me.rect.midtop, bullet1_image)) # midtop表示顶部
# 中弹图片索引
e1_destroy_index = 0
e2_destroy_index = 0
e3_destroy_index = 0
me_destroy_index = 0
running = True # 游戏执行状态
while running:
for event in pygame.event.get(): # 键盘操作
if event.type == QUIT:
sys.exit()
# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]: # 如果按下上键或者↑
me.moveup() # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]: # 如果按下下键或者↓
me.movedown() # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]: # 如果按下左键或者←
me.moveleft() # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]: # 如果按下右键或者→
me.moveright() # 飞船向右飞行
screen.blit(background, (0, 0)) # 绘制背景
# 绘制大型敌机
for each in bigenemies:
if each.active: # 如果大型敌机为生存状态
each.move()
if switch_image:
screen.blit(each.enemy3_n1, each.rect)
else:
screen.blit(each.enemy3_n2, each.rect)
# 即将出现在画面中,播放音效
if each.rect.bottom > -50:
enemy3_fly_sound.play()
else: # 毁灭
if not (delay % 3): # 设置两张照片转换的时间延时
# 只需要播放一次
if e3_destroy_index == 0:
enemy3_down_sound.play()
screen.blit(each.destroy_images[e3_destroy_index], each.rect)
e3_destroy_index = (e3_destroy_index + 1) % 6 # 循环播放爆炸图片
if e3_destroy_index == 0:
enemy3_fly_sound.stop() # 关闭声音
each.reset()
# 绘制中型敌机:
for each in middleenemies:
if each.active:
each.move()
screen.blit(each.enemy2, each.rect)
else:
# 毁灭
if not (delay % 3):
if e2_destroy_index == 0:
enemy2_down_sound.play()
screen.blit(each.destroy_images[e2_destroy_index], each.rect)
e2_destroy_index = (e2_destroy_index + 1) % 4 # 循环播放爆炸图片
if e2_destroy_index == 0:
each.reset()
# 绘制小型敌机:
for each in smallenemies:
if each.active:
each.move()
screen.blit(each.enemy1, each.rect)
else:
# 毁灭
if not(delay%3):
if e1_destroy_index == 0:
enemy1_down_sound.play()
screen.blit(each.destroy_images[e1_destroy_index], each.rect)
e1_destroy_index = (e1_destroy_index + 1)%4 # 循环播放爆炸图片
if e1_destroy_index == 0:
each.reset()
# 检测我方飞机和其他飞机发生碰撞 spritecollide矩形区域, pygame.sprite.collide_mask检测边缘碰撞
enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
if enemies_down:
me.active = False
for e in enemies_down:
e.active = False
# 发射子弹 每10桢绘制一次子弹
if not (delay % 10):
bullet1[bullet1_index].reset(me.rect.midtop)
bullet1_index = (bullet1_index + 1) % bullet_num
# 检测子弹是否击中敌机
for b in bullet1: # 对于列表中的的所有子弹
if b.active: # 如果子弹有效
b.move() # 子弹移动
screen.blit(b.image, b.rect) # 把子弹绘制在背景上
# 将所有与子弹发生碰撞的敌方飞机都加入到组中
enemies_hit = pygame.sprite.spritecollide(b, enemies, False,\
collided=pygame.sprite.collide_mask)
if enemies_hit: # 如果有敌机与子弹相碰
for e in enemies_hit: # 对于所有相撞的敌机
e.active = False # 将他们的状态设置为死亡
# 绘制我方飞机
if me.active:
if switch_image: # 如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
else:
# 毁灭
if not (delay % 3):
if me_destroy_index == 0:
me_down_sound.play()
screen.blit(me.destroy_images[me_destroy_index], me.rect)
me_destroy_index = (me_destroy_index + 1) % 4 # 循环播放爆炸图片
if me_destroy_index == 0:
print("Game Over")
running = False
# 切换图片
if delay % 5 == 0:
switch_image = not switch_image
delay -= 1
if delay == 0:
delay = 100
pygame.display.flip() # 不停的刷新画面,不停的绘画
clock.tick(60) # 设置帧率
if __name__ == "__main__":
# 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
try:
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass
7.生成血条
7.1 设置颜色
写在设置计时器下面
# 设置游戏名称
pygame.display.set_caption("飞机大战")
# RGB颜色
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
7.2 设置中大飞机血量
# 大飞机血量
energy = 20
# 中飞机血量
energy = 8
7.3 画中大飞机血条
大飞机
# 绘制血槽 红黑绿
pygame.draw.line(screen, BLACK, \
(each.rect.left, each.rect.top - 5), \
(each.rect.right, each.rect.top - 5), \
2)
# 当生命大于20%显示绿色,否则显示红色
energy_remain = each.energy / BigEnemy.energy
if energy_remain > 0.2:
energy_color = GREEN
else:
energy_color = RED
pygame.draw.line(screen, energy_color, \
(each.rect.left, each.rect.top - 5), \
(each.rect.left + each.rect.width * energy_remain, \
each.rect.top - 5), 2)
中飞机
# 绘制血槽 红黑绿
pygame.draw.line(screen, BLACK, \
(each.rect.left, each.rect.top - 5), \
(each.rect.right, each.rect.top - 5), \
2)
# 当生命大于20%显示绿色,否则显示红色
energy_remain = each.energy / MiddleEnemy.energy
if energy_remain > 0.2:
energy_color = GREEN
else:
energy_color = RED
pygame.draw.line(screen, energy_color, \
(each.rect.left, each.rect.top - 5), \
(each.rect.left + each.rect.width * energy_remain, \
each.rect.top - 5), 2)
7.4 设置掉血效果
# 检测子弹是否击中敌机
for b in bullet1: # 对于列表中的的所有子弹
if b.active: # 如果子弹有效
b.move() # 子弹移动
screen.blit(b.image, b.rect) # 把子弹绘制在背景上
enemies_hit = pygame.sprite.spritecollide(b, enemies, False,
collided=pygame.sprite.collide_mask) # 将所有与子弹发生碰撞的敌方飞机都加入到组中
if enemies_hit: # 如果有敌机与子弹相碰
b.active = False # 将碰撞后在子弹设置为未激活,使其消失,不再继续存在在画面中
for e in enemies_hit: # 对于所有相撞的敌机
# 中大型敌机
if e in middleenemies or e in bigenemies: # 如果敌机是中型飞机或者大型飞机
e.energy -= 1
if e.energy == 0: # 如果生命值变为0
e.active = False # 将敌机的生命属性设置为死亡
else:
# 小飞机
e.active = False
7.5 目前所写代码
from pygame.locals import *
from random import *
import traceback
import tkinter as tk # 制作GUI界面库
import pygame
import math
import sys
pygame.init() # 初始化
pygame.mixer.init() # 混音器初始化
clock = pygame.time.Clock() # 设置一个计时器
# 设置游戏名称
pygame.display.set_caption("飞机大战")
# RGB颜色
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3") # 设置背景音乐
pygame.mixer.music.set_volume(1) # 设置音量
# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3") # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3") # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3") # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3") # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3") # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3") # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3") # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3") # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3") # 按键音效
myself_down_sound.set_volume(0.2)
"""图片文件路径"""
background_image = "image/background.png" # 背景图的路径
bullet1_image = "image/bullet1.png" # 第一种子弹图
enemy1_image = "image/enemy1.png" # 小敌机图片
enemy2_image = "image/enemy2.png" # 中敌机图片
enemy3_n1_image = "image/enemy3.png" # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png" # 大敌机图片2
me1_image = "image/hero1.png" # 自身飞机第一张图片
me2_image = "image/hero2.png" # 自身飞机第二张图片
# 设置背景
bg_size = width, height = 430, 700 # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size) # 这是背景大小
background = pygame.image.load(background_image).convert_alpha() # 画背景
pygame.mixer.music.play(-1) # 播放背景音乐,-1 表示无限循环播放
######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite): # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, bg_size,me1_image,me2_image):
self.me1_image = me1_image
self.me2_image = me2_image
self.image1 = pygame.image.load(me1_image).convert_alpha() # 第一张飞机图片
self.image2 = pygame.image.load(me2_image).convert_alpha() # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
self.rect = self.image1.get_rect() # 获得飞机图片的尺寸
self.width, self.height = bg_size[0], bg_size[1] # 设置飞机允许活动地点
self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
(self.height - self.rect.height - 20)] # 注意括号设置我方飞机出现的位置
self.speed = 10 # 设置飞机出现的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.image1) # 给类添加上mask属性,之后可以按照完美碰撞
def moveup(self): # 飞机向上飞的函数
if self.rect.top > 0: # 如果我方飞机没有飞出 上方边界
self.rect.top -= 10 # 那么我方飞机朝上飞10个像素
else: # 飞出 上方边界
self.rect.top = 0 # 锁定在0的位置,不再发生变化
def movedown(self): # 飞机向下飞的函数
if self.rect.bottom < (self.height - 20): # 如果我方飞机没有飞出 上方边界
self.rect.bottom += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.bottom = (self.height - 20) # 锁定在底边界上方60的位置,不再发生变化
def moveleft(self): # 飞机向左飞的函数
if self.rect.left > 0: # 如果我方飞机没有飞出 左方边界
self.rect.left -= 10 # 那么我方飞机朝下左10个像素
else: # 飞出 左方边界
self.rect.left = 0 # 锁定在左边界的位置,不再发生变化
def moveright(self): # 飞机向下飞的函数
if self.rect.right < self.width: # 如果我方飞机没有飞出 上方边界
self.rect.right += 10 # 那么我方飞机朝下飞10个像素
else: # 飞出 下方边界
self.rect.right = self.width # 锁定在底边界的位置,不再发生变化
####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite): #定义小敌机,继承自动画精灵
def __init__(self,bg_size,enemy1_image):
pygame.sprite.Sprite.__init__(self)
self.enemy1 = pygame.image.load(enemy1_image).convert_alpha() # 载入小敌机图片
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成小敌机的活动范围
self.rect = self.enemy1.get_rect() #获得低级敌机的尺寸
# 在窗口的5倍之上的距离中产生飞机
self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height , 0)]
self.speed = 2 # 设置小敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([\
pygame.image.load("image/enemy1_down1.png").convert_alpha(), \
pygame.image.load("image/enemy1_down2.png").convert_alpha(), \
pygame.image.load("image/enemy1_down3.png").convert_alpha(), \
pygame.image.load("image/enemy1_down4.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy1) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): # 小敌机的移动函数
if self.rect.top < self.height: #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else: #如果小飞机已经超出窗口的下边界框
self.reset() #重置小飞机
def reset(self): #重置小飞机函数
self.active = True # 飞机碰撞时写
# 在窗口的5倍之上的距离中产生飞机
self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
randint(-5*self.height, 0)]
class MiddleEnemy(pygame.sprite.Sprite): #定义中敌机,继承自动画精灵
energy = 8
def __init__(self,bg_size,enemy2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy2 = pygame.image.load(enemy2_image).convert_alpha() #载入中级敌机照片
self.width,self.height = bg_size[0], bg_size[1] #获取生成低级敌机的活动范围
self.rect = self.enemy2.get_rect() #获得低级敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置中敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/enemy2_down1.png").convert_alpha(), \
pygame.image.load("image/enemy2_down2.png").convert_alpha(), \
pygame.image.load("image/enemy2_down3.png").convert_alpha(), \
pygame.image.load("image/enemy2_down4.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy2) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): #中敌机的移动函数
if self.rect.top < self.height : #如果小飞机的底超出窗口的下边框
self.rect.top += self.speed #小飞机向下移动他的速度
else : #如果小飞机已经超出窗口的下边界框
self.reset() #重置中飞机
def reset(self): #重置中飞机函数
self.energy = 8
self.active = True # 飞机碰撞时写
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
# 大敌机
class BigEnemy(pygame.sprite.Sprite): #定义大敌机类,继承自动画精灵
energy = 20
def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
pygame.sprite.Sprite.__init__(self)
self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha() # 载入大敌机图片1
self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha() # 载入大敌机图片2
self.width, self.height = bg_size[0] , bg_size[1] # 获取生成大敌机的活动范围
self.rect = self.enemy3_n1.get_rect() #获得大敌机的尺寸
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5*self.height, 0)] #在窗口的5倍之上的距离中产生飞机
self.speed = 1 #设置大敌机移动的速度
# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
pygame.image.load("image/enemy3_down1.png").convert_alpha(), \
pygame.image.load("image/enemy3_down2.png").convert_alpha(), \
pygame.image.load("image/enemy3_down3.png").convert_alpha(), \
pygame.image.load("image/enemy3_down4.png").convert_alpha(), \
pygame.image.load("image/enemy3_down5.png").convert_alpha(), \
pygame.image.load("image/enemy3_down6.png").convert_alpha()])
self.active = True # 表示飞机生存状态
self.mask = pygame.mask.from_surface(self.enemy3_n1) # 给类添加上mask属性,之后可以按照完美碰撞
def move(self): #大敌机的移动函数
if self.rect.top < self.height : #如果大飞机的底超出窗口的下边框
self.rect.top += self.speed #大飞机向下移动他的速度
else: #如果大飞机已经超出窗口的下边界框
self.reset() #重置大飞机
def reset(self): #重置大飞机函数
self.energy = 20
self.active = True # 飞机碰撞时写
self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
randint(-5 * self.height, 0)] # 在窗口的5倍之上的距离中产生飞机
########################### 子弹 ################################
class Bullet1(pygame.sprite.Sprite): #定义子弹类,继承动画精灵类(因为之后要进行碰撞检测)
def __init__(self, position, bullet1_image):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(bullet1_image).convert_alpha() # 加载子弹1图
self.rect = self.image.get_rect() # 获得子弹1图的尺寸
self.rect.left, self.rect.top = position # 把飞机的位置传给子弹
self.speed = 15 # 子弹运动的速度
self.active = True # 用来表示这颗子弹是或否失效
self.mask = pygame.mask.from_surface(self.image) # 给类添加上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
def add_smallenemies(group1, group2, num):
for i in range(num):
e1 = SmallEnemy(bg_size, enemy1_image)
group1.add(e1)
group2.add(e1)
def add_middleenemies(group1, group2, num):
for i in range(num):
e2 = MiddleEnemy(bg_size, enemy2_image)
group1.add(e2)
group2.add(e2)
def add_bigenemies(group1, group2, num):
for i in range(num):
e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
group1.add(e3)
group2.add(e3)
def main():
me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
switch_image = True # 用于切换战机图片
delay = 100 # 用于延时
# 生成敌方飞机 定义精灵组,把生成的飞机放到这里
enemies = pygame.sprite.Group() # 生成整个飞机组
smallenemies = pygame.sprite.Group() # 生成小飞机组
add_smallenemies(smallenemies, enemies, 20) # 生成小型飞机
middleenemies = pygame.sprite.Group() # 生成中飞机组
add_middleenemies(middleenemies, enemies, 10) # 生成中型飞机
bigenemies = pygame.sprite.Group() # 生成大飞机组
add_bigenemies(bigenemies, enemies, 4) # 生成大型飞机
# 生成普通子弹
bullet1 = []
bullet1_index = 0
bullet_num = 4
for i in range(bullet_num):
bullet1.append(Bullet1(me.rect.midtop, bullet1_image)) # midtop表示顶部
# 中弹图片索引
e1_destroy_index = 0
e2_destroy_index = 0
e3_destroy_index = 0
me_destroy_index = 0
running = True # 游戏执行状态
while running:
for event in pygame.event.get(): # 键盘操作
if event.type == QUIT:
sys.exit()
# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]: # 如果按下上键或者↑
me.moveup() # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]: # 如果按下下键或者↓
me.movedown() # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]: # 如果按下左键或者←
me.moveleft() # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]: # 如果按下右键或者→
me.moveright() # 飞船向右飞行
screen.blit(background, (0, 0)) # 绘制背景
# 绘制大型敌机
for each in bigenemies:
if each.active: # 如果大型敌机为生存状态
each.move()
if switch_image:
screen.blit(each.enemy3_n1, each.rect)
else:
screen.blit(each.enemy3_n2, each.rect)
# 绘制血槽 红黑绿
pygame.draw.line(screen, BLACK, \
(each.rect.left, each.rect.top - 5), \
(each.rect.right, each.rect.top - 5), \
2)
# 当生命大于20%显示绿色,否则显示红色
energy_remain = each.energy / BigEnemy.energy
if energy_remain > 0.2:
energy_color = GREEN
else:
energy_color = RED
pygame.draw.line(screen, energy_color, \
(each.rect.left, each.rect.top - 5), \
(each.rect.left + each.rect.width * energy_remain, \
each.rect.top - 5), 2)
# 即将出现在画面中,播放音效
if each.rect.bottom > -50:
enemy3_fly_sound.play()
else: # 毁灭
if not (delay % 3): # 设置两张照片转换的时间延时
# 只需要播放一次
if e3_destroy_index == 0:
enemy3_down_sound.play()
screen.blit(each.destroy_images[e3_destroy_index], each.rect)
e3_destroy_index = (e3_destroy_index + 1) % 6 # 循环播放爆炸图片
if e3_destroy_index == 0:
enemy3_fly_sound.stop() # 关闭声音
each.reset()
# 绘制中型敌机:
for each in middleenemies:
if each.active:
each.move()
screen.blit(each.enemy2, each.rect)
# 绘制血槽 红黑绿
pygame.draw.line(screen, BLACK, \
(each.rect.left, each.rect.top - 5), \
(each.rect.right, each.rect.top - 5), \
2)
# 当生命大于20%显示绿色,否则显示红色
energy_remain = each.energy / MiddleEnemy.energy
if energy_remain > 0.2:
energy_color = GREEN
else:
energy_color = RED
pygame.draw.line(screen, energy_color, \
(each.rect.left, each.rect.top - 5), \
(each.rect.left + each.rect.width * energy_remain, \
each.rect.top - 5), 2)
else:
# 毁灭
if not (delay % 3):
if e2_destroy_index == 0:
enemy2_down_sound.play()
screen.blit(each.destroy_images[e2_destroy_index], each.rect)
e2_destroy_index = (e2_destroy_index + 1) % 4 # 循环播放爆炸图片
if e2_destroy_index == 0:
each.reset()
# 绘制小型敌机:
for each in smallenemies:
if each.active:
each.move()
screen.blit(each.enemy1, each.rect)
else:
# 毁灭
if not(delay%3):
if e1_destroy_index == 0:
enemy1_down_sound.play()
screen.blit(each.destroy_images[e1_destroy_index], each.rect)
e1_destroy_index = (e1_destroy_index + 1)%4 # 循环播放爆炸图片
if e1_destroy_index == 0:
each.reset()
# 检测我方飞机和其他飞机发生碰撞 spritecollide矩形区域, pygame.sprite.collide_mask检测边缘碰撞
enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
if enemies_down:
me.active = False
for e in enemies_down:
e.active = False
# 发射子弹 每10桢绘制一次子弹
if not (delay % 10):
bullet1[bullet1_index].reset(me.rect.midtop)
bullet1_index = (bullet1_index + 1) % bullet_num
# 检测子弹是否击中敌机
for b in bullet1: # 对于列表中的的所有子弹
if b.active: # 如果子弹有效
b.move() # 子弹移动
screen.blit(b.image, b.rect) # 把子弹绘制在背景上
enemies_hit = pygame.sprite.spritecollide(b, enemies, False,
collided=pygame.sprite.collide_mask) # 将所有与子弹发生碰撞的敌方飞机都加入到组中
if enemies_hit: # 如果有敌机与子弹相碰
b.active = False # 将碰撞后在子弹设置为未激活,使其消失,不再继续存在在画面中
for e in enemies_hit: # 对于所有相撞的敌机
# 中大型敌机
if e in middleenemies or e in bigenemies: # 如果敌机是中型飞机或者大型飞机
e.energy -= 1
if e.energy == 0: # 如果生命值变为0
e.active = False # 将敌机的生命属性设置为死亡
else:
# 小飞机
e.active = False
# 绘制我方飞机
if me.active:
if switch_image: # 如果改变属性为真 画第一张飞机图
screen.blit(me.image1, me.rect)
else: # 2如果改变属性为假 画第二张飞机图
screen.blit(me.image2, me.rect)
else:
# 毁灭
if not (delay % 3):
if me_destroy_index == 0:
me_down_sound.play()
screen.blit(me.destroy_images[me_destroy_index], me.rect)
me_destroy_index = (me_destroy_index + 1) % 4 # 循环播放爆炸图片
if me_destroy_index == 0:
print("Game Over")
running = False
# 切换图片
if delay % 5 == 0:
switch_image = not switch_image
delay -= 1
if delay == 0:
delay = 100
pygame.display.flip() # 不停的刷新画面,不停的绘画
clock.tick(60) # 设置帧率
if __name__ == "__main__":
# 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
try:
print()
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass