Python 的一个小项目 —— 飞机大战

一.安装pygame

1. 更新pip

之前装了 python 3.x 的任一个版本之后,会自己下载pip,用的时候更新以下,就可以了,打开cmd(快捷键:win + r),输入以下指令

python -m pip install -U pip
2.通过pip安装工具直接安装pygame

继续在cmd命令行输入

python -m pip install pygame
3. 检查是否安装成功

重新打开 cmd,先输入 python ,注意一定要先输入 python ,然后输入

import pygame

输出结果没有报错,并且输出 pygame
的版本号即为正确,还有一串英语,感觉就是个欢迎的语句

以上是在python的命令行打开的结果,使用pycharm编辑代码,在使用pygame碰到pygame不能正常使用的办法如下

file -> setting -> project(这里是你的项目名称) -> project interpreter 然后设置就好


二. pygame 入门

使用 pygame 创建图形窗口

  • 游戏的初始化和退出
  • 理解游戏中的坐标系
  • 创建游戏主窗口
  • 简单的游戏循环
  1. 简单游戏的初始化和退出
方法 说明
pygame.init() 导入并初始化所有 pygame 模块,使用其他模块之前,必须先调用 init 方法
游戏代码 游戏运行的代码
pygame.quit() 卸载所有 pygame 模块,在游戏结束之前调用

以上是使用pygame开发游戏时必须的两个模块

  1. 理解游戏中的坐标系
    1. 原点 在 左上角(0,0)
    2. x 轴是水平方向,从左向右,依次递增
    3. y 轴是垂直方向,从上向下,依次递增

在游戏中,所有可见的元素都是 使用矩形区域表示位置,所以要描述一个矩形需要四个元素:(x,y)(width,height)
(图形在 x 轴的位置,图形在 y 轴的位置)(图形的宽度,图形的高度)

pygame 专门提供了一个比较特殊的类 pygame。Rect 用于描述 矩形区域

Rect(x,y,width,height) -> Rect
pygame.Rect
x,y,left,top,bottom,right,center,centerx,centery,size,width,height

其中的size 是一个元组,输出结果为 (width,height)

pygame.Rect 是一个比较特殊的类,内部只是封装了一些数字计算,并不执行 pygame.init() 方法同样能够直接使用

  1. 创建游戏的主窗口
  • pygame 专门提供了一个模块 pygame.display 用于创建、管理 游戏窗口
方法 说明
pygame.display.set_mode() 初始化游戏显示窗口
pygame.display.update() 刷新屏幕内容显示,稍后使用

其中 set_mode()方法

set_mode(resolution=(0,0),flags=0,depth=0)  -> Surface
  • 作用 —— 创建游戏显示窗口
  • 参数
    • 若是参数形式为 带=,则表示为缺省参数
    • rersolution 指定屏幕的宽 和 高,默认创建的窗口大小和屏幕大小一致
    • flags 参数指定屏幕的附加选项,例如是否全屏等等,默认不需要传递
    • depth 参数表示颜色的位数,默认自动匹配
  • 返回值
    • 暂时 可以理解为 游戏的屏幕,游戏的元素 都需要被绘制到 游戏的屏幕上
  • 注意:必须使用变量记录 set_mode 方法的返回结果!
# 创建游戏主窗口
screen = pygame.display.set_mode(480,700)
  1. 简单的游戏循环

因为一般的 pygame 模块(目前学了不用这两个方法的是Rect)都必须有init 和 quit
方法,所以输出的游戏屏幕在显示器一闪而过,为了解决这一问题,引入了 游戏循环

import pygame

pygame.init()

# 创建游戏的窗口 480 * 700
screen = pygame.display.set_mode((480,700))

while True:
    pass

pygame.quit()

三. 理解 图像 并实现图像绘制

将保存的图片绘制到游戏屏幕上

  • 要在屏幕上看到一个图像的内容,需要按照三个步骤
  • 使用 pygame.image.load() 加载图像的数据
  • 使用 游戏屏幕 对象,调用 blit 方法,将图像绘制到指定位置
  • 调用 pygame.display.update() 方法更新整个屏幕的显示

第一步:

pygame.image
load(file_path)

第二步:

pygame.Surface
blit(图像,位置)

其中,图像是第一步的返回结果,位置是个元组(或者 背景.size应该也是可以的 )

第三步:

pygame.display.update()

注意:要想在屏幕上看到结果,就一定要调用 pygame.display.update() 方法

  • 代码演练 1 —— 绘制背景图像
import pygame
# import time

pygame.init()

