本文目标
前面几章我们学了很多Pygame基础知识了,从这篇博客开始我们将会学习pygame中高级部分,更多和精灵模块,冲突检测相关的知识。这一节我们还是通过一个简单的实例来做讲解。
Sprite模块介绍
一、Sprite模块、sprite对象
在pygame.sprite模块里面包含了一个名为Sprite类,他是pygame本身自带的一个精灵。但是这个类的功能比较少,因此我们新建一个类对其继承,在sprite类的基础上丰富,以方便我们的使用。
首先来了解一下如何使用sprite类来加载动画吧。
之外,还需要告诉精灵类,精灵序列图里面有多少列。load函数可以加载一个精灵序列图。
1 2 3 4 5 6 |
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 |
3.更新帧
一个循环动画通常是这样工作的:从第一帧不断的加载直到最后一帧,然后在折返回第一帧,并不断重复这个操作。
1 2 3 4 |
self.frame += 1 if self.frame > self.last_frame: self.frame = self.first_frame self.last_time = current_time |
但是如果只是这样做的话,程序会一股脑地将动画播放完了,我们想让它根据时间间隔一张一张的播放,因此加入定时的代码。
pygame中的time模块有一个get_ticks()方法可以满足定时的需要。
1 |
ticks = pygame.time.get_ticks() |
然后将ticks变量传递给sprite的update函数,这样就可以轻松让动画按照帧速率来播放了。哦,帧速率还没有设置,咱们现在设置一下帧速率。
启动一个定时器,然后调用tick(num)函数就可以让游戏以num帧来运行了。
1 2 |
framerate = pygame.time.Clock() framerate.tick(60) |
4、绘制帧
sprite.draw()方法是用来绘制帧的,但是这个函数是由精灵来自动调用的,我们没有办法重写它,因此需要在update函数里面做一些工作。
首先需要计算单个帧左上角的x,y位置值(x表示列编号,y表示行编号):
1 2 3 |
frame_x = (self.frame % self.columns) * self.frame_width #用帧数目除以行数,然后在乘上帧的高度 frame_y = (self.frame // self.columns) * self.frame_height |
然后将计算好的x,y值传递给位置rect属性。
1 2 3 4 |
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) |
5、精灵组
当程序中有大量的实体的时候,操作这些实体将会是一件相当麻烦的事,那么有没有什么容器可以将这些精灵放在一起统一管理呢?答案就是精灵组。
pygame使用精灵组来管理精灵的绘制和更新,精灵组是一个简单的容器。
使用pygame.sprite.Group()函数可以创建一个精灵组:
1 2 |
group = pygame.sprite.Group() group.add(sprite_one) |
精灵组也有update和draw函数:
1 2 |
group.update() group.draw() |
二、自定义的精灵类
好了,通过前面的学习,我们已经了解了一些精灵的知识了,现在我们将前面说到的方法封装成一个自定义的类,以方便我们的调用,这个类继承自pygame.sprite.Sprite:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
class MySprite(pygame.sprite.Sprite): def __init__(self, target): pygame.sprite.Sprite.__init__(self) #基类的init方法 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 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 def update(self, current_time, rate=60): #更新动画帧 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 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 |
好了现在我们写一个小程序来测试一下这个类的性能怎么样。
这里我用ps制作了一个简单的精灵序列图,咱们就用这个萌萌的嗷大喵好了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
import pygame from pygame.locals import * class MySprite(pygame.sprite.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 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 def update(self, current_time, rate=60): 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 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 pygame.init() screen = pygame.display.set_mode((800,600),0,32) pygame.display.set_caption("精灵类测试") font = pygame.font.Font(None, 18) framerate = pygame.time.Clock() cat = MySprite(screen) cat.load("sprite.png", 100, 100, 4) group = pygame.sprite.Group() group.add(cat) while True: framerate.tick(30) ticks = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() key = pygame.key.get_pressed() if key[pygame.K_ESCAPE]: exit() screen.fill((0,0,100)) group.update(ticks) group.draw(screen) pygame.display.update() |
效果图:萌萌的嗷大喵跃然于屏幕上。看起来功能还不错的说。
大家也可以制作一些自己喜欢的精灵序列图,然后加载并查看他们的效果。
关于精灵与精灵之间的冲突检测,精灵与组之间的碰撞检测,我们将会放在下个博客一起学习。
未经允许不得转载:Python在线学习 » Python游戏开发教程六:Pygame中的Sprite(精灵)模块和加载动画