游戏框架
整体来看,飞机大战游戏只需要两个文件:
plane_main.py
- 封装 主游戏类
- 创建 游戏对象
- 启动游戏
plane_sprites.py
- 封装游戏中所有需要使用的 精灵子类
- 提供精灵的 相关工具
主游戏类
飞机大战主游戏类命名为 PlaneGame
,这个类应包含的函数为:
其中:
__init__
:游戏初始化__create_sprites(self)
:创建精灵和精灵组
start_game()
:游戏循环__event_handler(self)
:事件监听__check_collide(self)
:碰撞检测 —— 子弹销毁敌机、敌机撞毁英雄__update_sprites(self)
:精灵组更新和绘制__game_over()
:游戏结束
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飞机大战主游戏"""
def __init__(self):
print("游戏初始化...")
pass
def start_game(self):
print("开始游戏...")
pass
if __name__ == '__main__':
PlaneGame().start_game()
__init__(self)
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
def __init__(self):
print("游戏初始化")
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
self.clock = pygame.time.Clock()
self.__create_sprites()
这里使用到了 常量,一般约定是全部字母大写。
start_game()
FPS = 60
def start_game(self):
"""游戏循环"""
print("开始游戏...")
while True:
self.clock.tick(FPS)
self.__event_handler()
self.__check_collide()
self.__update_sprites()
pygame.display.update()
其中,事件监听和游戏结束的代码如下:
def __event_handler(self):
"""事件监听"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
PlaneGame.__game_over()
@staticmethod
def __game_over():
"""游戏结束"""
print("游戏结束")
pygame.quit()
exit()
碰撞检测 和 更新精灵组 之后再细说。
准备精灵组
创建精灵组
def __create_sprites(self):
"""创建精灵组"""
self.back_group = pygame.sprite.Group()
self.enemy_group = pygame.sprite.Group()
self.hero_group = pygame.sprite.Group()
更新精灵组
def __update_sprites(self):
"""更新精灵组"""
for group in [self.back_group, self.enemy_group, self.hero_group]:
group.update()
group.draw(self.screen)
背景图像
背景图像应不断地向下方移动,这样在视觉上就是英雄的飞机不断向上方飞行。这是很多跑酷游戏常用的套路。
实现思路
两张背景图纵向拼接到一起,一起向下移动。当其中一张的 rect.y
>= 屏幕的高度,则说明已经移动到了屏幕下方,此时将另一张图像设置回屏幕的上方 rect.y = -rect.height
即可。
之前已经设计了一个游戏精灵类 GameSpirte
:
class GameSprite(pygame.sprite.Sprite):
"""游戏精灵基类"""
def __init__(self, image_name, speed=5):
super().__init__()
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speed = speed
def update(self, *args):
self.rect.y += self.speed
因此,只需创建一个 背景类,继承父类 GameSpirte
的方法,适当重写即可。plane_spirtes.py
:
class Background(GameSprite):
"""游戏背景精灵"""
def update(self):
super().update()
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
plane_main.py
:
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background("./images/background.png")
bg2 = Background("./images/background.png")
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
简化
根据面向对象设计原则,应该将对象的职责封装到类内部,并且尽量简化程序调用。
因此可进行如下改进:
plane_sprites.py
中 Background
的初始化方法:
def __init__(self, is_alt=False):
super().__init__("./images/background.png")
if is_alt:
self.rect.y = -self.rect.height
plane_main
中的 __create_sprites
方法:
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
敌机
设计 Enemy
类,然后使用 定时器 添加敌机。
定时器
使用 pygame.time.set_timer(eventid, milliseconds)
创建定时器。
eventid
:事件代号,基于常量pygame.USEREVENT
来指定USEREVENT
是一个整数,再增加的事件可以使用USEREVENT + 1
指定
milliseconds
:事件触发间隔的毫秒值
创建定时器步骤:
- 定义定时器常量
eventid
- 在初始化方法中调用
set_timer
创建定时器事件 - 在游戏循环中监听
plane_sprites.py
:
CREATE_ENEMY_EVENT = pygame.USEREVENT
在 plane_main.py
中 PlaneGame
的 初始化方法 中创建事件:
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
在 plane_main.py
中 __event_handler
的方法中进行监听:
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("敌机出场...")
self.enemy_group.add(Enemy())
敌机类的设计
- 每隔 1 秒会出现一架敌机
- 敌机向屏幕下方飞行,速度各不相同,水平位置也不尽相同
- 当敌机从屏幕下方飞出,销毁
plane_sprites.py
:
import random
- 在导入模块时,建议按照以下顺序导入
1. 官方标准模块导入 2. 第三方模块导入 3. 应用程序模块导入
class Enemy(GameSprite):
"""敌机精灵"""
def __init__(self):
super().__init__("./images/enemy1.png")
self.speed = random.randint(1, 3)
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
def update(self):
super().update()
if self.rect.y >= SCREEN_RECT.height:
print("敌机飞出屏幕...")
self.kill()
敌机飞出屏幕之后,为节省内存,应将其从敌机组删除。__del__
内置方法会在对象被销毁前调用,可用于判断对象是否被销毁。
def __del__(self):
print("敌机挂了 %s" % self.rect)
在 plane_game.py
文件中,创建敌机精灵组并更新,代码略。