基本精灵对象,继承 pygame.sprite.Sprite
属性:加载图片、设置初始速度
功能:纵向更新速度
import random
import pygame
SCREEN_PRO = pygame.Rect(0, 0, 512, 768)
# 自定义派生精灵子类,继承pygame.sprite.Sprite
class GameSprites(pygame.sprite.Sprite):
"""游戏精灵基类"""
def __init__(self, img_name, speed=1):
# 调用父类的初始化方法
super().__init__()
if img_name is None:
return
# 加载图像
self.image = pygame.image.load(img_name)
# 设置尺寸; get_rect()可以获取图像的原始大小
self.rect = self.image.get_rect()
# 设置速度
self.speed = speed
def update(self):
# 默认在屏幕上垂直方向移动
self.rect.y += self.speed
背景图对象(继承精灵基类)
属性:背景图片、背景音乐
位置:从屏幕0,0 开始绘制(屏幕大小与背景图一样大小)
功能:更新图片纵向移动,当移出屏幕后重置到屏幕上方(需要两张背景图,不断交替纵向下移动,表现出飞机不停飞的现象)
class BackGround(GameSprites):
"""背景精灵"""
# 初始化背景图片
def __init__(self, is_alternate=False):
super().__init__("./img/bg2.jpg")
# 加载背景音乐
pygame.mixer.music.load("./music/bg.mp3")
# 设置音量
pygame.mixer.music.set_volume(0.1)
# 设置播放次数, -1 表示无限循环
pygame.mixer.music.play(-1)
# 如果是交替图,初始位置则在屏幕上方
if is_alternate:
self.rect.bottom = SCREEN_PRO.y
def update(self):
# 调用父类更新
super().update()
# 当图片移出屏幕外时,将图片设置到屏幕上方
if self.rect.top >= SCREEN_PRO.height:
self.rect.bottom = SCREEN_PRO.y
英雄战机对象
英雄图片
x轴在屏幕中间,y轴距离屏幕底部200个像素
横向移动,不能移出屏幕。发射子弹,发射子弹音乐
class Hero(GameSprites):
"""英雄战机精灵"""
def __init__(self):
super().__init__("./img/hero.png")
# 初始化英雄的位置
self.rect.centerx = SCREEN_PRO.centerx
self.rect.y = SCREEN_PRO.height - 200
def update(self, speed=1):
self.rect.x += speed
# 控制边界
if self.rect.left <= 0:
self.rect.left = 0
elif self.rect.right >= SCREEN_PRO.right:
self.rect.right = SCREEN_PRO.right
def fire(self, bulletGroup):
# 英雄发射子弹
for i in range(1, 2):
bullet = Bullet(-2)
bullet.rect.centerx = self.rect.centerx
bullet.rect.y = self.rect.top - 30 * i
bulletGroup.add(bullet)
# 播放子弹音乐
bullet.bulletMusic.play()
两种类型的敌机对象
一群普通敌机
属性:敌机图片
位置:从屏幕上方纵向移动到屏幕中
功能:从上往下,纵向移动。移动屏幕后,销毁敌机对象
一群雷霆敌机
功能同上,敌机图片不同
class EnemyPlane(GameSprites):
"""敌机精灵"""
def __init__(self):
# 初始化敌机图像
super().__init__("./img/enemy1.png")
# 初始化 敌机随机速度
self.speed = random.randint(2, 4)
# 初始化 敌机随机位置,x轴的 最小位置是0,最大位置是屏幕宽度-敌机宽度
maxSpeed = SCREEN_PRO.width - self.rect.width
self.rect.bottom = SCREEN_PRO.y
self.rect.x = random.randint(0, maxSpeed)
# 初始化爆炸图片
self.boomImg = pygame.image.load("./img/boom.png")
# 初始化敌机销毁音乐
self.boomMusic = pygame.mixer.Sound("./music/boom.mp3")
self.boomMusic.set_volume(0.3)
def update(self):
# 调用父类更新敌机速度
super().update()
# 如果敌机飞出屏幕需要从精灵组中删除
if self.rect.top >= SCREEN_PRO.height:
# kill 方法可以让精灵从所有精灵组中移除,精灵会自动销毁(会默认调用 __del__ 方法)
self.kill()
def plan_die(self):
# 播放音乐
self.boomMusic.play()
class EnemyPlane2(GameSprites):
"""敌机精灵2-雷霆敌机"""
def __init__(self):
# 初始化敌机图像
super().__init__("./img/enemy2.png")
# 初始化 敌机随机速度
self.speed = random.randint(2, 4)
# 初始化 敌机随机位置,x轴的 最小位置是0,最大位置是屏幕宽度-敌机宽度
maxSpeed = SCREEN_PRO.width - self.rect.width
self.rect.bottom = SCREEN_PRO.y
self.rect.x = random.randint(0, maxSpeed)
# 初始化爆炸图片
self.boomImg = pygame.image.load("./img/boom.png")
# 初始化敌机销毁音乐
self.boomMusic = pygame.mixer.Sound("./music/boom.mp3")
self.boomMusic.set_volume(0.3)
def update(self):
# 调用父类更新敌机速度
super().update()
# 如果敌机飞出屏幕需要从精灵组中删除
if self.rect.top >= SCREEN_PRO.height:
# kill 方法可以让精灵从所有精灵组中移除,精灵会自动销毁(会默认调用 __del__ 方法)
self.kill()
def plan_die(self):
# 播放音乐
self.boomMusic.play()
子弹图对象
属性:子弹图片
位置:在英雄敌机的正上方
功能:子弹纵向移动,从下往上。移出屏幕后,子弹对象销毁
class Bullet(GameSprites):
"""子弹精灵"""
def __init__(self, speed):
super().__init__("./img/bullet.png", speed)
# 初始子弹发出音乐
self.bulletMusic = pygame.mixer.Sound("./music/bullet2.wav")
self.bulletMusic.set_volume(0.2)
def update(self):
super().update()
# 子弹超出屏幕就销毁
if self.rect.bottom <= 0:
self.kill()
计分器对象
属性:计分器文字对象
位置:初始位置在屏幕左上角,游戏结束时,在结束图片的中间
功能:子弹销毁一个敌机,分值+1
class FontSprites(GameSprites):
"""字体精灵"""
def __init__(self, size=18):
super().__init__(None)
self.font = pygame.font.Font("./font/msyh.ttf", size)
# 初始分值
self.fontValue = 0
self.textShow = self.font.render("分值:%d" % self.fontValue, True, (0, 255, 0))
def update(self, color=(0, 255, 0)):
# 第一个参数是写的文字;第二个参数是个布尔值,以为这是否开启抗锯齿,就是说True的话字体会比较平滑,不过相应的速度有一点点影响;
# 第三个参数是字体的颜色;第四个是背景色,如果你想没有背景色(也就是透明),那么可以不加这第四个参数。
self.textShow = self.font.render("分值:%d" % self.fontValue, True, color)
背景音乐材料
子弹发出音乐材料
敌机爆炸音乐材料
敌机爆炸图片材料
游戏结束图片材料、
游戏重新开始图片材料
点击关闭窗口程序退出事件
敌机随机出现事件
鼠标点击重新开始游戏事件
子弹发出事件
初始化pygame模块
初始化英雄生命
初始化开始菜单图片位置
初始化游戏窗口
初始化游戏时钟
初始化爆炸敌机对象
初始化各个精灵及精灵组对象
初始化 创建敌机定时器(每700毫秒创建一架敌机)
初始化 创建子弹定时器 (每500毫秒创建一颗子弹)
检测如果敌机爆炸了,让爆炸效果最多持续1秒
设置刷新频率,每秒刷新60次
监听事件
监听鼠标点击关闭窗口退出游戏事件
监听创建敌机事件
监听发射子弹事件
监听鼠标点击重新开始游戏事件
监听键盘按住向左或向右移动英雄战机事件
判断英雄战机,如果死亡则不再向下更新,直到点击重新开始,或者关闭游戏
碰撞检测
检测子弹精灵组与敌机精灵组碰撞,一旦有碰撞,则相应的敌机与子弹都销毁,并播放敌机爆炸声音,加载爆炸图片、分值加+1
检测英雄战机与敌机精灵组碰撞,一旦有碰撞,英雄战机阵亡,游戏结束,弹出游戏结束界面。停止全部音乐,加载最终分值
更新精灵组
更新与绘制背景图
更新与绘制敌机精灵组,如果有爆炸的敌机,需要绘制爆炸图
绘制英雄战机
更新与绘制子弹
绘制分值
如果英雄战机销毁,则调用结束方法
更新屏幕显示
from plane_sprites import *
# 设置游戏时钟(刷新频率)
TICK_TIMES = 60
# 设置敌机事件、创建敌机所需时间
EVENT_ENEMY=pygame.USEREVENT
CREATE_ENEMY_TIME=700
# 设置子弹事件、创建子弹所需时间
EVENT_BULLET=pygame.USEREVENT+1
CREATE_BULLET_TIME=500
# 总分值
TOTAL_SCORE=0
class PlaneGame:
"""飞机大战主类"""
def __init__(self):
# 初始化pygame模块
pygame.init()
# 初始化英雄生命
self.life=True
# 初始化开始菜单图片位置
self.startImgRect=pygame.Rect(0,0,0,0)
# 初始化游戏窗口
self.screen = pygame.display.set_mode(SCREEN_PRO.size)
# 初始化游戏时钟
self.clock = pygame.time.Clock()
# 初始化爆炸敌机对象
self.boomEnemy= {"boomEnemy":None,"times":0}
# 初始化精灵及精灵组相关
self.__create_sprites()
# 初始化 创建敌机定时器
pygame.time.set_timer(EVENT_ENEMY,CREATE_ENEMY_TIME)
# 初始化 创建子弹定时器
pygame.time.set_timer(EVENT_BULLET,CREATE_BULLET_TIME)
def __create_sprites(self):
# 创建背景精灵
bg1 = BackGround()
bg2 = BackGround(True)
# 创建精灵组,并放入背景精灵
self.bgGroup = pygame.sprite.Group(bg1, bg2)
# 创建敌机精灵组
self.enemyGroup=pygame.sprite.Group()
# 创建英雄战机
self.hero=Hero()
self.heroGroup=pygame.sprite.Group(self.hero)
# 创建子弹精灵组
self.bulletGroup=pygame.sprite.Group()
# 创建分值
self.font=FontSprites()
self.fontGroup=pygame.sprite.Group(self.font)
def start_game(self):
# 游戏循环开始
while True:
# 爆炸图片持续1秒
self.__enemy_boom()
# 设置刷新频率
self.clock.tick(TICK_TIMES)
# 监听事件
self.__event_handler()
if not self.life:
continue
# 碰撞检测
self.__check_collide()
# 更新精灵组
self.__update_group()
# 更新屏幕
pygame.display.update()
def __enemy_boom(self):
# 爆炸图片持续1秒
if self.boomEnemy["boomEnemy"] is not None:
enemyTimes = self.boomEnemy["times"]
self.boomEnemy["times"] = enemyTimes + 1
if enemyTimes > TICK_TIMES:
self.boomEnemy["boomEnemy"] = None
self.boomEnemy["times"] = 0
def __event_handler(self):
global TOTAL_SCORE
for event in pygame.event.get():
# 判断退出游戏
if event.type==pygame.QUIT:
PlaneGame.game_over()
# 监听鼠标点击开始游戏
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
print("鼠标点击了...x:%d ,y:%d,原始图片位置,x:%d,y:%d"%(x,y,self.startImgRect.x,self.startImgRect.y))
if self.startImgRect.collidepoint(x, y):
self.life = True
TOTAL_SCORE=0
pygame.quit()
PlaneGame().start_game()
# 监听英雄死亡
if not self.life:
continue
# 监听到创建敌机
if event.type==EVENT_ENEMY:
enemy=EnemyPlane()
enemy2 = EnemyPlane2()
self.enemyGroup.add(enemy)
self.enemyGroup.add(enemy2)
# 监听子弹
if event.type == EVENT_BULLET:
self.hero.fire(self.bulletGroup)
keyPressed=pygame.key.get_pressed()
if keyPressed[pygame.K_RIGHT]:
self.hero.update(3)
if keyPressed[pygame.K_LEFT]:
self.hero.update(-3)
def __update_group(self):
# 绘制背景
self.bgGroup.update()
self.bgGroup.draw(self.screen)
# 绘制敌机
self.enemyGroup.update()
self.enemyGroup.draw(self.screen)
boomEnemy=self.boomEnemy["boomEnemy"]
if boomEnemy:
# 绘制爆炸图片
self.screen.blit(boomEnemy.boomImg,(boomEnemy.rect.x,boomEnemy.rect.y))
# 绘制英雄
self.heroGroup.draw(self.screen)
# 绘制子弹
self.bulletGroup.update()
self.bulletGroup.draw(self.screen)
# 绘制分值
self.fontGroup.update()
self.screen.blit(self.font.textShow,(0,0))
# 更新游戏结束
if not self.life:
self.load_game_over()
def __check_collide(self):
global TOTAL_SCORE
# 子弹碰撞敌机,都销毁
dictG=pygame.sprite.groupcollide(self.bulletGroup,self.enemyGroup,True,True)
if dictG:
self.font.kill()
# 分值加1
TOTAL_SCORE += 1
self.font=FontSprites()
self.font.fontValue=TOTAL_SCORE
self.fontGroup.add(self.font)
# 爆炸敌机对象
enemy=list(dictG.values())[0][0]
# 将爆炸的敌机记录
self.boomEnemy["boomEnemy"]=enemy
# 播放音乐
enemy.plan_die()
# # 敌机碰撞英雄战机,都销毁
spriteList=pygame.sprite.spritecollide(self.hero,self.enemyGroup,True)
# 碰撞的敌机列表
if len(spriteList)>0:
# self.hero.kill()
self.life=False
self.load_game_over()
def load_game_over(self):
# 背景音乐停止
pygame.mixer.music.stop()
# 停止全部音效
pygame.mixer.stop()
# 加载游戏结束
img = pygame.image.load("./img/gameover1.png")
self.screen.blit(img, (0, 30))
# 加载开始菜单
startImg = pygame.image.load("./img/restart.png")
self.startImgRect=self.screen.blit(startImg, (150,img.get_rect().height+30))
# 加载文字
gameOverFont=FontSprites(40)
gameOverFont.fontValue=TOTAL_SCORE
gameOverFont.update((255,0,0))
self.screen.blit(gameOverFont.textShow,(200,250))
@staticmethod
def game_over():
print("游戏结束!!!!")
# 游戏退出
pygame.quit()
exit()
if __name__ == '__main__':
planGame = PlaneGame()
planGame.start_game()
程序猿与投资生活实录已改名为 程序猿知秋,WX同款,欢迎关注!