Python学习第二十一章 飞机大战(项目实战)

飞机大战(项目实战)

左右移动飞机,子弹可以消灭飞机

目的: 综合复习 面向对象

  1. 需要模块: pygame
    安装(在终端输入)
    sudo pip3 install pygame
    验证安装
    python3 -m pygame.examples.aliens

  2. 需要游戏素材照片

  3. 设计思路
    将静止的图片,放到游戏窗口中取
    通过用户交互,移动图片,产生动画效果

使用pygame创建游戏初始化窗口

pygame.init() 导入初始化 的pygame模块
pygame.quit() 卸载pygame模块

在这里插入图片描述

游戏窗口中的坐标系

在这里插入图片描述
x和y确定矩形的左上角出发点,width和height确定矩形的大小

pygame.React 用于描述矩阵区域

在这里插入图片描述

案例:
定义hero_act 描述英雄的位置和大小

import pygame

pygame.init()

hero_act = pygame.Rect(100, 500, 120, 125)
print("英雄原点 %d %d" % (hero_act.x, hero_act.y))
print("英雄尺寸 %d %d" % (hero_act.width, hero_act.height))
print('%d %d' % (hero_act.width, hero_act.height))
pygame.quit()

pygame 2.0.1 (SDL 2.0.14, Python 3.8.8)
Hello from the pygame community. https://www.pygame.org/contribute.html
英雄原点 100 500
英雄尺寸 120 125
120 125

创建游戏主窗口

pygame.display 用于创建,管理游戏窗口
在这里插入图片描述
在这里插入图片描述
setmodel创建游戏窗口,需要三个参数。
第一个参数:窗口大小
flags 附加选项
depth 颜色的位数,默认自动匹配
在这里插入图片描述

使用pygame绘制图像

第一步 加载图片
第二步 将 图片 blit到指定位置
第三步 调用pygame.display.update()更新屏幕

在这里插入图片描述

import pygame

pygame.init()

screen = pygame.display.set_mode((480, 700))

# 绘制背景图像
bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
pygame.display.update()

while True:
    pass
pygame.quit()

绘制英雄飞机图像

import pygame

pygame.init()

screen = pygame.display.set_mode((480, 700))

# 绘制背景图像
bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
pygame.display.update()

# 绘制英雄的图像
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (200, 500))
pygame.display.update()

while True:
    pass
pygame.quit()

update的作用

可以在所有绘制完成之后,统一调用update方法

screen 好比一个画布
screen.blit 在画布上 画图
display.update 展示最终画的情况

动起来

游戏动画实现原理: 跟电影类似,将多张图像连续快速播放。
在频幕上 快速绘制多张图像。

帧: 每个静止的画面
对应调用的 update方法
每秒60帧就可以产生连续高品质的动画效果。

在这里插入图片描述

游戏时钟

用于控制游戏内部循环的帧率

  1. 游戏初始化 创建 时钟对象
  2. 时钟对象调用tick(帧率)方法
    clock.tick(数字) 表示 每秒 循环 数字 次数
# 游戏初始化
pygame.init()

screen = pygame.display.set_mode((480, 700))

bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (200, 500))

pygame.display.update()

# 创建时钟对象
clock = pygame.time.Clock()
i = 0
while True:
    # 指定循环体 内部的代码执行的频率
    clock.tick(1) # 每秒循环1次
    print(i)
    i += 1
    pass
pygame.quit()

英雄的简单动画实现

在这里插入图片描述

import pygame

# 游戏初始化
pygame.init()

screen = pygame.display.set_mode((480, 700))

bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (150, 500))

pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()

# 定义rect 记录飞机的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)

i = 0
while True:
    # 指定循环体 内部的代码执行的频率,60表示每秒执行60次
    clock.tick(60)
    # 修改飞机的位置
    hero_rect.y -= 1
    # 调用blit方法
    screen.blit(bg, (0, 0))
    screen.blit(hero, hero_rect)
    # 调用update方法更新显示
    pygame.display.update()
pygame.quit()

升级版

import pygame

# 游戏初始化
pygame.init()

