一、实现功能包括:多架敌机随机出现,生命数3,死亡时倒计时后重新开局,炸弹随机降落,统计击败敌机数,三张地图每局随机出现,击败敌机数达到10时出现大飞机,大飞机发射子弹更密集等。
二、pycharm源码文件以及图片素材资源已在主页上传,代码以及运行结果如下:
import time
import random
from PIL import Image
import pygame
from pygame.constants import *
#己方飞机类
class Player(pygame.sprite.Sprite):
# 存放所有飞机的子弹的组
bullets = pygame.sprite.Group()
def __init__(self,screen):
# 这个精灵的初始化方法 必须调用
pygame.sprite.Sprite.__init__(self)
# 创建一个玩家飞机图片,当做真正的飞机
self.image = pygame.image.load("./feiji/hero1.png")
#通过图片获得矩阵
self.rect = self.image.get_rect() # rect:矩形
# 定义飞机初始化坐标
self.rect.topleft = [Manager.bg_size[0] / 2 - 100 / 2,600]
# 飞机速度
self.speed = 10
#记录当前窗口对象
self.screen = screen
#子弹图片
self.bullet_image = "./feiji/bullet.png"
# 飞机子弹频率 1~100,表示每0.01秒百分之几的概率发射
self.bullet_frequency = 10
def key_control(self):
# 监听键盘事件
key_pressed = pygame.key.get_pressed()
if key_pressed[K_w] or key_pressed[K_UP]:
self.rect.top -= self.speed
if key_pressed[K_s] or key_pressed[K_DOWN]:
self.rect.bottom += self.speed
if key_pressed[K_a] or key_pressed[K_LEFT]:
# 定义飞机左行驶尽头边界
if self.rect.left >= 10 :
self.rect.left -= self.speed
if key_pressed[K_d] or key_pressed[K_RIGHT]:
#定义飞机右行驶尽头边界
if self.rect.right <= Manager.bg_size[0]:
self.rect.right += self.speed
if key_pressed[K_SPACE]:
# 随机发射子弹
if random.randint(0,99) in range(self.bullet_frequency):
bullet = Bullet(self.screen ,self.rect.left + 50 - Image.open(self.bullet_image).size[0]/2
,self.rect.top - Image.open(self.bullet_image).size[1])
# 将己方子弹子弹改为
bullet.image = pygame.image.load(self.bullet_image)
Player.bullets.add(bullet)
#键盘监听控制飞机,飞机的显示
def update(self):
self.key_control()
self.display()
def display(self):
# 粘贴飞机坐标
self.screen.blit(self.image, self.rect)
#更新子弹坐标
for i in Player.bullets:
i.player_fire()
# 对应子弹的update方法
Player.bullets.update()
# 把所有子弹全部添加到屏幕
Player.bullets.draw(self.screen)
#敌方飞机类
class Enemyplayer(pygame.sprite.Sprite):
# 放子弹的列表,类属性,通过类名调用
bullets = pygame.sprite.Group()
def __init__(self,screen,image ):
# 这个精灵的初始化方法 必须调用
pygame.sprite.Sprite.__init__(self)
#记录窗口
self.screen = screen
#获取敌方飞机图片
self.image = pygame.image.load(image)
#通过图片获得矩阵
self.rect = self.image.get_rect()
#敌方飞机坐标初始化
self.rect.topleft = [Manager.bg_size[0]/2 - 50/2,0]
# 放子弹的列表,类属性,通过类名调用
self.bullets = pygame.sprite.Group()
# 子弹图片
self.bullet_image = "./feiji/bullet1.png"
#敌方飞机子弹频率 1~100,平均一秒发射几个
self.bullet_frequency = 3
#敌机移动方向
self.direciton= "left"
#飞机是否向下移动
self.direciton_up = False
#敌机速度
self.speed = 4
def display(self):
#粘贴敌机到窗口
self.screen.blit(self.image,self.rect.topleft)
#敌方飞机自动开火方法
def auto_fire(self):
#控制敌方子弹频率
if random.randint(1, 100) in range(0,self.bullet_frequency):
#通过飞机坐标跟子弹分辨率大小调用子弹对象
bullet = Bullet(self.screen,self.rect.left + 25 - Image.open(self.bullet_image).size[0]/2
,self.rect.top + Image.open(self.bullet_image).size[1] + 20)
#将敌方子弹子弹改为
bullet.image = pygame.image.load(self.bullet_image)
#向Bullet子弹对象列表增加一个子弹对象
Enemyplayer.bullets.add(bullet)
#敌方飞机自动飞行方法
def auto_move(self):
if self.direciton == "left":
self.rect.left -= self.speed
if self.direciton_up :
self.rect.bottom += self.speed
elif self.direciton == "right":
self.rect.right += self.speed
if self.direciton_up:
self.rect.bottom += self.speed
if self.rect.left <= 0 :
self.direciton = "right"
elif self.rect.right >=Manager.bg_size[0]:
self.direciton = "left"
#使敌方飞机飞出窗口时消除该敌方飞机对象
def kill_enemy(self):
if self.rect.top > Manager.bg_size[1]:
self.kill()
#敌方飞机自动移动,自动发射以及显示
def update(self):
self.auto_move()
self.auto_fire()
self.display()
self.kill_enemy()
#子弹类
class Bullet(pygame.sprite.Sprite):
def __init__(self,screen,x,y):
# 这个精灵的初始化方法 必须调用
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.image = pygame.image.load("./feiji/bullet.png")
#通过图片获得矩阵
self.rect = self.image.get_rect()
# 初始化子弹坐标
self.rect.topleft = [x , y ]
#子弹速度
self.speed = 8
#己方飞机开火
def player_fire(self):
self.rect.top -= self.speed+4
#敌方飞机开火
def enemy_fire(self):
self.rect.bottom += self.speed/2
def update(self):
# 如果子弹移出屏幕上方 则销毁子弹对象
if self.rect.top > Manager.bg_size[1] or self.rect.bottom < 0 :
self.kill()
self.enemy_fire()
# 把所有子弹全部添加到屏幕
Enemyplayer.bullets.draw(self.screen)
# 炸弹类
class Bombshell(pygame.sprite.Sprite):
def __init__(self,screen):
# 这个精灵的初始化方法 必须调用
pygame.sprite.Sprite.__init__(self)
self.screen = screen
# 传入炸弹图片
self.image = pygame.image.load("./feiji/bomb-2.gif")
# 炸弹矩形获取
self.rect = self.image.get_rect()
# 炸弹速度
self.speed = 2
self.direciton = "left"
# 炸弹初始坐标
self.rect.topleft = [0,0]
def auto_move(self):
# 往左移动
if self.direciton == "left":
self.rect.left -= self.speed
self.rect.bottom += self.speed
# 往右移动
elif self.direciton == "right":
self.rect.right += self.speed
self.rect.bottom += self.speed
#左右移动边界
if self.rect.left <= 0:
self.direciton = "right"
elif self.rect.right >= Manager.bg_size[0]:
self.direciton = "left"
# 使敌方炸弹飞出窗口时消除该敌方飞机对象
def kill_bomb(self):
if self.rect.top > Manager.bg_size[1]:
self.kill()
def display(self):
# 粘贴炸弹到窗口
self.screen.blit(self.image, self.rect.topleft)
def update(self):
self.auto_move()
self.display()
self.kill_bomb()
class Bomb(object):
# 初始化爆炸
def __init__(self, screen, type):
self.screen = screen
if type == 'enemy':
# 加载爆炸资源
self.mImages = [
pygame.image.load("./feiji/enemy0_down" + str(v) + ".png") for v in range(1, 5)]
else:
# 加载爆炸资源
self.mImages = [pygame.image.load(
"./feiji/hero_blowup_n" + str(v) + ".png") for v in range(1, 5)]
self.mImages += self.mImages
# 设置当前爆炸播放索引
self.mIndex = 0
# 爆炸位置
self.mPos = [0, 0]
# 是否可见
self.mVisible = False
# 设置位置
def action(self, rect):
# 触发爆炸方法draw
# 爆炸的坐标
self.mPos[0] = rect.left
self.mPos[1] = rect.top
# 打开爆炸的开关
self.mVisible = True
# 绘制爆炸
def draw(self):
if not self.mVisible:
return
self.screen.blit(self.mImages[self.mIndex], (self.mPos[0], self.mPos[1]))
self.mIndex += 1
if self.mIndex >= len(self.mImages):
# 如果下标已经到最后 代表爆炸结束
# 下标重置 mVisible重置
self.mIndex = 0
self.mVisible = False
# 地图
class GameBackground(object):
# 初始化地图,传入参数窗口跟地图编号
def __init__(self, screen,num):
self.mImage1 = pygame.image.load("./feiji/img_bg_level_"+str(num)+".jpg")
self.mImage2 = pygame.image.load("./feiji/img_bg_level_"+str(num)+".jpg")
# 窗口
self.screen = screen
# 辅助移动地图
self.y1 = 0
self.y2 = -Manager.bg_size[1] # -768
# 移动地图
def move(self):
self.y1 += 2
self.y2 += 2
if self.y1 >= Manager.bg_size[1]:
self.y1 = 0
if self.y2 >= 0:
self.y2 = -Manager.bg_size[1]
# 绘制地图
def draw(self):
self.screen.blit(self.mImage1, (0, self.y1))
self.screen.blit(self.mImage2, (0, self.y2))
# 背景音乐类
class GameSound(pygame.sprite.Sprite):
def __init__(self):
#这个精灵的初始化方法必须调用
pygame.sprite.Sprite.__init__(self)
pygame.mixer.init() # 音乐模块初始化
pygame.mixer.music.load('./feiji/bg2.ogg') #载入背景音乐
pygame.mixer.music.set_volume(0.5) # 声音大小,0.5表示一半大小的声音
self.__bomb = pygame.mixer.Sound('./feiji/bomb.wav')
# 背景音乐
def playBackgroundMusic(self):
pygame.mixer.music.play(-1) # 开始播放音乐,数字表示播放次数,-1表示循环播放
# 爆炸音乐
def playBombSound(self):
self.__bomb.play()
class Manager(object):
#对应图片的窗口大小
bg_size = (512,768)
#玩家生命数
life_num = 3
#生成敌方飞机的定时器
create_enemy_id = 10
#游戏结束定时器
create_game_over_id = 11
#游戏结束标志
gameover = False
#倒计时数
over_time = 3
#boss最大数量
boss_num = 10
# 是否存在boss
have_boss = False
#初始化击败敌方飞机数
defeat_num = 0
def __init__(self):
pygame.init()
# 创建一个窗口
self.screen = pygame.display.set_mode(Manager.bg_size)
# 生成音乐对象
self.gamesound = GameSound()
# 己方飞机精灵组
self.players = pygame.sprite.Group()
# 敌方飞机精灵组
self.enemyplayers = pygame.sprite.Group()
# 敌方炸弹精灵组
self.bombshells = pygame.sprite.Group()
# 创建一个背景图片
self.background = pygame.image.load(r"./feiji/background.png")
#创建一个可移动地图 ,随机取一种地图,
self.move_background_num = random.randint(1,5)
self.move_background=GameBackground(self.screen,self.move_background_num)
def player(self):
# 调用一个飞机对象
player = Player(self.screen)
# 将该飞机对象增加到己方飞机精灵组中
self.players.add(player)
def enemyplayer(self):
# 调用一个敌方飞机对象
enemyplayer = Enemyplayer(self.screen,"./feiji/enemy0.png")
# 将该飞机对象增加到己方飞机精灵组中
self.enemyplayers.add(enemyplayer)
#增加多个敌机对象
def add_enemy(self):
enemyplayer = Enemyplayer(self.screen,"./feiji/enemy0.png")
enemyplayer.direciton_up = True
x = random.randint(0,Manager.bg_size[0])
#敌机随机出现
enemyplayer.rect.topleft = (x,0)
#如果敌机出现在窗口较左边,则敌机优先向右飞行
if x <= Manager.bg_size[0] / 2:
enemyplayer.direciton = "right"
#向敌机精灵组增加一个敌机精灵
self.enemyplayers.add(enemyplayer)
#判断碰撞
def judge_bomb(self,player_bomb,enemy_bomb):
delete_sprite = False
if Manager.life_num == 1:
delete_sprite = True
# 参1:碰撞对象1 ;参2:碰撞对象2 ;参3:判断调出碰撞对象1还是2还是一起的爆炸图片 ; 参3:是否删除爆炸对象1
def judge(x1,x2,who,delete1):
# 判断碰撞对象1(精灵组)与2(精灵组)的碰撞
iscollide = pygame.sprite.groupcollide(x1, x2, delete1, True)
if iscollide and (who == "player" or who == "both"):
Manager.life_num -= 1
if Manager.life_num == 0:
# 游戏结束
Manager.gameover = True
pygame.time.set_timer(Manager.create_game_over_id,1000)
if iscollide:
#取出爆炸对象1
items = list(iscollide.items())[0]
x = items[0]
if who == "player":
# 传入爆炸位置,打开爆炸图片输出按钮
player_bomb.action(x.rect)
elif who == "enemy":
#x = items[1][0]
# 传入敌方爆炸图片的位置
enemy_bomb.action(x.rect)
# 敌方爆炸击败数加1
Manager.defeat_num += 1
# 爆炸的声音
elif who == "both":
# 传入爆炸位置,打开爆炸图片输出按钮
player_bomb.action(x.rect)
# 取出爆炸对象2
y = items[1][0]
# 传入爆炸对象2的爆炸图片的位置
enemy_bomb.action(y.rect)
# 敌方爆炸击败数加1
Manager.defeat_num += 1
# 爆炸删除子弹精灵组
# Enemyplayer.bullets.empty()
#爆炸音乐
self.gamesound.playBombSound()
# 判断玩家飞机(精灵组)与敌方子弹(精灵组)的碰撞
judge(self.players, Enemyplayer.bullets, "player", delete_sprite)
# 判断玩家飞机(精灵组)与敌方炸弹(精灵组)的碰撞
judge(self.players, self.bombshells, "player", delete_sprite)
# 判断敌方飞机(精灵组)与我方子弹(精灵组)的碰撞
judge(self.enemyplayers, Player.bullets, "enemy", True)
# 判断玩家飞机(精灵组)与敌方飞机(精灵组)的碰撞
judge(self.players, self.enemyplayers, "both", delete_sprite)
#召唤boss
def add_boss(self):
enemy_boss_player = Enemyplayer(self.screen,"./feiji/enemy1.png")
enemy_boss_player.bullet_frequency *= 2
enemy_boss_player.bullet_image ='./feiji/bullet2.png'
self.enemyplayers.add(enemy_boss_player)
# 绘制文字 rgb 红绿蓝 0 - 255
# 参1要绘制的文字 参2 x轴坐标 参3y轴坐标 参4文字大小 参5 文字颜色 参6 背景颜色
def drawText(self, text, x, y, textHeight = 30, fontColor = (255, 255, 255), backgroudColor = None):
# 通过字体文件获得字体对象 参数1 字体文件 参数2 字体大小
font_obj = pygame.font.Font('./feiji/baddf.ttf', textHeight)
# 1文字 2是否抗锯齿 3文字颜色 4背景颜色
text_obj = font_obj.render(text, True, fontColor, backgroudColor) # 配置要显示的文字
# 获得要显示的对象的rect
text_rect = text_obj.get_rect()
# 设置显示对象的坐标
text_rect.topleft = (x, y)
# 绘制字 到指定区域 参1是文字对象 参2 矩形对象
self.screen.blit(text_obj, text_rect)
def show_over_text(self):
# 游戏结束 倒计时后重新开始
self.drawText('gameover %d' % Manager.over_time, 100, Manager.bg_size[1] / 2,
textHeight=50, fontColor=[255, 0, 0])
#显示击败敌机数
def show_defeatnum_text(self):
# 显示击败敌机数
self.drawText('击败敌机数: %d' % Manager.defeat_num, Manager.bg_size[0]-150, 0,
textHeight=20, fontColor=[255, 0, 0])
# 显示剩余生命数
self.drawText('剩余生命数: %d' % Manager.life_num, Manager.bg_size[0] - 150, 20,
textHeight=20, fontColor=[255, 0, 0])
def game_over(self):
# 结束后倒计时
Manager.over_time -= 1
self.show_over_text()
if Manager.over_time == 0:
# 倒计时结束后游戏重新开始,相应变量返回初始化
Manager.over_time = 3
Manager.gameover = False
self.game_start()
def game_start(self):
# 重新开始游戏,有些类属性要清空
# 击败敌机数回 0
Manager.defeat_num = 0
# 生命数数回 3
Manager.life_num = 3
#boss按钮恢复
Manager.have_boss = False
#清空飞机类属性的子弹精灵组
Player.bullets.empty()
# 清空敌方飞机类属性的子弹精灵组
Enemyplayer.bullets.empty()
#重新运行游戏
manager = Manager()
manager.main()
def main(self):
# 播放背景音乐
self.gamesound.playBackgroundMusic()
# 增加一个己方飞机对象
self.player()
# 增加一个敌方飞机对象
self.enemyplayer()
# 开启生成敌方飞机定时器
pygame.time.set_timer(Manager.create_enemy_id, 2000)
# 初始化一个己方飞机爆炸对象
player_bomb = Bomb(self.screen, 'player')
# 初始化一个敌机爆炸的对象
enemy_bomb = Bomb(self.screen, 'enemy')
while True:
# 调用地图移动方法
self.move_background.move()
# 向窗口不断添加背景图
self.move_background.draw()
# 窗口显示击败敌机数
self.show_defeatnum_text()
# 击败敌机数50时,召唤boss
if Manager.defeat_num == 10 and Manager.have_boss == False:
self.add_boss()
Manager.have_boss = True
# 随机增加炸弹,平均每十秒增加一个炸弹
if random.randint(0, 1000) == 1:
bombshell = Bombshell(self.screen)
# 在窗口最上方左右之间随机出现
bombshell.rect.topleft = (random.randint(0, Manager.bg_size[0]), -103)
self.bombshells.add(bombshell)
# 对应飞机类里的update方法
self.players.update()
self.enemyplayers.update()
# 不断显示敌方子弹,此为类方法
Enemyplayer.bullets.update()
# 显示炸弹
self.bombshells.update()
#调用爆炸对象调出爆炸图片
player_bomb.draw()
enemy_bomb.draw()
if self.players.sprites():
#调用判断碰撞方法
self.judge_bomb(player_bomb,enemy_bomb)
#游戏结束播放倒计时文字
if Manager.gameover:
self.show_over_text()
# 不断更新窗口
pygame.display.update()
# 遍历所有的事件、
for event in pygame.event.get():
# 判断事件类型如果是pygame的退出
if event.type == QUIT:
# 执行pygame退出
pygame.quit()
# python程序的退出
exit()
elif event.type == Manager.create_enemy_id:
# 创建一个敌机
self.add_enemy()
elif event.type == Manager.create_game_over_id:
if Manager.gameover:
#游戏结束
self.game_over()
time.sleep(0.01)
if __name__ == "__main__":
manager = Manager()
manager.main()
三、运行结果: