Python学习日记-第二十四天-飞机大战(敌机出场设计)
系列文章目录
·使用定时器添加敌机
·设计Enemy 类
前言
昨天因为有事,所以没有及时更新
一、使用定时器添加敌机
- 游戏启动后,每隔一秒会出现一架敌机
- 每架敌机向屏幕下方飞行,飞行速度各不相同
- 每架敌机出现的水平位置也不尽相同
当敌机从屏幕飞出,不会再飞回屏幕中
1.1 定时器
·在Python中,可以使用 pygame.time.set_timer()来添加定时器
·所谓的定时器,就是每隔一段时间,去执行一些动作
代码: set_timer(eventid, milliseconds) -> None
·set_timer 可以创建一个事件
·可以在游戏循环的事件监听方法中捕获到该事件
·第1个参数 事件代码需要基于常量pygame.USEREVENT来指定
USEREVENT是一个整数,再增加的事件可以使用 USEREVENT+1 指定,以此类推
·第2个参数是事件触发 间隔 的毫秒值
定时器事件的监听
·通过pygame.event.get()可以获得当前时刻所有的事件列表
·遍历列表并且判断 event.type 是否等于event.id 如果相等,表示定时器事件发生
1.2 定义并监听创建敌机事件
pygame的定时器使用套路非常固定:
- 定义定时器常量——eventid
- 在初始化方法中,调用set_timer方法设置定时器事件
- 在游戏循环中,监听定时器事件
1)定义事件
·在plane_sprites.py的顶部定义 事件常量
这里虽然pygame 提供了一个 pygame.USEREVENT的常量,但是在我们开发时,还是会针对我们的游戏需求,以及特有的事件,定义一个名字更加方便我们理解的事件常量,会更加的合理,所以我们在这里创建了一个 CREAT_ENEMY_EVENT的常量
这里设置的时间是1000,是因为单位是以毫秒计算的,1000毫秒=1秒
再在之前封装好的 event_handler 监听事件方法里面,增加一个判断,最后再控制台观察“敌机出场”是否是间隔一秒出现一次
二、 设计Enemy类
- 游戏启动后,每隔一秒会出现一架敌机
- 每架敌机向屏幕下方飞行,飞行速度各不相同
- 每架敌机出现的水平位置也不尽相同
- 当敌机从屏幕飞出,不会再飞回屏幕中
·初始化方法
指定 敌机图片
随机 敌机的初始位置和初始速度
·重写update方法
判断是否飞出屏幕,如果是,从精灵族删除
2.1 敌机类的准备
代码:
class Enemy(GameSprite):
"""敌机精灵"""
def __init__(self):
# 1.调用父类方法,创建敌机精灵,同时指定敌机图片
super().__init__("./images/enemy1.png")
# 2.指定敌机的初始随机速度
# 3.指定敌机的初始随机位置
pass
def update(self):
# 1. 调用父类方法,保持垂直方向的飞行
super().update()
# 2. 判断是否飞出屏幕,飞出了,就冲精灵组删除敌机
if self.rect.y >= SCREEN_RECT.height:
print("飞出屏幕,需要从精灵组删除")
2.2 创建敌机
演练步骤
1. 在__create_sprites,添加敌机精灵组
·敌机是定时被创建的,因此在初始化方法中,不需要创建敌机
2. 在__event_handler,创建敌机,并且添加到精灵组
·调用精灵组的 add 方法可以像精灵族添加精灵
3. 在 __update_sprites,让敌机精灵组调用update和draw方法
代码:
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飞机大战主游戏"""
def __init__(self):
print("游戏初始化")
# 1.创建游戏的窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 2.创建游戏的时钟
self.clock = pygame.time.Clock
# 3.调用私有方法,精灵和精灵组的创建
self.__create_sprites()
# 4. 设置定时器事件-创建敌机 1s
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
# 创建敌机的精灵组
self.enemy_group = pygame.sprite.Group()
def start_game(self):
print("游戏开始...")
while True:
# 1.设置刷新帧率
self.clock().tick(FRAME_PER_SEC)
# 2.事件监听
self.__event_handler()
# 3.碰撞检测
self.__check_collide()
# 4.更新/绘制精灵组
self.__update_sprites()
# 5.更新显示
pygame.display.update()
def __event_handler(self):
for event in pygame.event.get():
# 判断是否退出游戏
if event.type == pygame.QUIT:
PlaneGame.__game_over()
elif event.type == CREATE_ENEMY_EVENT:
print("敌机出场")
# 创建敌机精灵
enemy = Enemy()
# 将敌机精灵添加到敌机精灵组
self.enemy_group.add(enemy)
def __check_collide(self):
pass
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
self.enemy_group.update()
self.enemy_group.draw(self.screen)
@staticmethod
def __game_over():
print("游戏结束")
pygame.quit()
exit()
if __name__ == '__main__':
# 创建游戏对象
game = PlaneGame()
# 启动游戏
game.start_game()
运行结果:
屏幕每间隔1秒钟,就会生出一架敌机
2.3 随机敌机位置和速度
1. 导入模块(随机速度)
·在导入模块时,建议 按照以下顺序导入
- 官方标准模块导入
- 第三方模块导入
- 应用程序导入
·修改 plane_sprites.py增加random的导入(random模块 在Python中是数字随机,之前有讲过的,random模块时官方标准模块)
import random
运行结果:
敌机的速度都是随机1 - 3了
2. 随机位置
敌机的初始位置x,y的值都是要设置的,通过上面的图解可以了解清楚
使用pygame.Rect 提供的bottom属性,在指定敌机初始位置时,会比较方便
·bottom = y + height
·y = bottom - height
操作:
代码:
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
运行结果:
2.4 移出屏幕销毁敌机(清除内存)
·敌机移出屏幕之后,如果没有碰撞到英雄,敌机的历史使命结束
·需要从敌机组删除,否则会造成内存浪费
检测敌机被销毁
·__del__内置方法会在对象被销毁前调用,在开发中,可以用于判断对象是否被销毁
·判断敌机是否飞出屏幕,如果是,调用kill() 方法从所有组中删除
代码:
def update(self):
# 1. 调用父类方法,保持垂直方向的飞行
super().update()
# 2. 判断是否飞出屏幕,飞出了,就冲精灵组删除敌机
if self.rect.y >= SCREEN_RECT.height:
print("飞出屏幕,需要从精灵组删除")
self.kill()
总结
关于敌机出场的设计就已经设计完成,目前所有的代码总结一下:
1. plane_sprites.py:
import random
import pygame
# 屏幕大小的常量
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 定义刷新帧率
FRAME_PER_SEC = 60
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
class GameSprite(pygame.sprite.Sprite):
"""飞机大战游戏精灵"""
def __init__(self, image_name, speed=1):
# 调用父类的初始化方法
super().__init__()
# 定义对象的属性
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speed = speed
def update(self):
# 在屏幕的垂直方向上移动
self.rect.y += self.speed
class Background(GameSprite):
"""游戏背景精灵"""
def __init__(self, is_alt=False):
# 1.调用父类方法实现精灵的创建(images/rect/speed)
super().__init__("./images/background.png")
# 2.判断是否是交替图像,如果是,需要设置初始位置
if is_alt:
self.rect.y = -self.rect.height
def update(self):
# 1.调用父类的方法实现(垂直在屏幕方向向上移动)
super().update()
# 2.判断是否移出屏幕,如果移出屏幕,将图像设置到屏幕上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
class Enemy(GameSprite):
"""敌机精灵"""
def __init__(self):
# 1.调用父类方法,创建敌机精灵,同时指定敌机图片
super().__init__("./images/enemy1.png")
# 2.指定敌机的初始随机速度1 ~ 3
self.speed = random.randint(1, 3)
# 3.指定敌机的初始随机位置
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
def update(self):
# 1. 调用父类方法,保持垂直方向的飞行
super().update()
# 2. 判断是否飞出屏幕,飞出了,就冲精灵组删除敌机
if self.rect.y >= SCREEN_RECT.height:
print("飞出屏幕,需要从精灵组删除")
self.kill()
2. plane_main.py
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飞机大战主游戏"""
def __init__(self):
print("游戏初始化")
# 1.创建游戏的窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 2.创建游戏的时钟
self.clock = pygame.time.Clock
# 3.调用私有方法,精灵和精灵组的创建
self.__create_sprites()
# 4. 设置定时器事件-创建敌机 1s
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
# 创建敌机的精灵组
self.enemy_group = pygame.sprite.Group()
def start_game(self):
print("游戏开始...")
while True:
# 1.设置刷新帧率
self.clock().tick(FRAME_PER_SEC)
# 2.事件监听
self.__event_handler()
# 3.碰撞检测
self.__check_collide()
# 4.更新/绘制精灵组
self.__update_sprites()
# 5.更新显示
pygame.display.update()
def __event_handler(self):
for event in pygame.event.get():
# 判断是否退出游戏
if event.type == pygame.QUIT:
PlaneGame.__game_over()
elif event.type == CREATE_ENEMY_EVENT:
print("敌机出场")
# 创建敌机精灵
enemy = Enemy()
# 将敌机精灵添加到敌机精灵组
self.enemy_group.add(enemy)
def __check_collide(self):
pass
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
self.enemy_group.update()
self.enemy_group.draw(self.screen)
@staticmethod
def __game_over():
print("游戏结束")
pygame.quit()
exit()
if __name__ == '__main__':
# 创建游戏对象
game = PlaneGame()
# 启动游戏
game.start_game()
目前主程序运行结果:
敌机随机从屏幕上方飞出,速度设置的是(1-3)之间的随机速度,飞出屏幕之后自动销毁