screen = pygame.display.set_mode((480, 700))

bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (150, 500))

pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()

# 定义rect 记录飞机的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)

i = 0
while True:
    # 指定循环体 内部的代码执行的频率,60表示每秒执行60次
    clock.tick(60)
    # 修改飞机的位置
    hero_rect.y -= 1
    # 判断飞机的位置 hero_rect.bottom是表示图片的底部
    if hero_rect.bottom <= 0:
        hero_rect.y = 700
    # 调用blit方法
    screen.blit(bg, (0, 0))
    screen.blit(hero, hero_rect)
    # 调用update方法更新显示
    pygame.display.update()
pygame.quit()

监听事件

事件(event): 用户针对游戏的操作
eg: 点击关闭按键,点击鼠标 按下键盘

监听: 判断用户 的具体操作

pygame.event.get() 可以获得用户当前所做动作 的 事件列表

import pygame

# 游戏初始化
pygame.init()

screen = pygame.display.set_mode((480, 700))

bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (150, 500))

pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()

# 定义rect 记录飞机的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)

i = 0
while True:
    # 指定循环体 内部的代码执行的频率,60表示每秒执行60次
    clock.tick(60)

    # 捕获事件
    event_list = pygame.event.get()
    if event_list:
        print(event_list)
    # 修改飞机的位置
    hero_rect.y -= 1
    # 判断飞机的位置 hero_rect.bottom是表示图片的底部
    if hero_rect.bottom <= 0:
        hero_rect.y = 700
    # 调用blit方法
    screen.blit(bg, (0, 0))
    screen.blit(hero, hero_rect)
    # 调用update方法更新显示
    pygame.display.update()
pygame.quit()

增加 退出事件 的捕获

在这里插入图片描述

import pygame

# 游戏初始化
pygame.init()

screen = pygame.display.set_mode((480, 700))

bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (150, 500))

pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()

# 定义rect 记录飞机的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)

i = 0
while True:
    # 指定循环体 内部的代码执行的频率,60表示每秒执行60次
    clock.tick(60)

    # 捕获事件
    event_list = pygame.event.get()
    for event in event_list:
        # 判断事件类型是否满足退出事件
        if event.type == pygame.QUIT:
            print("游戏退出...")
            # 卸载所有模块 退出
            pygame.quit()
            exit()
    # 修改飞机的位置
    hero_rect.y -= 1
    # 判断飞机的位置 hero_rect.bottom是表示图片的底部
    if hero_rect.bottom <= 0:
        hero_rect.y = 700
    # 调用blit方法
    screen.blit(bg, (0, 0))
    screen.blit(hero, hero_rect)
    # 调用update方法更新显示
    pygame.display.update()
pygame.quit()

精灵 和 精灵组

精灵: 包含了图像位置 和 显示的对象
精灵 通俗的理解:就好比一个可以移动的类,用来制作可以移动的对象。

在这里插入图片描述
精灵组: 包含多个精灵

目的是为了操控 所有精灵

在这里插入图片描述
在这里插入图片描述
精灵组 update 一下子更新所有精灵的位置
精灵组 draw 一下子 绘制所有精灵组的图片
精灵组display.update() 将图片展示出来

import pygame


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

派生精灵子类

新建 plane_sprites.py文件
在其中定义 GameSprite 继承 pygame.sprite.Sprite

封装三个属性:
图像
位置
速度
重写一个方法:
垂直方向的运动

在这里插入图片描述

使用游戏精灵 和 精灵组 创建敌机

在这里插入图片描述

#!/usr/bin/python3
# coding=utf-8
# Author by Zhenzhou Zhou
import pygame
from plane_sprites import *

# 游戏初始化
pygame.init()

screen = pygame.display.set_mode((480, 700))

bg = pygame.image.load("./images/background.png")
screen.blit(bg, (0, 0))
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (150, 500))

pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()

# 定义rect 记录飞机的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)

i = 0

# 创建敌机的精灵
enemy = GameSprite("./images/enemy1.png")
enemy1 = GameSprite("./images/enemy1.png", 2)

