【简介】

Pygame 是python用来开发视频游戏的游戏引擎,底层主要是SDL库实现,算是目前利用python开发小游戏的一个性能比较高的一个游戏框架

一、安装pygame

使用pip下载安装

pip install pygame

二、入门案例详析

1、示例效果

在这里插入图片描述

2、示例代码

import os
import pygame
# 标识是否退出循环
exitFlag = False
# 设置画面刷新的帧率,即1s内刷新几次
FPS = 10
# 初始化pygame游戏引擎
pygame.init()
# 指定窗口的坐标(x,y),默认屏幕中央
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 25)
# 设置窗口大小
surface = pygame.display.set_mode((800, 500))
# 设置窗口标题
pygame.display.set_caption("pygame教程")
# 设置icon
icon = pygame.image.load('E:\AS-workspace\pygameTest\drawable\icon.png').convert_alpha()
pygame.display.set_icon(icon)
# 加载本地图片
bgSurface = pygame.image.load('E:\AS-workspace\pygameTest\drawable\BG.jpg').convert()
# 获取游戏时钟
clock = pygame.time.Clock()
# 图片缩放
scaleImg = pygame.transform.scale(icon, (400, 400))
# 获取图片的矩形框
rect = scaleImg.get_rect()
# 移动步长
step = 10
# 绘制背景
surface.blit(bgSurface,(0,0))
# 刷新帧率
newRect = None
while not exitFlag:
    clock.tick(FPS)
    # 重新绘制背景指定区域,等同于擦除图片效果
    if rect:
        surface.blit(bgSurface, rect,rect)
    # 图片移动指定步长
    newRect = rect.move(step, 0)
    # 弹出事件,这个一定要写,要不事件栈满了之后就会卡死
    for event in pygame.event.get():
        # 点击关闭
        if event.type == pygame.QUIT:
            exitFlag = True
    # 绘制图片到屏幕画布指定区域
    surface.blit(scaleImg,newRect)
    # 控制在窗口内来回移动
    if newRect.x > 800 - newRect.w:
        step = -10
    elif newRect.x < 0:
        step = 10

    # 更新绘制到屏幕上
    pygame.display.update([rect,newRect])
    rect = newRect


if __name__ == '__main__':
    pass

3、代码分析

1)pygame窗口保持一直显示的前提是: python进程持续地在运行,要实现这个目的,需要有一个循环体在不停地运行,所以需要一个全局变量标识是否退出循环,结束进程,比如:上面声明exitFlag这个变量来记录当前是否退出循环,当exitFlag=True就退出游戏

2)游戏界面变化的频率,对应的是画面刷新的帧率,即画面每秒刷新多少次,这个刷新帧率设置太快,假如设备的GPU刷新跟不上也是没效果的,所以一般设置1秒刷新30次就可以达到看视频那样流畅的效果了,比如:上面代码设置FPS = 10是为了不让刷新太快,否则动画移动太快,看不清图片,其中,pygame时钟是控制游戏画面刷新的帧率,通过clock = pygame.time.Clock()获取到时钟对象,然后在循环体中设置指定的帧率即可: clock.tick(FPS)

3)pygame初始化是调用pygame.init(),这句代码需要在所有设置pygame属性之前调用,先初始化再做其他操作

4)os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 25) , 指定pygame窗口的左上角显示在坐标(0,25)上,即距离屏幕左边0像素,距离屏幕上边25像素;不设置的话,窗口默认显示屏幕正中央

5)surface = pygame.display.set_mode((800, 500)),设置游戏窗口大小为:宽800像素,高500像素;

  • 当然,你还可以设置surface = pygame.display.set_mode((0, 0)),这样就是全屏显示,
    不过单纯这样设置全屏的话,你会发现窗口的大小是固定的,没法缩小
  • 那么要达到默认显示全屏,但是又可以随意调节的目的,可以这样设置:surface = pygame.display.set_mode((0, 0),pygame.RESIZABLE)
  • 上面两种方式显示的全屏都有一个问题,那就是还看到游戏窗口的标题栏与桌面的任务栏,不算是严格意义的全屏,要想游戏画面铺满整个屏幕,需要这样设置:surface = pygame.display.set_mode((0, 0),pygame.FULLSCREEN)

