# Python-Pygame实现飞机大战
和小甲鱼的飞机的大战很像,但是多一些功能的实现
开发的环境是python3.5/pygame1.9.6
# 效果图
# 模块划分
- 主机模块
- 敌机模块
- 子弹模块
- 道具模块
- 背景滚动模块
# 主机模块
# user/bin/python
# Author:ZQD
# -*- coding: utf-8 -*-
import pygame
from src.buttle import Bullet1
SCREEN_RECT = pygame.Rect(0, 0, 480, 652)
# pygame.sprite.Sprite 加载动态效果
class OurPlane(pygame.sprite.Sprite):
"玩家飞机:两张图片,上下左右功能,复位功能"
def __init__(self,bg_size):
super(OurPlane, self).__init__()
#确定玩家两张图片
self.image_one=pygame.image.load("../image/hero1.png")
self.image_two = pygame.image.load("../image/hero2.png")
#获取飞机的 位置
self.rect=self.image_one.get_rect()
#获取背景图片的宽高
self.width,self.height=bg_size[0],bg_size[1]
#获取飞机图片的掩膜,用来精确的碰撞检测
self.mask=pygame.mask.from_surface(self.image_one)
#获取飞机的初始位置
self.rect.left,self.rect.top=(self.width-self.rect.width)//2,(self.height-self.rect.height-60)
#移动速度
self.speed=10
#存活状态
self.active=True
#死亡状态,爆炸效果
self.destroy_images=[]
self.destroy_images.extend([
pygame.image.load("../image/hero_blowup_n1.png"),
pygame.image.load("../image/hero_blowup_n2.png"),
pygame.image.load("../image/hero_blowup_n3.png"),
pygame.image.load("../image/hero_blowup_n4.png"),
])
# self.bullet1=Bullet1()
# def planeShoot(self):
# self.bullet1.active=True
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<self.height-30:
self.rect.bottom+=self.speed
else:
self.rect.bottom=self.height-30
def moveLeft(self):
if self.rect.left>0:
self.rect.left-=self.speed
else:
self.rect.left=0
def moveRight(self):
if self.rect.right<self.width:
self.rect.right+=self.speed
else:
self.rect.right=self.width
def reset(self):
"位置重置的方法"
self.rect.left, self.rect.top = (self.width - self.rect.width) // 2,\
(self.height - self.rect.height - 60)
self.active=True
# 敌机模块
分为小型敌机和中型敌机
# user/bin/python
# Author:ZQD
# -*- coding: utf-8 -*-
import pygame
from random import *
# pygame.sprite.Sprite 加载动态效果
class OurEnemy(pygame.sprite.Sprite):
"玩家飞机:两张图片,上下左右功能,复位功能"
energy=1
def __init__(self,bg_size):
super(OurEnemy, self).__init__()
#确定玩家两张图片
self.image=pygame.image.load("../image/enemy1.png")
#获取飞机的 位置
self.rect=self.image.get_rect()
#获取背景图片的宽高
self.width,self.height=bg_size[0],bg_size[1]
#获取飞机图片的掩膜,用来精确的碰撞检测
self.mask=pygame.mask.from_surface(self.image)
#获取飞机的初始位置
self.rect.left,self.rect.top=(randint(0,self.width-self.rect.width),
randint(-5*self.rect.height,-self.rect.height))
#移动速度
self.speed=2
#存活状态
self.active=True
self.energy = OurEnemy.energy
#死亡状态,爆炸效果
self.destroy_images = []
self.destroy_images.extend([
pygame.image.load("../image/enemy1_down1.png"),
pygame.image.load("../image/enemy1_down2.png"),
pygame.image.load("../image/enemy1_down3.png"),
pygame.image.load("../image/enemy1_down4.png"),
])
def move(self):
if self.rect.top<self.height:
self.rect.top += self.speed
else:
self.reset()
def reset(self):
self.active=True
self.energy = OurEnemy.energy
self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width),
randint(-5 * self.rect.height, -self.rect.height))
class Midenemy(pygame.sprite.Sprite):
energy = 4
def __init__(self, bg_size):
super(Midenemy, self).__init__()
# 确定玩家两张图片
self.image = pygame.image.load("../image/enemy2.png")
# 获取飞机的 位置
self.rect = self.image.get_rect()
# 获取背景图片的宽高
self.width, self.height = bg_size[0], bg_size[1]
# 获取飞机图片的掩膜,用来精确的碰撞检测
self.mask = pygame.mask.from_surface(self.image)
# 获取飞机的初始位置
self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width),
randint(-10 * self.rect.height, -self.height))
# 移动速度
self.speed = 1
# 存活状态
self.active = True
self.energy = Midenemy.energy
# 死亡状态,爆炸效果
self.destroy_images=[]
self.destroy_images.extend([
pygame.image.load("../image/enemy2_down1.png"),
pygame.image.load("../image/enemy2_down2.png"),
pygame.image.load("../image/enemy2_down3.png"),
pygame.image.load("../image/enemy2_down4.png"),
])
def move(self):
if self.rect.top < self.height:
self.rect.top += self.speed
else:
self.reset()
def reset(self):
self.active = True
self.energy = OurEnemy.energy
self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width),randint(-10 * self.rect.height, -self.height))
# 子弹模块
# user/bin/python
# Author:ZQD
# -*- coding: utf-8 -*-
import pygame
#英雄子弹
class Bullet1(pygame.sprite.Sprite):
def __init__(self, position):
#引用精灵
super(Bullet1, self).__init__()
self.image = pygame.image.load("../image/bullet1.png").convert_alpha()
self.rect = self.image.get_rect()
#坐标
self.rect.left, self.rect.top = position
#运动速度
self.speed = 20
#按键盘触发active true
self.active = True
#获取掩模,检测碰撞
self.mask = pygame.mask.from_surface(self.image)
def move(self):
# 判定子弹的消失
self.rect.top -= self.speed
if self.rect.top < 0:
self.active = False
else:
self.rect.top -= self.speed
def reset(self, position):
#重新,初始化定位
self.rect.left, self.rect.top = position
self.active = True
class Bullet2(pygame.sprite.Sprite):
def __init__(self, position):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("../image/bullet2.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = position
self.speed = 12
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
# 道具模块
# user/bin/python
# Author:ZQD
# -*- coding: utf-8 -*-
import pygame
#导入randint
from random import randint
#子弹的道具
class Bullet_Tool(pygame.sprite.Sprite):
def __init__(self, bg_size):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("../image/ufo1.png").convert_alpha()
self.rect = self.image.get_rect()
self.width, self.height = bg_size[0], bg_size[1]
self.rect.left, self.rect.top =(randint(0, self.width - self.rect.width), 10)
self.speed = 5
self.active = False
self.mask = pygame.mask.from_surface(self.image)
#移动速度,下降速度
def move(self):
if self.rect.top < self.height:
self.rect.top += self.speed
else:
self.active = False
#重置子弹道具位置
def reset(self):
self.active = True
self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width), 10)
# 背景移动模块
# user/bin/python
# Author:ZQD
# -*- coding: utf-8 -*-
import pygame
class BackGround1(pygame.sprite.Sprite):
def __init__(self, bg_size):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("../image/background.png").convert_alpha()
self.rect = self.image.get_rect()
self.width, self.height = bg_size[0], bg_size[1]
self.speed = 1
self.active = True
self.rect.center = ((self.width // 2), (self.height // 2))
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.center = ((self.width // 2), -(self.height // 2))
class BackGround2(pygame.sprite.Sprite):
def __init__(self, bg_size):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("../image/background.png").convert_alpha()
self.rect = self.image.get_rect()
self.width, self.height = bg_size[0], bg_size[1]
self.speed = 1
self.active = True
self.rect.center = ((self.width // 2), -(self.height // 2))
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.center = ((self.width // 2), -(self.height // 2))
# 主模块
程序的入口
# usr/bin/python
# Author:ZQD
# -*- coding: utf-8 -*-
'''
程序的入口,核心代码区域
主要实现窗体界面显示,各种精灵的加载,以及相应功能体现
'''
import pygame,sys
import random
from src.plane import OurPlane
from src.enemy1 import OurEnemy,Midenemy
from src.buttle import Bullet1,Bullet2
from src.tools import Bullet_Tool
from src.bg import BackGround1,BackGround2
''' 1、创建窗体显示,并添加背景图片'''
# 1.1 创建窗体,并设置其相关属性
bg_size = (480,652)#设置背景的大小
screen = pygame.display.set_mode(bg_size,0,32)#创建窗体
pygame.display.set_caption("飞机大战")#设置窗体标题
#定义四种血槽颜色
color_black = (0,0,0)
color_green = (0,255,0)
color_red = (255,0,0)
color_white = (255,255,255)
#初始化
pygame.mixer.init()
# # 载入游戏音乐
pygame.mixer.music.load("../sound/game_music.wav")
pygame.mixer.music.set_volume(0.2)
pygame.mixer.music.play()
#2.1创建玩家飞机对象
ourplane = OurPlane(bg_size)
#创建敌机方法
def add_enemys(group1,group2,num):
for i in range(num):
small_enemy = OurEnemy(bg_size)
middle_enemy=Midenemy(bg_size)
group1.add(small_enemy)
group2.add(small_enemy)
group1.add(middle_enemy)
group2.add(middle_enemy)
def add_background1(group1, group2, num):
for i in range(num):
bg1 = BackGround1(bg_size)
group1.add(bg1)
group2.add(bg1)
def add_background2(group1, group2, num):
for i in range(num):
bg2 = BackGround2(bg_size)
group1.add(bg2)
group2.add(bg2)
def main():
"核心代码封装在main方法中去,此main方法为自定义方法"
#程序运行状态
running = True
# 2.3 图片切换的条件
switch_image = False
delay = 60
enemies = pygame.sprite.Group()
small_enemies = pygame.sprite.Group()
middle_enemies = pygame.sprite.Group()
backgrounds = pygame.sprite.Group()
background1 = pygame.sprite.Group()
background2 = pygame.sprite.Group()
#添加敌机
add_enemys(enemies,small_enemies,6)
add_enemys(enemies, middle_enemies, 3)
#添加背景
add_background1(backgrounds,background1,1)
add_background2(backgrounds, background2, 1)
#子弹列表
bullet1 = []
bullet1_index = 0
el_destroy_index=0
me_destroy_index=0
BULLET1_NUM = 10
#循环添加
for i in range(BULLET1_NUM):
#添加
bullet1.append(Bullet1(OurPlane(bg_size).rect.midtop))
# 二级子弹
bullet2 = []
bullet2_index = 0
BULLET2_NUM = 40
for i in range(BULLET2_NUM // 2):
bullet2.append(Bullet2((ourplane.rect.centerx - 33, ourplane.rect.centery)))
bullet2.append(Bullet2((ourplane.rect.centerx + 30, ourplane.rect.centery)))
#设定子弹道具出现时间
bullet_tool =Bullet_Tool(bg_size)
# USEREVENT
tool_time=pygame.USEREVENT
#在事件队列上重复创建事件,只用于插入到pygame的事列中
pygame.time.set_timer(tool_time, 10000)
# 标志是否使用正常子弹
is_bullet1 = True
# 子弹
bullet_time = pygame.USEREVENT + 1
# 子弹2
is_bullet2 = False
# # 标志是否暂停游戏
# 设定开始
start_game = False
#设定暂停
pause = False
game_resume_pressed_image = pygame.image.load("../image/game_resume_pressed.png").convert_alpha()
game_pause_pressed_image = pygame.image.load("../image/game_pause_pressed.png").convert_alpha()
game_resume_nor_image = pygame.image.load("../image/game_resume_nor.png").convert_alpha()
game_paused_nor_image = pygame.image.load("../image/game_pause_nor.png").convert_alpha()
paused_rect = game_paused_nor_image.get_rect()
#暂停的位置
paused_rect.left, paused_rect.top =10, 10
paused_image = game_paused_nor_image
# 游戏暂停画面
continues_image = pygame.image.load("../image/game_resume_nor.png").convert_alpha()
continues_rect = continues_image.get_rect()
continues_rect.left, continues_rect.top =((bg_size[0] - continues_rect.width) // 2, (bg_size[1]- continues_rect.height) // 2)
#结束
again_image = pygame.image.load("../image/btn_finish.png").convert_alpha()
again_rect = again_image.get_rect()
over_image=pygame.image.load("../image/gameover.png").convert_alpha()
over_rect=over_image.get_rect()
# 游戏开始画面
logo_image = pygame.image.load("../image/bg1.png").convert_alpha()
#logo的图片位置
logo_rect = logo_image.get_rect()
logo_rect.left, logo_rect.top = ( (bg_size[0] - logo_rect.width) // 2, (bg_size[1] - logo_rect.height) // 2)
begin_image = pygame.image.load("../image/game_resume_nor.png")
#开始图片位置
begin_image_rect = begin_image.get_rect()
begin_image_rect.left, begin_image_rect.top = ((bg_size[0] - begin_image_rect.width) // 2, (logo_rect.bottom + 20))
#life
life_image=pygame.image.load("../image/life.png")
life_rect=life_image.get_rect()
life_num=3
while running:
#绘制背景图片
# screen.blit(background,(0,0))
# 绘制移动背景
for each in background1:
screen.blit(each.image, each.rect)
each.move()
if each.rect.height > 0:
for each in background2:
screen.blit(each.image, each.rect)
each.move()
# 绘制开始界面
#游戏没开始的时候
if not start_game:
screen.blit(logo_image,logo_rect)
screen.blit(begin_image,begin_image_rect)
# 判断按下鼠标哪个键
if pygame.mouse.get_pressed()[0]:
# 获取鼠标坐标
pos = pygame.mouse.get_pos()
# 如果用户点击重新开始
if begin_image_rect.left < pos[0] < begin_image_rect.right and begin_image_rect.top < pos[1] < begin_image_rect.bottom:
start_game = True
elif life_num and not pause and start_game:
key_pressed = pygame.key.get_pressed()
if key_pressed[pygame.K_w] or key_pressed[pygame.K_UP]:
ourplane.moveUp()
if key_pressed[pygame.K_s] or key_pressed[pygame.K_DOWN]:
ourplane.moveDown()
if key_pressed[pygame.K_a] or key_pressed[pygame.K_LEFT]:
ourplane.moveLeft()
if key_pressed[pygame.K_d] or key_pressed[pygame.K_RIGHT]:
ourplane.moveRight()
if key_pressed[pygame.K_SPACE] or key_pressed[pygame.K_0]:
ourplane.planeShoot()
# 绘制检测是否获得
if bullet_tool.active:
bullet_tool.move()
screen.blit(bullet_tool.image,bullet_tool.rect)
# pygame.sprite.collide_mask(bullet_tool, OurPlane(bg_size))
# butt=pygame.sprite.spritecollide(ourplane,bullet_tool,False,pygame.sprite.collide_mask)
if pygame.sprite.collide_mask(bullet_tool, OurPlane(bg_size)):
is_bullet2 = True
pygame.time.set_timer(bullet_time, 10000)
bullet_tool.active = False
# 绘制暂停按钮
screen.blit(paused_image, paused_rect)
for each in small_enemies:
if each.active:
# 敌机下落
each.move()
# 绘制敌机
screen.blit(each.image,each.rect)
pygame.draw.line(screen,color_black,(each.rect.left,each.rect.top-5),(each.rect.right,each.rect.top - 5))
energy_remain = each.energy / OurEnemy.energy
if energy_remain > 0.2:
energy_color = color_green
else:
energy_color = 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 el_destroy_index==0:
pass
#实现爆炸效果
if not (delay % 3):
screen.blit(each.destroy_images[me_destroy_index], each.rect)
el_destroy_index = (el_destroy_index + 1) % 4
if el_destroy_index == 0:
each.reset()
for each in middle_enemies:
if each.active:
each.move()
screen.blit(each.image,each.rect)
pygame.draw.line(screen,color_black,(each.rect.left,each.rect.top-5),
(each.rect.right,each.rect.top - 5))
energy_remain = each.energy / Midenemy.energy
if energy_remain > 0.2:
energy_color = color_green
else:
energy_color = 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 el_destroy_index == 0:
pass
# 实现爆炸效果
if not (delay % 4):
screen.blit(each.destroy_images[me_destroy_index], each.rect)
el_destroy_index = (el_destroy_index + 1) % 4
if el_destroy_index == 0:
each.reset()
#飞机True的时候
if ourplane.active:
if switch_image:
screen.blit(ourplane.image_one,ourplane.rect)
else:
screen.blit(ourplane.image_two,ourplane.rect)
#子弹一,小子弹
if not (delay % 2):
if is_bullet1:
bullets = bullet1
bullets[bullet1_index].reset(ourplane.rect.midtop)
bullet1_index = (bullet1_index + 1) % BULLET1_NUM
#子弹移动
for b in bullets:
if b.active:
b.move()
screen.blit(b.image,b.rect)
#子弹和敌机碰撞效果
enemies_hit=pygame.sprite.spritecollide(b,enemies,False,pygame.sprite.collide_mask)
if enemies_hit:
b.active=False
for e in enemies_hit:
# 子弹造成伤害
if e in small_enemies or e in middle_enemies :
e.energy -= 1
# 敌机死亡
if e.energy == 0:
e.active = False
else:
e.active = False
if is_bullet2:
bullets = bullet2
bullets[bullet2_index].reset((ourplane.rect.centerx - 33, ourplane.rect.centery))
bullets[bullet2_index + 1].reset((ourplane.rect.centerx + 33, ourplane.rect.centery))
bullet2_index = (bullet2_index + 2) % BULLET2_NUM
#升级后:
for b in bullets:
if b.active:
b.move()
screen.blit(b.image, b.rect)
# 子弹和敌机碰撞效果
enemies_hit = pygame.sprite.spritecollide(b, enemies, False, pygame.sprite.collide_mask)
if enemies_hit:
b.active = False
for e in enemies_hit:
#子弹造成伤害
if e in small_enemies or e in middle_enemies:
e.energy -= 2
# 敌机死亡
if e.energy == 0:
e.active = False
else:
e.active = False
else:
#绘制损毁的英雄机
# pass
if not (delay%3):
screen.blit(ourplane.destroy_images[me_destroy_index],ourplane.rect)
me_destroy_index=(me_destroy_index+1) %4
if me_destroy_index == 0:
ourplane.reset()
life_num-=1
#实现英雄机与敌机的碰撞
# for e in enemies:
# flag=ourplane.checkHit(e)
# if flag:
# ourplane.active=False
# e.active=False
#碰撞检测
#飞机和敌机的碰撞事件
enemies_down=pygame.sprite.spritecollide(ourplane,enemies,False,pygame.sprite.collide_mask)
if enemies_down:
ourplane.active=False
for e in enemies_down:
e.active=False
is_bullet2=False
if life_num:
for i in range(life_num):
screen.blit(life_image, (bg_size[0]- 10 - (i + 1) * life_rect.width, 10))
#第三模块:
# 绘制暂停游戏界面
elif pause:
screen.blit(continues_image, continues_rect)
pygame.mixer.music.stop()
# 检测用户的鼠标操作
#鼠标事件
# pygame.mouse.get_pressed()
# 用户按下鼠标
if pygame.mouse.get_pressed()[0]:
# 获取鼠标坐标
pos = pygame.mouse.get_pos()
# 点击继续游戏
if continues_rect.left < pos[0] < continues_rect.right and continues_rect.top < pos[1] < continues_rect.bottom:
pause = not pause
pygame.mixer.music.play()
#插入掉落tool事件
pygame.time.set_timer(tool_time, 10000)
#生命
elif life_num==0:
pygame.mixer.music.stop()
again_rect.left, again_rect.top = (bg_size[0] - again_rect.width) // 2,300
screen.blit(again_image, again_rect)
over_rect.left, over_rect.top =(bg_size[0]- again_rect.width) // 2, again_rect.bottom + 10
screen.blit(over_image, over_rect)
# 检测用户的鼠标操作
# 如果用户按下鼠标左键
if pygame.mouse.get_pressed()[0]:
# 获取鼠标坐标
pos = pygame.mouse.get_pos()
# 如果用户点击重新开始
if again_rect.left < pos[0] < again_rect.right and \
again_rect.top < pos[1] < again_rect.bottom:
# 调用main函数,重新开始游戏
main()
# 如果用户点击结束游戏
elif over_rect.left < pos[0] < over_rect.right and over_rect.top < pos[1] < over_rect.bottom:
# 退出游戏
pygame.quit()
sys.exit(0)
#退出事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#鼠标事件
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and paused_rect.collidepoint(event.pos):
pause = not pause
if pause:
pygame.time.set_timer(tool_time, 0)
else:
pygame.time.set_timer(tool_time,10000)
elif event.type ==pygame.MOUSEMOTION:
if paused_rect.collidepoint(event.pos):
if pause:
paused_image = game_resume_pressed_image
else:
paused_image = game_pause_pressed_image
else:
if pause:
paused_image = game_resume_nor_image
else:
paused_image = game_paused_nor_image
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
for each in enemies:
if each.rect.bottom > 0:
each.active = False
elif event.type == tool_time:
if random.choice([1, 2, 3, 4, 5, 6]) == 2:
bullet_tool.reset()
# 2.2 设置动画效果的帧数,(图片切换的时间差)
clock = pygame.time.Clock()
clock.tick(60)
if not delay % 3:
switch_image = not switch_image
if delay == 0:
delay = 60
delay -= 1
#键盘事件监听,通过键盘控制飞机移动方法
#图片更新
pygame.display.flip()
pygame.display.update()
# time.sleep(0.001)
if __name__ == '__main__':
"程序的入口,执行此方法,调用自定义main方法"
main()