# 创建敌机的精灵组
enemy_group = pygame.sprite.Group(enemy, enemy1)

while True:
    # 指定循环体 内部的代码执行的频率,60表示每秒执行60次
    clock.tick(60)

    # 捕获事件
    event_list = pygame.event.get()
    for event in event_list:
        # 判断事件类型是否满足退出事件
        if event.type == pygame.QUIT:
            print("游戏退出...")
            # 卸载所有模块 退出
            pygame.quit()
            exit()
    # 修改飞机的位置
    hero_rect.y -= 1
    # 判断飞机的位置 hero_rect.bottom是表示图片的底部
    if hero_rect.bottom <= 0:
        hero_rect.y = 700
    # 调用blit方法
    screen.blit(bg, (0, 0))
    screen.blit(hero, hero_rect)
    # 调用update方法更新显示
    # 让精灵组调用两个方法
    # update - 让组中的所有精灵更新位置
    enemy_group.update()
    # draw  - 在screen上绘制所有的精灵
    enemy_group.draw(screen)
    pygame.display.update()
pygame.quit()

游戏框架的搭建

两个部分: 游戏初始化 和 游戏循环
游戏初始化:
创建游戏窗口,用于展示。
创建游戏时钟,通过时钟设置 刷新帧率。
根据游戏需求,创建 不同精灵 和 精灵组。

封装一个私有方法,用于 调用精灵组or精灵的属性,负责精灵组 和 精灵的创建。

游戏循环: 一旦开始执行,游戏就开始了。
start game 开启游戏循环。
设置刷新帧率,控制游戏内部代码执行的频率。
事件监听,捕获用户 对游戏的操作。
碰撞检测,玩家 和 敌机 碰撞,导致双方销毁。
更新,绘制精灵组在屏幕上,更新屏幕显示。
game over 结束游戏。
在这里插入图片描述
属性:
封装 屏幕 用于 精灵绘制
封装 时间 用于 设置刷新帧率
封装 精灵

方法:
初始化方法 完成 游戏初期制作
startgame 完成 游戏循环

明确几个文件用于开发游戏

两个文件
plane_main: 游戏主程序
plane_sprites: 屏幕尺寸,游戏子精灵
主游戏类文件: 负责启动游戏,创建玩家
飞机精灵文件 : 负责提供攻击的敌人 和 相关工具

在这里插入图片描述

常量和变量替代固定数值

常量: 不可变化的量
变量: 可以变化的量

定义常量 和 变量的语法完全一样,使用赋值语句
但是定义常量 时候,所有的字母都得使用大写,单词和单词之间使用下划线连接

SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
import pygame
from plane_sprites import *
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)


class PlaneGame(object):
    '''飞机大战主游戏'''
    def __init__(self):
        print("游戏初始化")
        # 创建游戏的窗口set_mode方法
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 调用私有方法,精灵和精灵组的创建
        self.__create_sprites()
    def __create_sprites(self):
        pass
    def start_game(self):
        print("游戏开始...")
        while True:
if __name__ == '__main__':
    # 创建游戏对象
    game = PlaneGame()
    # 启动游戏
    game.start_game()

主文件:框架

#!/usr/bin/python3
# coding=utf-8
# Author by Zhenzhou Zhou
import pygame
from plane_sprites import *


class PlaneGame(object):
    '''飞机大战主游戏'''

    def __init__(self):
        print("游戏初始化")
        # 创建游戏的窗口set_mode方法
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 调用私有方法,精灵和精灵组的创建
        self.__create_sprites()

    def __create_sprites(self):
        pass

    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()
            pass

    def __event_handler(self):
        for event in pygame.event.get():
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                PlaneGame.__game_over()

    def __check_collide(self):
        pass

    def __update_sprites(self):
        pass

    @staticmethod
    def __game_over():
        print("游戏结束")
        pygame.quit()
        exit()


if __name__ == '__main__':
    # 创建游戏对象
    game = PlaneGame()
    # 启动游戏
    game.start_game()

背景图像交替滚动实现

背景图像连续变化,游戏的玩家的位置并没有变化

在这里插入图片描述