# 创建游戏的窗口 480 * 700
screen = pygame.display.set_mode((480,700))

#  绘制背景图像
# 1> 加载图像数据
bg = pygame.image.load("./images/background.png")
# 2> 调用 blit 绘制图像
screen.blit(bg,(0,0))
# 3> update 更新屏幕显示
pygame.display.update()

while True:
    pass

#time.sleep(5)

pygame.quit()
  • 代码演练 II —— 绘制英雄图像
# 绘制英雄飞机的图像
# 1> 加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2> blit 绘制图像
screen.blit(hero,(150,500))
# 3> update 更新屏幕显示
pygame.display.update()

透明图像

png 格式的图像是支持 透明 的,在绘制图像时,透明区域 不会显示任何内容,即如果透明区域的下方有内容,会通过透明区域显示出来

理解 update 方法

可以在 screen 对象完成 所有 blit 方法之后,统一调用依次 display.update 方法,同样可以在屏幕上 看到最终的绘制结果

四. 游戏循环

无限循环 即为游戏循环,游戏循环的开始 就意味着 游戏的正式开始

游戏的两个组成部分

  • 游戏初始化

    • 设置游戏窗口
    • 绘制图像初始位置
    • 设置游戏时钟
  • 游戏循环

    • 设置刷新帧率 ( 每秒60帧 )
    • 检测用户交互 ( 用户的操作,如:移动鼠标、按动键盘等 )
    • 更新所有图像位置
    • 更新屏幕显示

游戏循环内部的代码,每秒更新60次

游戏时钟
  • 经实验证明 若不使用其他控制条件,则循环内部,每秒更新的频率超级快,但是我们并不需要这么快
  • pygame 专门提供了一个类 pygame.time.Clock 可以非常方便的设置屏幕绘制速度 —— 刷新帧率
  • 使用 时钟对象 需要两个步骤
    • 1)在 游戏初始化 中创建一个时钟对象
    • 2)在 游戏循环 中让时钟对象调用 **tick(帧率)**方法
  • tick 方法会根据 上次被调用的时间,自动设置 游戏循环 中的延时
# 创建时钟对象
clock = pygame.time.Clock()

# 无限循环 / 游戏循环 —— 意味这游戏的正式开始!
i= 0

while True:

    # 可以指定循环体内部的代码执行的频率
    clock.tick(1)

    print(i)
    i += 1
    pass
英雄简单动画实现
import pygame
# import time


# 游戏的初始化
pygame.init()

# 创建游戏的窗口 480 * 700
screen = pygame.display.set_mode((480,700))

#  绘制背景图像
# 1> 加载图像数据
bg = pygame.image.load("./images/background.png")
# 2> 调用 blit 绘制图像
screen.blit(bg,(0,0))
# 3> update 更新屏幕显示
# pygame.display.update()

# 绘制英雄飞机的图像
hero = pygame.image.load("./images/me1.png")
# screen.blit(hero,(150,300))

# 可以在所有绘制工作完成之后,统一调用 update 方法
pygame.display.update()

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

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

# 无限循环 / 游戏循环 —— 意味这游戏的正式开始!
while True:

    # 可以指定循环体内部的代码执行的频率
    clock.tick(60)

    # 2. 修改飞机的位置
    hero_rect.y -= 1

    # 判断飞机的位置
    if hero_rect.y <= -hero_rect.height:
        hero_rect.y = 700

    # 3. 调用 blit 方法绘制图像
    screen.blit(bg,(0,0))
    screen.blit(hero,hero_rect)

    # 4.调用 update 方法更新显示
    pygame.display.update()

#time.sleep(5)

pygame.quit()
在游戏循环中 监听 事件
事件 event

游戏启动后,用户针对游戏所作的操作,例如:点击关闭按钮、移动鼠标、按下按键……

监听
  • 在游戏循环中,判断用户的具体操作

只有 捕获 到用户具体的操作,才能有针对性的做出响应

代码实现
  • pygame 中通过 pygame.event.get() 可以获得 用户当前所作的事件列表
    • 用户可以同一时间做很多事情,所以返回值,是一个列表
  • 提示:这段代码非常 固定 ,几乎所有的 pygame 游戏都 大同小异
while True:

    # 可以指定循环体内部的代码执行的频率
    clock.tick(60)

    # 捕获事件
    event_list = pygame.event.get()
    for event in event_list:
        if event.type == pygame.QUIT:
            print("退出程序")

            # pygame 卸载所有的模块
            pygame.quit()
            # exit() 直接终止当前正在执行的程序
            exit()
        if len(event_list) > 0:
            print(event_list)

