【简介】
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集合记录每一帧图片变化的区域,然后只对这些区域进行刷新即可