class Background(GameSprite):
    '''游戏背景精灵'''

    def update(self):
        # 调用父类的方法实现
        super().update()
        # 判断是否移除屏幕,如果移除屏幕,将图像设置到屏幕的上方
        if self.rect.y >= SCREEN_RECT.height:
            self.rect.y = -self.rect.height

敌机出场

使用 定时器 添加 敌机
设计 Enemy类

使用定时器 添加敌机

  1. 游戏启动,每隔1s出现一架敌机
  2. 每架敌机向屏幕下方飞行,飞行速度不相同
  3. 每架敌机出现的 水平位置 不尽相同
  4. 当敌机从屏幕下方飞出,不再会飞回到屏幕中去

定时器

语法:

set_timer(eventid, milliseconds)

使用set_timer,每隔milliseconds时间创建一个(事件类型为eventid)的空事件。

定时器的监听:
通过pygame.event.get() 获取当前时刻所有事件列表。
遍历列表,判断event.type是否等于eventid,如果相等,表示 定时器事件 发生。

定义并监听创建敌机的定时器事件

定义定时器常量 eventid
初始化方法中,通过 set_timer 设定定时器事件
游戏循环中, 监听定时器事件

#!/usr/bin/python3
# coding=utf-8
# Author by Zhenzhou Zhou
import pygame
from plane_sprites import *


class PlaneGame(object):
    '''飞机大战主游戏'''

    def __init__(self):
        print("游戏初始化")
        # 创建游戏的窗口set_mode方法
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 调用私有方法,精灵和精灵组的创建
        self.__create_sprites()
        pygame.init()
        # 设置定时器事件 - 创建敌机 1s,这里单位是毫秒,100表示1秒
        # 表示 每1s创建一下CREATE_ENERMY_EVENT事件
        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)

    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()
            pass

    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('敌机出场......')

    def __check_collide(self):
        pass

    def __update_sprites(self):
        self.back_group.update()
        self.back_group.draw(self.screen)

    @staticmethod
    def __game_over():
        print("游戏结束")
        pygame.quit()
        exit()

if __name__ == '__main__':
    # 创建游戏对象
    game = PlaneGame()
    # 启动游戏
    game.start_game()

设计 Enemy类(敌人)

指定敌机的图片
随机 敌机的 初始位置 和 初始速度
在这里插入图片描述
初始化:
指定敌机图片
随机 敌机初始位置 和 初始速度

重写update方法
判断敌机是否飞出屏幕,如果是,从精灵组中删除

class Enemy(GameSprite):
    '''敌机精灵'''

    def __init__(self):
        # 调用父类方法,创建敌机精灵,指定敌机图片
        super().__init__('./imaegs/enemy1.png')

        # 指定敌机的初始随机速度

        # 指定敌机的初始随机位置

        pass

    def update(self):
        # 调用父类方法,保持垂直方向的飞行
        super().update()
        # 判断是否飞出屏幕,如果是,需要从精灵组删除敌机
        if self.rect.y >= SCREEN_RECT.height:
            print("飞出屏幕,需要从精灵组删除...")
        pass

创建敌机

在__create_sprites中,添加 敌机精灵组
敌机是定时被创建的, 初始化方法中,不需要创建敌机
在__event_hander 创建敌机,添加到精灵组
在 __update_sprites,让敌机精灵组调用update和draw方法
在这里插入图片描述

    def __create_sprites(self):
        # 创建 背景精灵 和 精灵组
        bg1 = Background()
        bg2 = Background(True)

        self.back_group = pygame.sprite.Group(bg1, bg2)
        # 创建敌机的精灵组
        self.enemy_group = pygame.sprite.Group()
    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 __update_sprites(self):
        self.back_group.update()
        self.back_group.draw(self.screen)

        self.enemy_group.update()  # 更新所有敌机位置
        self.enemy_group.draw(self.screen)  # 将敌机位置绘制到图上

随机敌机位置 和速度

导入模块顺序:
官方标准模块
第三方模块
应用程序模块
在这里插入图片描述
在这里插入图片描述