五. 精灵 和 精灵组

1. 精灵 和 精灵组
  • 在之前的学习中,图像加载、位置变化、绘制图像 都需要程序员编写代码处理。
  • 为了简化开发步骤,pygame 提供了两个类
    • pygame.sprite.Sprite —— 存储 图像数据 image 和位置 Rect 的对象
    • pygame.sprite.Group —— 创建精灵组
精灵
image 记录图像数据 ;rect 记录在屏幕上的位置
update(*args):更新精灵位置 ; kill():从所有组中删除
精灵组
__ init__(self,*精灵): / add(*sprites):向组中添加精灵 / sorites():返回所有精灵列表 / update(*args):让组中所有精灵调用 update 方法 / draw(Surface):将组中所有的 image ,绘制到Surface 的位置
  • 游戏初始化

    • 创建精灵
    • 创建精灵组
  • 游戏循环

    • 精灵组.update()
    • 精灵组.draw(screen)
    • pygame.display.update
2. 派生精灵子类

定义 GameSprite 继承自 pygame.sprite.Sprite

注意

  • 如果一个类的额父类不是 object 方法,在重写 初始化方法时,一定要先 super() 一下父类的 init 方法,保证父类中实现的 init 代码能够正常执行
GameSprite
image ; rect ; speed
__ init__(self,image_name,speed=1): / update(self)

属性

  • image 精灵图像,使用 image_name 加载
  • rect 精灵大小,默认使用图像大小
  • speed 精灵移动速度,默认值为 1

方法

  • update 每次更新屏幕时在游戏循环内调用
    • 让精灵的 self.rect.y += self.speed

提示

  • image 的 get_rect() 方法,可以返回 pygame.Rect(0,0,图像宽,图像高)的对象
import pygame

class GameSprites(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
3. 使用 游戏精灵 和 精灵组 创建敌机

需求

  • 使用各个派生的 游戏精灵 和 精灵组 创建敌机并且实现敌机动画
    步骤
  • 使用 from 导入 plan_sprites 模块
    • 使用 from 导入的模块可以直接使用
    • import 导入的模块需要通过模块名.来使用
  • 在 ** 游戏初始化** 创建精灵对象 和 精灵组对象
  • 游戏循环中让精灵组对象 分别调用 update() 和 draw(screen) 方法

职责

  • 精灵
    • 封装 图像image、位置rect 和 速度 speed
    • 提供 update() 方法,根据游戏需求,更新位置 rect
  • 精灵组
    • 包含多个精灵对象
    • update 方法,让精灵组中的所有精灵调用 update 方法
    • draw(screen) 方法,在 screen 上绘制精灵组中的所有精灵

使用定时器添加敌机

1. 定时器
  • 在 pygame 中可以使用 pygame.time.set_timer() 来添加定时器(所谓定时器,就是每隔一段时间,就去执行一些动作)
set_timer(eventid,milliseconds) -> None
  • 第一个参数 需要基于常量 pygame.USEREVENT 来指定
    • USEREVENT 是一个整数,再增加的事件,可以使用 USEREVENT + 1 指定
    • 可以在 游戏循环 的 事件监听方法中捕获到该事件
  • 第二个参数是 事件触发 间隔的毫秒数
  • set_timer 可以创建一个事件
定时器的监听
  • 通过 pygame.time.get() 方法可以获取当前时刻所有的 事件列表
  • 遍历列表 并且判断 event.type 是否等于 eventid,如果相等,表示定时器事件发生
2. 定义并监听创建敌机的定时器事件

pygame 的定时器创建套路

  1. 定义 定时器常量 —— eventid
  2. 在初始化方法中,调用 set_timer 方法设置定时器事件
  3. 在 游戏循环 中,监听定时器事件

Hero —— 英雄

  • 初始化方法
    • 指定 英雄图片
    • 初始速度 = 0 —— 英雄默认静止不动
    • 定义 bullets 子弹精灵组 保存精灵子弹
  • 重写 update() 方法
    • 英雄需要左右水平移动
    • 并且需要保证不能移出屏幕
  • 增加 bullets 属性,记录所有 子弹精灵
  • 增加 fire() 方法,用于发射子弹

子弹需求

  1. 子弹从英雄的正上方发射 沿直线向上方飞行
  2. 飞出屏幕后,需要从精灵组中删除
发布了78 篇原创文章 · 获赞 4 · 访问量 4118

猜你喜欢

转载自blog.csdn.net/weixin_43580746/article/details/104405027