摘要
本项目基于pygame,实现了飞机大战小游戏。Pygame是python的一个package,是一个经典的游戏制作包,可以完成大部分2D游戏制作。Pygame模块可通过在CMD上运行pip install pygame安装。飞机大战主要是通过击杀敌方飞机增加分数,躲避敌方攻击,若被敌方攻击到或者撞击,会导致游戏结束,停止程序运行。
1、引言
本项目基于pygame模块,通过编写飞机大战这游戏,提升自己对pygame等模块的应用能力和编程能力的提升。飞机大战主要是通过击杀敌方飞机加分数,躲避敌方攻击,若己方飞机被敌方攻击到或者撞击,会导致游戏结束,停止程序运行。
2、系统结构:
(1)开发环境:python3.6(python3.0+)
(2)相关模块:
import pygame
import simpleaudio as sa #用于.wav音乐文件
from pygame.locals import * #按键
import time,random
(3)原理:利用pygame模块搭建游戏屏幕大小、背景,按键控制己方飞机移动、攻击,己方子弹位置与敌方飞机重叠,敌方飞机销毁。当己方飞机位置与敌方飞机位置重叠或者敌方子弹位置和己方飞机位置重叠,游戏结束。
(4)Pygame模块主框架:
set_mode():设置显示的尺寸大小,窗口模式,颜色位数(一般最好32)
updata():更新屏幕,提高游戏流畅
imge.load():从文件中加载图片
mixer.music的方法:打开音乐文件,设置音乐声音大小,播放音乐文件
pygame.mixer.music.load
pygame.mixer.music.set_volume(0.8) # 设置音量大小 0.0 ~ 1.0
pygame.mixer.music.play()
key:按键控制己方飞机移动和攻击
surface.blit(source,dest):将所需对象渲染到屏幕上,source为要渲染的对象,dest是位置(x,y),在游戏中用于计分数
(5)游戏中所需要的音乐、及其飞机模型
(6)打包成exe文件
3、实现代码:
己方飞机攻击声音,双方飞机销毁声音:
#我方,敌方被击败的声音
exp = sa.WaveObject.from_wave_file('./bgm/explosion.wav')
#我方攻击的声音
laser = sa.WaveObject.from_wave_file('./bgm/laser.wav')
构造游戏显示屏幕和游戏音乐:
screen=pygame.display.set_mode((512,568),0,32) #屏幕大小,屏幕模式,颜色位数
pygame.mixer.init()
pygame.mixer.music.load('./bgm/Casual Friday.mp3')
pygame.mixer.music.set_volume(0.8) # 设置音量大小 0.0 ~ 1.0
pygame.mixer.music.play()
background=pygame.image.load("./images/bg2.jpg")
定义己方飞机类(起始位置,飞机模型,判断是否爆炸,爆炸效果,移动方式、按键,如何爆炸,碰撞;其中,飞机爆炸效果是通过三张图片的演示完成的):
class HeroPlane:
# 定义玩家飞机
def __init__(self,screen_temp):
self.x=200
self.y=400
self.screen=screen_temp
self.image=pygame.image.load("./images/me.png")
self.hit=False # 表示是否要爆炸
self.bomb_picture_list=[] #用来存放爆炸时需要的图片
self.image_picture_num=4 #飞机爆炸效果的图片数量
self.picture_count = 0 #用来记录while true的次数,当次数达到一定值时,才显示一张爆炸的图,然后清空。当这个次数再次达到时,再显示下一个爆炸效果的图片
self.image_index=0 #用来记录当前要显示的爆炸效果的图片的序号
self.bullet_list=[] #用于存放玩家的子弹列表
self.crate_images()
self.delete=False
#这个display是飞机类的
def display(self):
# 绘制玩家发射的子弹
for bo in self.bullet_list:
# 在按空格前(发射子弹前),这个b.display函数是不存在的(哪怕写错也无所谓),
# 在按空格前(发射子弹后),这个b.display函数是子弹类的(因为传入的是子弹类元组)
bo.display()
if bo.move():
self.bullet_list.remove(bo)
# 绘制玩家飞机爆炸情况
if self.hit==True and self.image_index < 4: # 绘制玩家飞机爆炸情况
self.screen.blit(self.bomb_picture_list[self.image_index],(self.x,self.y))
self.picture_count+=1
if self.picture_count==4:
self.picture_count=0
self.image_index+=1
else:
self.screen.blit(self.image,(self.x,self.y)) # 绘制玩家正常飞机情况
if self.hit==True and self.image_index >= 4:
self.delete=True
#创建出爆炸效果的图片的引用
def crate_images(self):
for i in range(1, 5):
self.bomb_picture_list.append(pygame.image.load("./images/hero_blowup_n" + str(i) + ".png"))
def move_left(self): #向左移动
self.x=self.x-10
if self.x<=0:
self.x=0
def move_right(self): #向右移动
self.x=self.x+10
if self.x>=406:
self.x=406
def move_up(self): #向前移动
self.y=self.y-10
if self.y<=0:
self.y=0
def move_down(self): #向后移动
self.y=self.y+10
if self.y>=512:
self.y=512
def fire(self):
self.bullet_list.append(HeroBullet(self.screen,self.x,self.y))
print(len(self.bullet_list))
def ishitted(self,enemy):
#遍历所有子弹,并执行碰撞检测
for bo in enemy.bullet_list:
if bo.x>self.x+12 and bo.x <self.x+92 and bo.y>self.y+20 and bo.y<self.y+60:
enemy.bullet_list.remove(bo)
exp.play()
self.hit=True
定义敌方飞机类(起始位置,飞机模型,判断是否爆炸,爆炸效果,移动方式如何爆炸,碰撞,得分,判断飞机是否越界;其中,飞机爆炸效果是通过三张图片的演示完成的):
class EnemyPlane:
def __init__(self,screen_temp):
self.x=random.choice(range(408))
self.y=-75
self.screen=screen_temp
self.image=pygame.image.load("./images/e"+str(random.choice(range(3))) +".png")
self.bullet_list=[] #用于存放敌机的子弹列表
self.hit=False # 表示是否要爆炸
self.bomb_picture_list=[] #用来存放爆炸时需要的图片
self.image_picture_num=4 #飞机爆炸效果的图片数量
self.picture_count = 0 #用来记录while true的次数,当次数达到一定值时,才显示一张爆炸的图,然后清空。当这个次数再次达到时,再显示下一个爆炸效果的图片
self.image_index=0 #用来记录当前要显示的爆炸效果的图片的序号
self.crate_images()
self.plane_score = 0# 得分
self.delete=False
def display(self):
#绘制子弹
for bo in self.bullet_list:
bo.display()
if bo.move():
self.bullet_list.remove(bo)
#绘制敌机爆炸情况
if self.hit==True and self.image_index <4:
self.screen.blit(self.bomb_picture_list[self.image_index],(self.x+20,self.y))
self.picture_count += 1
if self.picture_count==4:
self.picture_count=0
self.image_index+=1
else:
self.screen.blit(self.image,(self.x,self.y))
if self.hit==True and self.image_index >= 4:
self.delete=True
#创建出爆炸效果的图片的引用
def crate_images(self):
for i in range(1, 5):
self.bomb_picture_list.append(pygame.image.load("./images/enemy1_down" + str(i) + ".png"))
def move(self):
self.y=self.y+5
if self.y>512: # 判断敌机是否越界
return True
def fire(self):
if random.choice(range(13))==6:
self.bullet_list.append(EnemyBullet(self.screen,self.x,self.y))
def ishitted(self,hero):
#遍历所有子弹,并执行碰撞检测
for bo in hero.bullet_list:
if bo.x>self.x+12 and bo.x <self.x+92 and bo.y>self.y+20 and bo.y<self.y+60:
hero.bullet_list.remove(bo)
exp.play()
self.hit=True
# 定义我方子弹类
子弹类(己方子弹样式,移动方式;敌方子弹样式,移动方式):
class HeroBullet:
def __init__(self,screen_temp,x,y):
self.x=x+53
self.y=y
self.screen=screen_temp
self.image=pygame.image.load("./images/pd.png")
def display(self):
self.screen.blit(self.image,(self.x,self.y))
def move(self):
self.y=self.y-10
if self.y<-20:
return True
class EnemyBullet:
# 定义敌方子弹类
def __init__(self,screen_temp,x,y):
self.x=x+53
self.y=y
self.screen=screen_temp
self.image=pygame.image.load("./images/pd2.png")
def display(self):
self.screen.blit(self.image,(self.x,self.y))
def move(self):
self.y=self.y+10
if self.y>568:
return True
按键鼠标控制(按键控制己方飞机移动和攻击,键盘上下左右和WASD控制移动,space键控制攻击;鼠标可以直接关闭游戏或者最小化游戏)):
def key_control(hero_temp): # 关于按键的鼠标,键盘
# 鼠标控制
for event in pygame.event.get():
if event.type==QUIT:
print("exit")
exit()
# 键盘控制
pressed_keys=pygame.key.get_pressed()
if pressed_keys[K_LEFT] or pressed_keys[K_a]:
hero_temp.move_left()
elif pressed_keys[K_RIGHT] or pressed_keys[K_d]:
hero_temp.move_right()
elif pressed_keys[K_UP] or pressed_keys[K_w]:
hero_temp.move_up()
elif pressed_keys[K_DOWN] or pressed_keys[K_s]:
hero_temp.move_down()
if pressed_keys[K_SPACE]:
print("space...")
laser.play()
hero_temp.fire()
主程序,设定屏幕大小,游戏开始声音,双方飞机的产生、绘制以及敌方飞机和我方飞机销毁后情况,同时击败敌方飞机后计分数以及计分数所在屏幕的位置:
def main():
screen=pygame.display.set_mode((512,568),0,32) #屏幕大小,屏幕模式,颜色位数
pygame.mixer.init()
pygame.mixer.music.load('./bgm/Casual Friday.mp3')
pygame.mixer.music.set_volume(0.8) # 设置音量大小 0.0 ~ 1.0
pygame.mixer.music.play()
background=pygame.image.load("./images/bg2.jpg")
pygame.init()
# 得分
score_font = pygame.font.SysFont('arial', 36) # 字体
hero=HeroPlane(screen) # 创建玩家飞机
enemy = EnemyPlane(screen)# 创建敌方飞机
m=-888
enemylist=[] #存放敌机列表
while True:
screen.blit(background,(0,m))#图像 绘制位置
score_text = score_font.render("Score : %s" % str(enemy.plane_score), True, (255, 255, 255))
screen.blit(score_text, (215,10))
m=m+2
if m>100:
m=-888
# 绘制玩家飞机
hero.display()
key_control(hero)
# 随机绘制敌机
if random.choice(range(50))==10:
enemylist.append(EnemyPlane(screen))
# 遍历所有敌机,显示敌机
for em in enemylist:
em.display()
em.fire()
if em.move():
enemylist.remove(em)
em.ishitted(hero)
if em.delete==True:
enemylist.remove(em)
enemy.plane_score += 10
hero.ishitted(em)
if hero.delete==True:
time.sleep(1)
exit()
pygame.display.update() #更新屏幕显示
time.sleep(0.03)
if __name__=="__main__":
main()
4、实验结果:
5、总结与展望
打包成exe文件时,字体不能设置成 None ,应该是‘arial’,否则打包成的exe文件会黑屏,停止工作,且程序所需要的资源(音乐,图片)应该复制到exe同个目录下。
本次项目提高了自己对pygame模块的理解,增强了对2D游戏制作的能力,本项目功能相对简单,不难理解。本项目不足之处功能没有完善,还能再此基础上增加,进入游戏界面,游戏暂停,选择难度,更换背景等功能。