移除屏幕前 销毁敌机

敌机移出屏幕前,销毁敌机

class Enemy(GameSprite):
    '''敌机精灵'''

    def __init__(self):
        # 调用父类方法,创建敌机精灵,指定敌机图片
        super().__init__('./images/enemy1.png')

        # 指定敌机的初始随机速度(1~~3)
        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()

    def __del__(self):
        print("敌机挂了! %s" % self.rect)

玩家飞机登场

两个 类:
玩家飞机 (英雄)
子弹
在这里插入图片描述
定时器功能:发射字典
键盘控制 飞机移动: pygame.keyboard
在这里插入图片描述
子弹上飞 y值不断减少,子弹的初始速度设置为负数
子弹飞出屏幕,从精灵组中删除,避免占用内存

飞机定义发射子弹
在这里插入图片描述
重接介绍React的属性
在这里插入图片描述
在这里插入图片描述

class Hero(GameSprite):
    '''玩家飞机-英雄精灵'''

    def __init__(self):
        # 调用父类,设置 image和speed
        super().__init__('./images/me1.png', 0)  # 初始速度为0
        # 设置英雄初始位置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 120

    def __create_sprites(self):
        # 创建 背景精灵 和 精灵组
        bg1 = Background()
        bg2 = Background(True)
        self.back_group = pygame.sprite.Group(bg1, bg2)

        # 创建敌机的精灵 和 精灵组
        self.enemy_group = pygame.sprite.Group()

        # 创建英雄的精灵 和 精灵组
        self.hero = Hero()
        self.hero_group = pygame.sprite.Group(self.hero)

    def __update_sprites(self):
        self.back_group.update()
        self.back_group.draw(self.screen)

        self.enemy_group.update()  # 更新所有敌机位置
        self.enemy_group.draw(self.screen)  # 将敌机位置绘制到图上

        self.hero_group.update()
        self.hero_group.draw(self.screen)

移动英雄的位置

捕获键盘 按键 操作
在这里插入图片描述

    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)
            # 键盘按键:方法1
            # elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            #     print('向右移动...')

            # 使用键盘提供方法-按键元组:方法2
            key_pressed = pygame.key.get_pressed()
            if key_pressed[pygame.K_RIGHT]:
                print('向右移动...')

移动英雄位置

叠加speed 和rect.x
通过update方法
在这里插入图片描述
先准备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)
            # 键盘按键:方法1
            # elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            #     print('向右移动...')

            # 使用键盘提供方法-按键元组:方法2
            key_pressed = pygame.key.get_pressed()
            if key_pressed[pygame.K_RIGHT]:
                print('向右移动...')
                self.hero.speed = 2
            elif key_pressed[pygame.K_LEFT]:
                print('向左移动...')
                self.hero.speed = -2

class Hero(GameSprite):
    '''玩家飞机-英雄精灵'''

    def __init__(self):
        # 调用父类,设置 image和speed
        super().__init__('./images/me1.png', 0)  # 初始速度为0
        # 设置英雄初始位置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 120

    def update(self):
        # 英雄在水平方向移动
        self.rect.x += self.speed
        

控制英雄的移动位置

update方法

理解 react的right属性
在这里插入图片描述

    def update(self):
        # 英雄在水平方向移动
        self.rect.x += self.speed
        # 控制英雄不能离开屏幕
        if self.rect.x < 0:
            self.rect.x = 0
        elif self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right

发射子弹

在这里插入图片描述
英雄类 准备fire方法
一旦检测到发射子弹事件,就让英雄调用fire方法

class PlaneGame(object):
    '''飞机大战主游戏'''

    def __init__(self):
        print("游戏初始化")
        # 创建游戏的窗口set_mode方法
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 调用私有方法,精灵和精灵组的创建
        self.__create_sprites()
        pygame.init()
        # 设置定时器事件 - 创建敌机 1s
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
        # 设置定时器事件 - 发射子弹 0.5s(每隔0.5s发生子弹)
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)

    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)
            # 键盘按键:方法1
            # elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            #     print('向右移动...')

            # 使用键盘提供方法-按键元组:方法2
            key_pressed = pygame.key.get_pressed()
            if key_pressed[pygame.K_RIGHT]:
                print('向右移动...')
                self.hero.speed = 2
            elif key_pressed[pygame.K_LEFT]:
                print('向左移动...')
                self.hero.speed = -2
            elif event.type == HERO_FIRE_EVENT:
                self.hero.fire()

    def fire(self):
        print("发射子弹")

