飞机大战
0 pygame入门
初始化和退出:pygame.init() | 导入并初始化所有 pygame 模块,使用其他模块之前,必须先调用 init 方法
pygame.quit() | 卸载所有 pygame 模块,在游戏结束之前调用
坐标系:坐标原点在左上角,x 轴正方向水平向右;y 轴正方向垂直向下
元素:以矩形区域来描述位置。类 pygame.Rect 用于描述 矩形区域
窗口:pygame.display模块用于创建、管理游戏窗口,
注意:必须使用变量记录 set_mode 方法的返回结果,因为后续所有的图像绘制都基于这个返回结果
pygame.display.set_mode() | 初始化游戏显示窗口,指定宽、高、颜色深度等
pygame.display.update() | 刷新屏幕内容显示
游戏循环:为了使游戏程序启动后,不会立即退出,通常会在游戏程序中增加一个 游戏循环,即无限循环:while True: pass
保证游戏 不会直接退出、变化图像位置(造成动画效果)、检测用户交互(按键、鼠标等)
游戏图形:用 pygame.image.load() 加载图像的数据:bg = pygame.image.load("./images/background.png")
用 游戏屏幕 对象,调用 blit 方法 将图像绘制到指定位置:screen.blit(bg, (0, 0))
调用 pygame.display.update() 方法更新整个屏幕的显示:pygame.display.update()
帧 Frame:类 pygame.time.Clock 可以设置刷新帧率,
clock = pygame.time.Clock()
i = 0
while True:
clock.tick(60)
print(i)
i += 1
简单动画:初始化定义一个 pygame.Rect 的变量记录图像初始位置;在游戏循环中每次让变量的坐标移动;
每一次调用 update() 方法之前,需要把所有的游戏图像都重新绘制一遍;应最先重新绘制背景图像;
监听事件:事件event,就是游戏启动后,用户针对游戏所做的操作,如按键、鼠标等。
通过pygame.event.get() 可以获得用户当前所做动作的事件列表
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("退出游戏...")
pygame.quit()
exit()
游戏精灵:显示图像的对象 叫做精灵 Sprite,有两个重要属性:"image"要显示的图像和"rect "图像要显示在屏幕的位置
注意:pygame.sprite.Sprite 没有提供 image 和 rect 两个属性;需要程序员从 pygame.sprite.Sprite 派生子类
并在子类的初始化方法中设置 image 和 rect 属性
class GameSprite(pygame.sprite.Sprite):
"""游戏精灵基类"""
def __init__(self, image_name, speed=1):
super().__init__() # 调用父类的初始化方法;如果一个类的父类
# 不是 object,在重写初始化方法时,要先
# super() 父类的 __init__ 方法
self.image = pygame.image.load(image_name) # 加载图像
self.rect = self.image.get_rect() # 设置尺寸,image 的 get_rect() 方法
# 可以返回图像宽,高
self.speed = speed # 记录速度
def update(self, *args): # 默认在垂直方向移动
self.rect.top += self.speed
精灵组:一个精灵组可以包含多个精灵对象;可以自动调用组内每一个精灵的update() 方法;
可以将组内每一个精灵 的 image 绘制在 rect 位置
enemy1 = GameSprite("./images/enemy1.png") #创建敌机精灵1
enemy2 = GameSprite("./images/enemy1.png", 2) #创建敌机精灵2
enemy2.rect.x = 200
enemy_group = pygame.sprite.Group(enemy1, enemy2) #创建敌机精灵组
while True:
。。。。。。
enemy_group.update() #更新精灵组中所有精灵的位置
enemy_group.draw(screen) #更新位置后重新绘制在窗口中
。。。。。。
pygame.display.update() #绘制后更新显示
1 游戏主程序
import pygame
from plane_sprites import *
CREATE_ENEMY_EVENT = pygame.USEREVENT # 敌机出现事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1 # 发射子弹事件
class PlaneGame(object):
"""飞机大战游戏类"""
def __init__(self): # 0. 初始化
pygame.init() # 1. pygame 初始化
self.screen = pygame.display.set_mode(SCREEN_RECT.size)# 2. 创建游戏屏幕
self.clock = pygame.time.Clock() # 3. 创建游戏时钟
self.__create_sprites() # 4. 创建精灵组
PlaneGame.__create_user_events() # 5. 创建用户事件
def __create_sprites(self):
"""创建精灵组"""
bg1 = Background() # 背景组
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
enemy = Enemy() # 敌机组
self.enemy_group = pygame.sprite.Group(enemy)
self.hero = Hero() # 英雄组
self.hero_group = pygame.sprite.Group(self.hero)
@staticmethod
def __create_user_events():
"""创建用户事件"""
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1 * 1000) # 每秒添加一架敌机
pygame.time.set_timer(HERO_FIRE_EVENT, 500) # 每秒发射两次子弹
def start_game(self):
"""开始游戏"""
while True:
self.clock.tick(60) # 1. 设置刷新帧率
self.__event_handler() # 2. 事件监听
self.__update_sprites() # 3. 更新精灵组
self.__check_collide() # 4. 碰撞检测
pygame.display.update() # 5. 更新屏幕显示
def __event_handler(self):
"""事件监听"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("退出游戏...")
pygame.quit()
exit()
elif event.type == CREATE_ENEMY_EVENT:
self.enemy_group.add(Enemy()) # 创建敌机,并且添加到敌机组
# enemy_count = len(self.enemy_group.sprites()) # 测试敌机精灵数量
# print("敌机精灵数量 %d" % enemy_count)
elif event.type == HERO_FIRE_EVENT:
self.hero.fire() # 英雄发射子弹
keys_pressed = pygame.key.get_pressed() # 通过 pygame.key 获取用户按键
dir = keys_pressed[pygame.K_RIGHT] - keys_pressed[pygame.K_LEFT]
self.hero.speed = dir * 2 # 根据移动方向设置英雄的速度
def __update_sprites(self):
"""更新精灵组"""
for group in [self.back_group, self.enemy_group,self.hero_group, self.hero.bullets]:
group.update()
group.draw(self.screen)
def __check_collide(self):
"""碰撞检测"""
# 1. 子弹摧毁敌机
pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
# 2. 英雄被撞毁
collide_list = pygame.sprite.spritecollide(self.hero, self.enemy_group, False)
if len(collide_list) > 0:
self.hero.is_alive = False
print("英雄牺牲...")
pygame.quit()
exit()
if __name__ == '__main__':
# 1. 创建游戏对象
game = PlaneGame()
# 2. 开始游戏
game.start_game()
2 游戏对象,plane_sprites.py
import random
import pygame
SCREEN_RECT = pygame.Rect(0, 0, 480, 700) # 游戏屏幕大小
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, *args): # 默认在垂直方向移动
self.rect.top += self.speed
class Background(GameSprite):
"""背景精灵"""
def __init__(self, is_alt=False):
image_name = "./images/background.png"
super().__init__(image_name)
if is_alt: # 判断是否交替图片,如果是,将图片设置到屏幕顶部
self.rect.bottom = 0
def update(self, *args):
super().update(args) # 调用父类方法
if self.rect.top >= SCREEN_RECT.height: # 判断是否超出屏幕
self.rect.bottom = 0
class Enemy(GameSprite):
"""敌机精灵"""
def __init__(self):
image_name = "./images/enemy1.png"
super().__init__(image_name)
width = SCREEN_RECT.width - self.rect.width # 随机敌机出现位置
self.rect.left = random.randint(0, width)
self.rect.bottom = 0
self.speed = random.randint(1, 3) # 随机速度
def update(self, *args):
super().update(args)
if self.rect.top >= SCREEN_RECT.height: # 判断敌机是否移出屏幕
self.kill() # 将精灵从所有组中删除
class Hero(GameSprite):
"""英雄精灵"""
def __init__(self):
image_name = "./images/me1.png"
super().__init__(image_name, 0)
self.rect.centerx = SCREEN_RECT.centerx # 设置初始位置
self.rect.bottom = SCREEN_RECT.bottom - 120
self.bullets = pygame.sprite.Group() # 创建子弹组
def update(self, *args):
self.rect.left += self.speed # 飞机水平移动
if self.rect.left < 0: # 超出屏幕检测
self.rect.left = 0
if self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
def fire(self):
# bullet_count = len(self.bullets.sprites())
# print("子弹数量 %d" % bullet_count)
for i in range(0, 3):
bullet = Bullet() # 创建子弹精灵
bullet.rect.bottom = self.rect.top - i * 20 # 设置子弹位置
bullet.rect.centerx = self.rect.centerx
self.bullets.add(bullet) # 将子弹添加到精灵组
class Bullet(GameSprite):
"""子弹精灵"""
def __init__(self):
image_name = "./images/bullet1.png"
super().__init__(image_name, -2)
def update(self, *args):
super().update(args)
if self.rect.bottom < 0: # 判断是否超出屏幕
self.kill()