6)pygame.display.set_caption("pygame教程"),设置游戏窗口标题栏显示的标题名称或者说软件名也可以
在这里插入图片描述在这里插入图片描述

7) pygame.image.load('E:\AS-workspace\pygameTest\drawable\icon.png').convert_alpha(),复制本地图片的像素数据到一个Surface对象中储存,为后续绘制到屏幕做准备

  • 因为是png图片,需要额外处理alpha通道,所以需要使用 convert_alpha()转换成与我们的屏幕显示器相同的像素格式,这样能获得最快渲染速度;
  • 如果是jpg格式图片,没有alpha通道,也就是没有透明背景的图片,可以直接用convert()转换为pygame最快的渲染格式即可
  • 注意: 最好每张图片都调用一下covert方法,这样可以提高渲染速度,否则,pygame每次绘制时候也会自动根据屏幕显示器的像素格式进行转换,会降低渲染速度,可能会出现卡顿现象

8)pygame.display.set_icon(icon),设置指定图片的surface对象作为该程序的图标

9) scaleImg = pygame.transform.scale(icon, (400, 400)) ,缩小/放大图片到指定宽高,并返回缩小/放大之后的图片surface对象

10)rect = scaleImg.get_rect(),获取图片的矩形区域,即(left, top, width, height),也就是返回图片左上角的坐标,宽,高,不过默认返回的左上角坐标都是(0,0)

11)surface.blit(bgSurface,(0,0)),将图片绘制到指定的surface对象中,左上角的坐标为(0,0),注意:这里仅仅只是将图片绘制到surface上而已,并没有渲染到屏幕上,也就是说只做了这一步,屏幕上是看不到新绘制的内容的,还需要调用 pygame.display.update() 或者pygame.display.flip()才会把新绘制的内容更新渲染到屏幕上

12) rect = rect.move(step, 0),将rect沿着x轴移动step像素,沿着y轴移动0像素,即step为整数时,向右移动step像素,step为负数时,向左移动step像素

13) PyGames通过事件队列来处理其所有事件消息传递,但是事件队列是有上限的,标准的SDL 1.2声明的队列长度是128,如果事件队列的事件超出了限制,那么后续的事件都会被丢弃,你的程序就会显示无法响应卡死,所以一定要在每一帧中都用以下其中一个方法来处理事件: pygame.event.get(), pygame.event.pump(), pygame.event.wait(), pygame.event.peek() 或者 pygame.event.clear()

 for event in pygame.event.get():
        # 点击关闭
        if event.type == pygame.QUIT:
            exitFlag = True

14)由于pygame是一帧一帧绘制的,那么图片在移动时候,假如没有对上一帧绘制的图片做擦除,就会出现一堆图片重叠的现象,这就是所谓的“脏图片“,所以上面代码可以看到在每一帧刷新中,都对背景的指定区域rect做了擦除动作:surface.blit(bgSurface, rect,rect),即重新绘制一遍背景图的指定区域,以达到覆盖脏图片的效果,当然,你也可以把整个背景图重新绘制一遍的,但是这样太耗费性能

15)同时,我们更新绘制内容到屏幕显示器时,也不要一股脑地调用 pygame.display.update()更新整个屏幕,因为据测算,在性能比较一般的机器,每次调用update更新整个屏幕的耗时接近35ms, 那么1秒内最大只能刷新:1000/35 = 28帧,但是这里还没有计算游戏逻辑、绘制、获取输入输出等操作所耗费时间,仅仅是update,就最多只能一秒刷新28帧,那么这样算下来,就很容易出现卡顿现象了,那么有什么解决办法吗?看看上面代码,我们是对图片有改变的区域进行刷新即可,这样可以获得最高的刷新速率:pygame.display.update([rect,newRect]),换句话说,我们可以用list集合记录每一帧图片变化的区域,然后只对这些区域进行刷新即可

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