定义子弹类

子弹 从英雄正上方,向上方飞行(速度设置为负数)
飞出屏幕后,从精灵组中删除

在这里插入图片描述

class Bullet(GameSprite):
    '''子弹精灵'''

    def __init__(self):
        # 调用父类方法,设置子弹图片。设置初始速度
        super().__init__('./images/bullet1.png', -2)
        

    def update(self):
        # 调用父类方法,让子弹沿着垂直方向飞行
        super().update()
        
        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            self.kill()
    def __del__(self):
        print('子弹被销毁了...')

发射子弹

在这里插入图片描述

class Bullet(GameSprite):
    '''子弹精灵'''

    def __init__(self):
        # 调用父类方法,设置子弹图片。设置初始速度
        super().__init__('./images/bullet1.png', -2)

    def update(self):
        # 调用父类方法,让子弹沿着垂直方向飞行
        super().update()

        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            self.kill()

    def __del__(self):
        print('子弹被销毁了...')

一次发射三个子弹

以玩家飞机 为标准
上方 三个位置三个子弹
0 20 40
在这里插入图片描述

    def fire(self):
        print("发射子弹")
        for i in (0, 1, 2):
            # 创建子弹精灵
            bullet = Bullet()
            # 设置精灵位置 (水平位置 和 垂直位置)
            # 指定 y值
            bullet.rect.bottom = self.rect.y - i * 20  # 在英雄上方0,20,40高处
            # 指定 中心点
            bullet.rect.centerx = self.rect.centerx
            # 将子弹精灵添加到精灵组
            self.bullets.add(bullet)

碰撞检测

pygame.sprite.groupcollide()
4个参数
group1对象 和 group2对象 都是精灵组
检测这两个精灵组的精灵对象 是否相碰
dokill1 摧毁精灵1
dokill2 摧毁精灵2
在这里插入图片描述

    def __check_collide(self):
        # 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)

在这里插入图片描述
方法会返回一个列表
Sprite_list 列表

    def __check_collide(self):
        # 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
        # 敌机撞毁英雄
        ememies = pygame.sprite.groupcollide(self.hero_group, self.enemy_group, False, True)
        # 判断列表是否有内容
        if len(ememies) > 0:
            # 让英雄牺牲
            self.hero.kill()
            # 结束游戏
            PlaneGame.__game_over()

最后代码总结

两个文件
plan_main.py

#!/usr/bin/python3
# coding=utf-8
# Author by Zhenzhou Zhou
import pygame
from plane_sprites import *


class PlaneGame(object):
    '''飞机大战主游戏'''

    def __init__(self):
        print("游戏初始化")
        # 创建游戏的窗口set_mode方法
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 调用私有方法,精灵和精灵组的创建
        self.__create_sprites()
        pygame.init()
        # 设置定时器事件 - 创建敌机 1s
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
        # 设置定时器事件 - 发射子弹 0.5s(每隔0.5s发生子弹)
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)

    def __create_sprites(self):
        # 创建 背景精灵 和 精灵组
        bg1 = Background()
        bg2 = Background(True)
        self.back_group = pygame.sprite.Group(bg1, bg2)

        # 创建敌机的精灵 和 精灵组
        self.enemy_group = pygame.sprite.Group()

        # 创建英雄的精灵 和 精灵组
        self.hero = Hero()
        self.hero_group = pygame.sprite.Group(self.hero)

    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()
            pass

    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)
            # 键盘按键:方法1
            # elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            #     print('向右移动...')

            # 使用键盘提供方法-按键元组:方法2
            key_pressed = pygame.key.get_pressed()
            if key_pressed[pygame.K_RIGHT]:
                print('向右移动...')
                self.hero.speed = 2
            elif key_pressed[pygame.K_LEFT]:
                print('向左移动...')
                self.hero.speed = -2
            elif event.type == HERO_FIRE_EVENT:
                self.hero.fire()

    def __check_collide(self):
        # 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
        # 敌机撞毁英雄
        ememies = pygame.sprite.groupcollide(self.hero_group, self.enemy_group, False, True)
        # 判断列表是否有内容
        if len(ememies) > 0:
            # 让英雄牺牲
            self.hero.kill()
            # 结束游戏
            PlaneGame.__game_over()

    def __update_sprites(self):
        self.back_group.update()
        self.back_group.draw(self.screen)

        self.enemy_group.update()  # 更新所有敌机位置
        self.enemy_group.draw(self.screen)  # 将敌机位置绘制到图上

        self.hero_group.update()
        self.hero_group.draw(self.screen)

        # 让子弹精灵组更新
        self.hero.bullets.update()
        self.hero.bullets.draw(self.screen)

    @staticmethod
    def __game_over():
        print("游戏结束")
        pygame.quit()
        exit()


