还记得我们在之前的程序中如何让兔子动起来的吗,没错,使用event模块检测键盘事件,改变绘图的坐标,画面刷新后兔子就移动了。接下来我们细说如何精确控制时间和运动。
主要内容: pygame的时间模块、动画的速度、向量的引入
一、pygame的时间模块
time模块是pygame用来监测时间流动的模块。由于不同的电脑CPU处理指令的速度不同,性能有差异,对于同一个pygame游戏的动画就会出现动画速度不一致的现象。因此,有必要使用time模块来控制速度。
time模块: 常用函数
pygame.time模块有很多测量时间的函数,它们的返回值都是一个常数,代表流逝的时间。pygame的时间是以毫秒(millisecond)来计算的,pygame中含有一个常量TIMER_RESOLUTION标记了一毫秒的长度。
1、pygame.time.get_ticks
语法:get_ticks() -> milliseconds
说明:返回值代表了自pygame.init()被调用以来经过的时间。在pygame.init()被调用之前,返回值始终为0
2、pygame.time.wait
语法:wait(milliseconds) -> time
说明:程序暂停给定的毫秒数。该函数占用很少的CPU使劲按,精度略低于delay()函数。
3、pygame.time.delay
语法:delay(milliseconds) -> time
说明:程序暂停给定的毫秒数。它使用CPU来精确控制时间,精确度高。
4、pygame.time.Clock
语法:Clock) -> Clock
说明:该函数返回一个跟踪时间的对象,该对象有很多计算时间的函数。
帧率:FPS(frame per second),代表了游戏画面的刷新速度,一般60帧的刷新频率就可以让画面看起来光滑逼真,对更高的帧率人眼基本上察觉不到变化了。
Clock对象 :常用函数
1、tick
语法:tick(framerate=0) -> milliseconds
说明:可以说,这个函数是非常好用了。在每一次画面刷新时,这个函数都会被调用,它返回距离上一次被调用经过的时间。如果传入可选的参数framerate,如下面的例子,此时该函数会产生延迟使游戏刷新频率低于40。
clock = pygame.time.Clock()
while True:
time_passed = clock.tick(40)
...
2、tick_busy_loop
语法:tick_busy_loop(framerate=0) -> milliseconds
说明:使用同tick()一样,只不过这个函数牺牲更多CPU时间来换取精确度
3、get_fps
语法:get_fps() -> float
说明:利用最后10次调用的Clock.tick()的返回值的平均值计算帧率并返回。
二、动画的速度
前面提到了动画的速度,如果不使用时间模块来控制,系统的程序在不同的机器上运行结果可能不一样。还记得我们在讨论键盘事件时做的动画吗,兔子?跑的特别快。这里,我们试试用time模块来控制速度:
我们知道,位移(displacement) = 速度(velocity) * 时间(time)
,而对于pygame窗口来说,surface对象的移动是在不同坐标的绘制,我们只需要控制在相同时间里,坐标(x, y)的增量相同就可以啦。先看几行代码:
import pygame, sys
from pygame.locals import *
pygame.init()
pygame.display.set_caption("constant speed")
screen = pygame.display.set_mode((640,480), 0, 32)
rabbit = pygame.image.load("rabbit.png")
(x, y) = (0, 0)
speed = 100
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 计算时间并转化为seconds
time_passed = clock.tick(2)
time_passed_seconds = time_passed / 1000
x += time_passed_seconds * speed
y += time_passed_seconds * speed
screen.fill((200,200,255))
screen.blit(rabbit, (x, y))
pygame.display.update()
上面的代码使用了Clock对象,坐标(x, y)的值由speed和时间控制,兔兔?每秒钟只移动100(speed = 100)个像素,下面是关键代码。
刷新频率只是影响了运动的平滑程度,不影响移动的平均速度,比如我们把frame rate设为1,则隔1秒小兔子移动100px,而设置为2时,可以发现每0.5秒小兔子移动50px,结果一样,可以实践验证。
clock = pygame.time.Clock()
while True:
time_passed = clock.tick(2)
time_passed_seconds = time_passed / 1000
x += time_passed_seconds * speed
y += time_passed_seconds * speed
三、向量的引入
数学对向量的定义是带方向的量,在pygame里面,向量只不过是一个元组,我们可以自己编写一个向量类,包含 获取模magnitude()、标准化normalize()以及各种重载运算符等方法。不过也利用现成的向量库可以使用,gameobjects库包含了Vector2、Vector3、Vector4等向量模块,下载一个gameobjects库,可以方便的在pygame中使用向量。
Vector2 —— 使用
step1:导入类
from gameobjects.vector2 import Vector2
step2:创建类对象
vector = Vector(3, 4)
step3:调用类方法
x = vector.get_x()
mag = vector.get_magnitude()
vector_normalized = vector.get_normalized()
Vector2 —— 主要函数
函数 | 功能 |
---|---|
Vector(x, y) | 构造函数,生成vector对象 |
get_x() | 返回向量的x分量 |
set_x() | 返回向量的x分量 |
get_length() | 返回向量的长度 |
normalise() | 将原向量标准化 |
get_normalise() | 返回单位化的向量,不修改原向量 |
运算符重载 | 加、减、乘、(不)等于判断 |
from_points(p1, p2) | 返回从点p1到点p2的向量 |
Vector2 —— 应用
下面,我们利用向量来实现兔子追胡萝卜的动画,代码如下:
import pygame, sys
from pygame.locals import *
from gameobjects.vector2 import Vector2
pygame.init()
pygame.display.set_caption("rabbit eat carrot")
screen = pygame.display.set_mode((640, 480), 0, 32)
rabbit = pygame.image.load("rabbit.png")
carrot = pygame.image.load("carrot.png")
speed = 100
direction = Vector2()
position = Vector2(300, 220)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
width = carrot.get_width()
height = carrot.get_height()
destination = (Vector2(*pygame.mouse.get_pos()) -
Vector2(width/2, height/2))
vector_to_mouse = Vector2.from_points(position, destination).get_normalised()
time_passed = clock.tick()
time_passed_seconds = time_passed / 1000
position.x += time_passed_seconds*speed*vector_to_mouse.x
position.y += time_passed_seconds*speed*vector_to_mouse.y
screen.fill((255, 255, 255))
screen.blit(carrot, destination)
screen.blit(rabbit, position)
pygame.display.update()
我们使用了clock和speed常量来控制兔子的移动速度,使用从兔子当前位置position到鼠标destination方向上的单位向量vector_to_mouse控制兔子的运动方向。兔兔吃胡萝卜的GIF如下 (●’◡’●)
第四篇pygame学习笔记完结 cheers! ?
附上:代码压缩包
提取码:j8th
参考博客:用Python和Pygame写游戏-从入门到精通
图标引用:Iconfont