之前就有学过一部分的pygame,前段时间还想着能用这东西来帮别人做一个毕业设计来着,事情可以不了了之,学习永不停止。
因为毕设内容是一个跑酷游戏,所以找了个github代码直接拿来看,并且很幸运找到了作者的日志,所以通篇引用这位老哥的内容(https://www.cnblogs.com/msxh/tag/python/),算是一个笔记。
sprite类
游戏开发中很常见的类,国内译做精灵,有一些游戏引擎也会以面向精灵(各种继承来的类)编程来体现这一点。
最初我以为是这个类为我们做了把图片分割成一个个动画帧这些操作,我们只需要传入图片,设定一个帧大小就可以了。但是代码告诉我,切割帧,然后选择选择要画出来的动画帧,这些操作都是我们自己来做的。。(向来不喜欢进行图片操作,真的很麻烦啊。。)
def __init__(self, target):
pygame.sprite.Sprite.__init__(self)
self.target_surface = target
self.image = None
self.master_image = None
self.rect = None
self.topleft = 0,0
self.frame = 0
self.old_frame = -1
self.frame_width = 1
self.frame_height = 1
self.first_frame = 0
self.last_frame = 0
self.columns = 1
self.last_time = 0
-初始化设定
成员 | 意义 |
---|---|
target_surface | python.display.setmode()返回的surface对象 |
image | 当前显示的动画帧帧 |
master_image | 读取的包含全部动画帧序列图 |
rect | 四个元素的元组,分别表示动画帧绘制在target_surface的位置x,y,以及一个动画帧的宽,高 |
frame | 当前帧的序号 |
old_frame | 上一帧的序号 |
frame_width | 一个动画帧宽度 |
frame_height | 一个动画帧的高度 |
first_frame | 首个动画帧编号,为0 |
last_frame | 最后一个动画帧编号,为总数-1 |
columns | 序列图有多少列动画帧 |
last_time | 后续会用到的更新动画帧时间 |
def load(self, filename, width, height, columns):
self.master_image = pygame.image.load(filename).convert_alpha()
self.frame_width = width
self.frame_height = height
self.rect = 0,0,width,height
self.columns = columns
rect = self.master_image.get_rect()
self.last_frame = (rect.width // width) * (rect.height // height) - 1
从加载图片里面就可以看出来初始化中一些变量的作用都是啥。感觉有点意义的地方也就是last_frame,这个数量其实是我们计算出来的。。。通过计算传入序列图和一个帧的大小计算。。(感觉合理,但总觉得应该会更加好用一些来着。。。)
def update(self, current_time, rate=50):
# 。。。帧数解释内容。
if self.frame != self.old_frame:
frame_x = (self.frame % self.columns) * self.frame_width
frame_y = (self.frame // self.columns) * self.frame_height
rect = ( frame_x, frame_y, self.frame_width, self.frame_height )
self.image = self.master_image.subsurface(rect)
self.old_frame = self.frame
这一段内容就是切割序列图获得准备现实的动画帧,给image变量,然后的一步是把交接当前帧序号。
- 但其实我还是不知道为啥每次update都会使用image来更新动画帧,我也试过了只要在update里面把那个image读取另外的图片就会显示读取的其他图片。每一个精灵的绘制帧应该是draw()函数,但是不能重写这个函数,所以只能在update里面进行部分处理。
- 说到底这个动画帧基本还是全部靠程序员,每一帧显示啥,程序设定为多少帧,把精灵序列图切割为动画帧,这些操作都是自己写入了类中。自由度很高。。但是真的好不智能啊。。。
帧数控制
每个sprite都应该有一个update函数用来进行自我更新,当是看的时候就在疑惑pygame提供了什么机制来控制帧率,在文章中也只是提了要这样那样进行配置,在自己改了一些东西试一试之后有了一些理解。
def update(self, current_time, rate=50):
if current_time > self.last_time + rate:
self.frame += 1
if self.frame > self.last_frame:
self.frame = self.first_frame
self.last_time = current_time
# 。。。
- current_time是作为输入参数,在循环中使用group的update来调用我们的sprite中的update,而这个参数的内容就是一个数字。从pygame.init()被调用开始进行计时,过了多少毫秒。而这个数字又是通过调用pygame.time.get_ticks()得到。
- 而在这个update函数中就一个默认50的参数就是决定刷新频率的一点。通过看函数内容就知道每次进行update都要至少经过50毫秒。当设置成1000的时候就可以观察到确实是在每一秒更新一次动画帧。
此外还有一个更加显示的控制帧率的方法。
framerate = pygame.time.Clock()
# 。。。
while True:
framerate.tick(4)
- pygame.time.Clock()的作用描述为create an object to help track time。
- 在循环体中有一句framerate.tick(4)。这个函数在文档中的描述为每一帧都应该被调用一次,返回值为距离上一帧经过了多少毫秒。但如果有参数传入,则作用为限定程序运行帧率不会超过给定数值。比如我在其中填入了数值4,画面也确实是每一秒更新4个动画帧。
- 同时,他也会限制这个循环在1秒内只会运行4次。