if __name__ == '__main__':
    # 创建游戏对象
    game = PlaneGame()
    # 启动游戏
    game.start_game()

plane_sprites.py

#!/usr/bin/python3
# coding=utf-8
# Author by Zhenzhou Zhou
import random
import pygame

# 屏幕大小常量
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 刷新的帧率
FRAME_PER_SEC = 60
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1


class GameSprite(pygame.sprite.Sprite):
    """飞机大战游戏-精灵"""

    def __init__(self, image_name, speed=1):
        # 调用父类初始化方法
        super().__init__()
        # 定义对象的属性
        # 图像名
        self.image = pygame.image.load(image_name)
        # 图像初始化位置 get_react()会自动计算图像矩阵
        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):

        # 调用父类方法实现精灵的创建(image/rect/speed)
        super().__init__("./images/background.png")

        # 判断是否是交替互相,如果是,设置初始位置
        if is_alt:
            self.rect.y = -self.rect.height

    def update(self):
        # 调用父类的方法实现
        super().update()
        # 判断是否移除屏幕,如果移除屏幕,将图像设置到屏幕的上方
        if self.rect.y >= SCREEN_RECT.height:
            self.rect.y = -self.rect.height


class Enemy(GameSprite):
    '''敌机精灵'''

    def __init__(self):
        # 调用父类方法,创建敌机精灵,指定敌机图片
        super().__init__('./images/enemy1.png')

        # 指定敌机的初始随机速度(1~~3)
        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()

    def __del__(self):
        # print("敌机挂了! %s" % self.rect)
        pass


class Hero(GameSprite):
    '''玩家飞机-英雄精灵'''

    def __init__(self):
        # 调用父类,设置 image和speed
        super().__init__('./images/me1.png', 0)  # 初始速度为0
        # 设置英雄初始位置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 120
        # 创建子弹精灵组
        self.bullets = pygame.sprite.Group()

    def update(self):
        # 英雄在水平方向移动
        self.rect.x += self.speed
        # 控制英雄不能离开屏幕
        if self.rect.x < 0:
            self.rect.x = 0
        elif self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right

    def fire(self):
        print("发射子弹")
        for i in (0, 1, 2):
            # 创建子弹精灵
            bullet = Bullet()
            # 设置精灵位置 (水平位置 和 垂直位置)
            # 指定 y值
            bullet.rect.bottom = self.rect.y - i * 20  # 在英雄上方0,20,40高处
            # 指定 中心点
            bullet.rect.centerx = self.rect.centerx
            # 将子弹精灵添加到精灵组
            self.bullets.add(bullet)


class Bullet(GameSprite):
    '''子弹精灵'''

    def __init__(self):
        # 调用父类方法,设置子弹图片。设置初始速度
        super().__init__('./images/bullet1.png', -2)

    def update(self):
        # 调用父类方法,让子弹沿着垂直方向飞行
        super().update()

        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            self.kill()

    def __del__(self):
        print('子弹被销毁了...')
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值