飞机大战
- 1.main类
- 2.配置类
- 3.游戏主类
- 4.游戏资源类
- 5.资源下载
- 6.游戏效果
1.main类
启动游戏。
from MainWindow import MainWindow
if __name__ == '__main__':
app=MainWindow()
app.run()
2.配置类
该类主要存放游戏的各种设置参数。
#窗口尺寸
import random
import pygame
WINDOW=pygame.Rect(0,0,512,768)#图片资源大小刚好是512*768
#窗口名字
WINDOW_NAME="飞机大战v1.0"
#地图索引
MAP_INDEX=random.randint(1,5)
#英雄子弹类型
HERO_BULLET_INDEX=1
#敌人子弹类型
ENEMY_BULLET_INDEX=3
#敌机事件
ENEMY_EVENT=pygame.USEREVENT#pygame用户事件(整型),有多个事件可以在后面+1以区分
#英雄子弹事件
BULLET_EVENT=pygame.USEREVENT+1#+1区分事件
#敌机子弹事件
BULLET_ENEMY_EVENT=pygame.USEREVENT+2#+2区分事件
#英雄移动速度
HERO_MOVE_SPEED=4
#英雄子弹移动速度
HERO_BULLET_MOVE_SPEED=4
3.游戏主类
游戏主类主要由游戏窗口创建、精灵和精灵组的创建、游戏启动函数(1.碰撞检测、2.事件处理、3.精灵组更新、4.窗口刷新)等构成。
import pygame
from Config import *
from GameSprite import *
class MainWindow:
def __init__(self):
pygame.init()
#游戏窗口初始化
self.window=pygame.display.set_mode([WINDOW.width,WINDOW.height])
pygame.display.set_caption(WINDOW_NAME)
#背景音乐
pygame.mixer.music.load("./source/music/bg.wav")
pygame.mixer.music.set_volume(0.1)
pygame.mixer.music.play(-1)
#爆炸音效
self.bomb=pygame.mixer.Sound("./source/music/bomb.wav")
self.bomb.set_volume(0.2)
#游戏分数
self.kill_enemys=0
self.hp=100
#FPS时钟
self.clock=pygame.time.Clock()
#激活敌机定时器,参数:事件、间隔时间ms
pygame.time.set_timer(ENEMY_EVENT,500)
# 激活英雄子弹定时器,参数:事件、间隔时间ms
pygame.time.set_timer(BULLET_EVENT,500)
pygame.time.set_timer(BULLET_ENEMY_EVENT,2000)
#创建精灵组
self.create_sprite_group()
#精灵组创建
def create_sprite_group(self):
#地图精灵组
map1=GameMap()
map2=GameMap(True)
self.map_group=pygame.sprite.Group(map1,map2)
#英雄精灵
self.hero=Hero()
self.hero_group=pygame.sprite.Group(self.hero)
#敌机精灵组
self.enemy_group=pygame.sprite.Group()
#英雄子弹精灵组
self.bullet_group=pygame.sprite.Group()
#敌机子弹精灵组
self.bullet_enemy_group=pygame.sprite.Group()
#爆炸动画精灵组
self.bomb_group=pygame.sprite.Group()
# 碰撞检测
def collie_check(self):
#1.英雄子弹与敌机
for bullet1 in self.bullet_group:
#第一个参数是精灵、第二个参数是精灵组、第三个参数为是否删除与该精灵碰撞的所有精灵;返回值为与第一个参数碰撞的所有精灵列表
eys=pygame.sprite.spritecollide(bullet1,self.enemy_group,True)#判断子弹精灵是否与敌机精灵组有碰撞,有则杀死所有敌机
#表示有碰撞
if len(eys)>0:
self.bomb.play()#发生碰撞,播放爆炸音效
self.kill_enemys+=1#记录杀死的敌机数量
bullet1.kill()#杀死发生碰撞的子弹精灵
bomb_enemy=Bomb(eys[0])#将发生碰撞的敌传入爆炸类,方便使用爆炸的具体位置
self.bomb_group.add(bomb_enemy)#加入爆炸精灵组
#2.敌机子弹与英雄
bullet2=pygame.sprite.spritecollide(self.hero,self.bullet_enemy_group,True)
if len(bullet2)>0:
self.bomb.play()#发生碰撞,播放爆炸音效
self.hp-=1#英雄与敌机子弹接触,自身HP值-1
#敌机与英雄
enemys=pygame.sprite.spritecollide(self.hero,self.enemy_group,True)
if len(enemys)>0:
self.bomb.play()#发生碰撞,播放爆炸音效
self.hp-=2#英雄与敌机接触,自身HP值-2
bomb_enemy2 = Bomb(enemys[0])#将发生碰撞的敌传入爆炸类,方便使用爆炸的具体位置
self.bomb_group.add(bomb_enemy2)#加入爆炸精灵组
pass
# 更新精灵组位置并绘制
def sprite_group_update_draw(self):
#地图精灵组更新
self.map_group.update()
self.map_group.draw(self.window)
#英雄精灵组更新
self.hero_group.update()
self.hero_group.draw(self.window)
#敌机精灵组更新
self.enemy_group.update()
self.enemy_group.draw(self.window)
#英雄子弹精灵组
self.bullet_group.update()
self.bullet_group.draw(self.window)
#敌机子弹精灵组
self.bullet_enemy_group.update()
self.bullet_enemy_group.draw(self.window)
#爆炸精灵组
self.bomb_group.update()
self.bomb_group.draw(self.window)
#绘制数据 #游戏数据
font=pygame.font.Font("./source/fonts/SimHei.ttf")#pygame不能直接绘制中文,先导入字体文件
text=f"得分:{self.kill_enemys} HP:{self.hp} "#编辑需要绘制的字符串
self.text=font.render(text,True,(255,255,255))#渲染的文字,抗锯齿,颜色
self.window.blit(self.text,[WINDOW.width/2,20])#blit()函数绘制,将text当做图片处理
#英雄生命值为0退出游戏
if self.hp==0:
pygame.quit()
# 事件处理
def handle_events(self):
#pygame.event.get()获取当前时间帧的所有事件,返回一个事件列表,可以对此列表遍历
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
#用户事件1,固定时间生成敌机(时间可以在窗口初始化代码中修改)
if event.type==pygame.USEREVENT:
self.enemy=Enemy()
self.enemy_group.add(self.enemy)
#用户事件2,固定时间生成敌机子弹(时间可以在窗口初始化代码中修改)
if event.type==pygame.USEREVENT+2:
#固定时间生成敌机子弹,需要遍历敌机精灵组,获取所有已经存在的敌机精灵,在对应的位置上绘制敌机子弹
for enemy_sprite in self.enemy_group:
self.bullet_enemy = Bullet(enemy_sprite.speed + 1,True)
self.bullet_enemy.rect.centerx = enemy_sprite.rect.centerx
self.bullet_enemy.rect.y =enemy_sprite.rect.bottom
#将敌机子弹精灵添加到敌机子弹精灵组
self.bullet_enemy_group.add(self.bullet_enemy)
#用户事件3,固定时间生成英雄子弹(时间可以在窗口初始化代码中修改)
if event.type==pygame.USEREVENT+1:
self.bullet_hero=Bullet(-HERO_BULLET_MOVE_SPEED)#英雄子弹飞行方向与敌机子弹飞行方向相反
#根据英雄的当前位置来设置英雄子弹的位置
self.bullet_hero.rect.centerx=self.hero.rect.centerx
self.bullet_hero.rect.y=self.hero.rect.y-self.bullet_hero.rect.height
# 将英雄飞机子弹精灵添加到英雄子弹精灵组
self.bullet_group.add(self.bullet_hero)
#pygame.key.get_pressed()获取当前时间帧的所有键盘事件并返回一个列表,遍历列表控制英雄上下左右移动
keys_event=pygame.key.get_pressed()
if keys_event[pygame.K_a] or keys_event[pygame.K_LEFT]:
self.hero.x_speed=-HERO_MOVE_SPEED
elif keys_event[pygame.K_d] or keys_event[pygame.K_RIGHT]:
self.hero.x_speed=HERO_MOVE_SPEED
else:
self.hero.x_speed = 0
if keys_event[pygame.K_w] or keys_event[pygame.K_UP]:
self.hero.y_speed=-HERO_MOVE_SPEED
elif keys_event[pygame.K_s] or keys_event[pygame.K_DOWN]:
self.hero.y_speed=HERO_MOVE_SPEED
else:
self.hero.y_speed=0
#游戏主框架
def run(self):
while True:
#碰撞检测
self.collie_check()
#事件处理
self.handle_events()
#更新精灵组
self.sprite_group_update_draw()
#窗口刷新
pygame.display.update()
self.clock.tick(60)#FPS
4.游戏资源类
游戏资源类主要包括各种游戏相关元素精灵、主要有基础精灵类、敌机精灵类、子弹精灵类、英雄飞机精灵类、爆炸动画精灵类等。
import pygame
from Config import *
import random
#精灵类————基类,定义了基本的导入图片操作,以及图片垂直移动操作
class GameSprite(pygame.sprite.Sprite):
def __init__(self,image_url,speed=0):
super().__init__()
self.image=pygame.image.load(image_url)
self.rect=self.image.get_rect()
self.speed=speed
def update(self, *args, **kwargs):
self.rect.y+=self.speed
#游戏地图类,地图由两张完全一样的图片拼接构成,其中两张图片的起始和末尾要无缝衔接
#第一张图片起始位置与窗口完全重合,第二张图片的起始位置在第一张图片的上方
class GameMap(GameSprite):
#is_1表示是否是第二张图片
def __init__(self,is_1=False):
#地图给了5张,保证地图索引在1~5,否则随机给一个1~5
self.map_index=MAP_INDEX if 1<=MAP_INDEX<=5 else random.randint(1,5)
map_filename=f"./source/map/map-{self.map_index}.jpg"
super().__init__(map_filename,2)
if is_1:
self.rect.y=-WINDOW.height#第二张图片的起始位置在第一张图片的上方
def update(self):
#更新图像的位置
super().update()
#如果地图图片完全运动到了窗口最下方,就将这张图片的位置移动到窗口的最上方,作为新的起始位置
if self.rect.y>=WINDOW.height:
self.rect.y=-WINDOW.height
#英雄飞机类,初始化定义比较简单
class Hero(GameSprite):
def __init__(self):
super().__init__("./source/plane/hero.png")
#定义英雄飞机出生在窗口中的具体位置
self.rect.centerx=WINDOW.centerx
self.rect.y=WINDOW.height-120
#初始移动速度为0,静止状态
self.x_speed=0
self.y_speed=0
def update(self, *args, **kwargs):
#水平方向移动
self.rect.x+=self.x_speed
#垂直方向移动
self.rect.y+=self.y_speed
#判断上、下、左、右四个边界条件,如果移动到了边界,让飞机停在原位
if self.rect.x<=0:
self.rect.x=0
if self.rect.x>=WINDOW.width-self.rect.width:
self.rect.x=WINDOW.width-self.rect.width
if self.rect.y<=0:
self.rect.y=0
if self.rect.y>=WINDOW.height-self.rect.height:
self.rect.y=WINDOW.height-self.rect.height
#敌机类
class Enemy(GameSprite):
def __init__(self):
#敌机有7中飞机,随机生成
self.enemy_url=f"./source/plane/enemy-{random.randint(1,7)}.png"
#敌机的垂直速度也是随机生成(1,3)
super().__init__(self.enemy_url,random.randint(1,3))
#敌机的初始水平位置需要随机生成,范围就是(0,WINDOW.width-self.rect.width)
self.rect.x=random.randint(0,WINDOW.width-self.rect.width)
#敌机的垂直位置y是固定值,保证敌机出现的位置在窗口之外
self.rect.y=-self.rect.height
#敌机水平方向的移动速度随机生成
self.x_speed=random.randint(-1,1)
def update(self, *args, **kwargs):
#调用父类的update()函数
super().update()
#父类函数不够用的情况下,直接补充
self.rect.x+=self.x_speed#水平移动
#如果到达左右边界则反向运动
if self.rect.x<=0 or self.rect.x>=WINDOW.width-self.rect.width:
self.x_speed=-self.x_speed
#敌机出了窗口底部则杀死此敌机精灵
if self.rect.y>WINDOW.height:
self.kill()
#子弹类(英雄飞机子弹和敌机子弹)
class Bullet(GameSprite):
#is_enemy表示是否是敌机,敌机和英雄飞机使用的子弹图片不同
def __init__(self,speed,is_enemy=False):
if is_enemy:
self.bullet_index=ENEMY_BULLET_INDEX
else:
self.bullet_index = HERO_BULLET_INDEX
bullet_filename = f"./source/bullet/bullet_{self.bullet_index}.png"
self.speed=speed
super().__init__(bullet_filename,self.speed)
#由于敌机和英雄飞机是相对运动,资源图片都是正向的,所以如果是敌机子弹,则需要对子弹图片做旋转180°操作
if is_enemy:
##flip(翻转的图片、是否绕x轴翻转、是否绕y轴翻转)
self.image=pygame.transform.flip(self.image,False,True)
def update(self, *args, **kwargs):
#垂直方向移动
super().update()
#超出屏幕则杀死此精灵
if self.rect.y<-self.rect.height or self.rect.y>WINDOW.height+self.rect.height:
self.kill()
#爆炸动画类
class Bomb(pygame.sprite.Sprite):
def __init__(self,sprite1):
super().__init__()
#导入所有动画的图片
self.images=[pygame.image.load(f"./source/bomb/bomb-{bomb_index}.png") for bomb_index in range(1,8)]
self.sprite1=sprite1
self.interval = 5 # 播放每一张图片的间隔 5帧
self.interval_index = 0 #帧数计数器 初始值为0
self.image_index=0#图片索引 初始值为0
self.image = self.images[self.image_index]
self.rect = self.image.get_rect()
self.rect.x = self.sprite1.rect.x
self.rect.y = self.sprite1.rect.y
def update(self, *args, **kwargs):
self.interval_index+=1#每一帧进入update()函数,帧计数器加1
#当计数器到达设置值时,切换图片
if self.interval_index>=self.interval:
self.image=self.images[self.image_index]
#帧计数器归零
self.interval_index=0
#切换图片
self.image_index+=1
#当所有图片都播放完毕之后杀死此精灵对象
if self.image_index==len(self.images):
self.kill()
5.资源下载
链接:资源
提取码:jixb