《pygame中Sprite类实现多帧动画》注-通过多张序列帧显示动画2-2

3 添加update()方法

《《pygame中Sprite类实现多帧动画》注-显示静态图片2-1》中提到,MySprite类的update()方法用于更新精灵的图片或位置信息。可以在该方法中根据时间更新当前帧图片,并且更新精灵的位置,代码如图7所示。

图7 update()方法的代码

其中,update()方法的current_time参数表示当前时间,speed表示更换帧的时间阈值,默认值是30毫秒。

3.1 更新帧图片

图7中,第33-38行代码实现了帧图片的更新。根据图6的原理图可知,第33行将类属性current_time设置为当前时间;第34行if语句判断从当前帧开始显示的时间last_time开始计时,是否已经显示了阈值时间speed,如果是,则说明该更换下一个帧图片了,因此第35行对当前帧图片的序号current_frame加1;第36-37行代码判断是否已经显示到最后一张帧图片了(序列号为MAX_FRAME),如果是最后一张,则将当前帧图片的序列号设置为0,表示从第一个帧开始循环显示。第38行代码更新帧图片。第42行代码将当前帧开始显示的时间last_time设置为current_time,表示图片显示重新开始计时。

3.2 更新精灵位置

图7中,第39-41行代码用于更新精灵的位置,其中self.rect为精灵的位置,将其left属性减去ZOMBIE_SPEED,表示精灵向左移动ZOMBIE_SPEED,ZOMBIE_SPEED在类定义代码之前定义为一个整型值;第40-41行代码表示当精灵类向左移动出窗口之外时,将精灵在窗口最后侧显示。

4 获取游戏时间

从以上分析可知,整个程序是通过游戏时间来进行驱动的。因此,获取游戏时间的代码是非常重要的,如图8所示。

图8 获取游戏时间的代码

该行代码在while循环内调用。其中,pygame.time,get_ticks()方法获取从调用pygame.init()开始的游戏时间,将该时间保存在变量tick中,如果在程序中打印tick,可以看到如图9所示效果。

图9 tick的值

从图9中可以看出,每隔16或者17毫秒获取一次当前时间。原因在于在设置每秒更新次数的代码clock.tick(FPS)中FPS的值是60,1000毫秒除以60的值就是16-17中间。

5 更新精灵帧图片及位置

《《pygame中Sprite类实现多帧动画》注-显示静态图片2-1》中提到,通过精灵组的update()方法,调用精灵组内所有精灵的update()方法。而此时精灵组的update()方法要与MySprite类的update()方法格式相同,如图10所示。

图10 更新精灵帧图片及位置的代码

其中,tick是“4 获取游戏时间”中获取的游戏时间。

注意1 因为MySprite类的update()方法中,更换帧的时间阈值speed是默认值30毫秒,如果向加快或者降低精灵更换帧图片的速度,只需在65行代码中,指定speed的合适值即可。

6 完整代码

完整代码如下所示。

import pygame
from pygame.locals import *


SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
BACKGROUND = 'green'
FPS = 60
FILEPATH = './BucketheadZombie/BucketheadZombie_0.png'
MAX_FRAME = 15
ZOMBIE_SPEED = 5
imagepath_list = ['./BucketheadZombie/BucketheadZombie_{}.png'.format(i) for i in range(15)]
print(imagepath_list)
#或者pygame.sprite.Sprite().__init__(self),推荐使用super().__init__()
class MySprite(pygame.sprite.Sprite):
    def __init__(self, filepath):
        super().__init__()
        self.image = pygame.image.load(filepath).convert_alpha()
        self.rect = self.image.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
        self.current_time = 0
        self.last_time = 0
        self.current_frame = 0
    def update(self, current_time, speed=30):
        self.current_time = current_time
        if self.current_time>=self.last_time + speed:
            self.current_frame += 1 
            if self.current_frame>=MAX_FRAME:
                self.current_frame = 0
            self.image = pygame.image.load(imagepath_list[self.current_frame]).convert_alpha()
            self.rect.left -= ZOMBIE_SPEED
            if self.rect.right <= 0:
                self.rect.left = SCREEN_WIDTH
            self.last_time = self.current_time
        
        
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

mysprite1 = MySprite(FILEPATH)
sprite_group = pygame.sprite.Group()
sprite_group.add(mysprite1)

running = True
clock = pygame.time.Clock()

#

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
    
    screen.fill(BACKGROUND)
    tick = pygame.time.get_ticks()
    print(tick)
    sprite_group.update(tick)
    sprite_group.draw(screen)
    pygame.display.update()
    clock.tick(FPS)
    
pygame.quit()

### 如何在 Pygame 中创建和控制逐动画 #### 创建逐动画的基础概念 逐动画通过连续显示一系列静态图像来创建动画效果[^4]。为了实现这一目标,在 Pygame 中通常会利用 `Sprite` 及其子化对象,这些对象能够存储个表示不同状态的图像,并可以在特定时刻更新自身的图像属性。 #### 自定义精灵 (Sprite) 用于动画 自定义一个继承自 `pygame.sprite.Sprite` 的,该内部维护着一组代表各个动作阶段的画面序列——即由若干个尺寸一致却描绘了角色不同姿态的位图所构成的一个列表。每当调用此精灵实例的方法去刷新其外观时,便会依据程序计数器或时间戳选取下一个要展示的画面并赋值给 `self.image` 成员变量,从而达到视觉上连贯的动作变化效果[^3]。 ```python import pygame from itertools import cycle class AnimatedSprite(pygame.sprite.Sprite): def __init__(self, position, images): super().__init__() self.images = images # 存储所有的列表 self.index = 0 # 当前索引 self.animation_cycle = cycle(self.images) self.image = next(self.animation_cycle) self.rect = self.image.get_rect(center=position) self.animation_time = 0.1 # 切换至下一所需秒数 self.current_time = 0 # 记录经过了少时间 def update(self, dt): # 更新函数接收 delta time 参数 if self.index >= len(self.images)-1: self.index = -1 # 循环播放 self.current_time += dt if self.current_time >= self.animation_time: self.current_time = 0 self.index += 1 self.image = next(self.animation_cycle) def main(): screen_width = 800 screen_height = 600 size = (screen_width, screen_height) pygame.init() screen = pygame.display.set_mode(size) clock = pygame.time.Clock() frames = [] # 加载每一图片文件路径 for i in range(12): # 假设有十二张图片编号从0到11 frame_image_path = f'./images/frame_{i}.png' image_surface = pygame.image.load(frame_image_path).convert_alpha() frames.append(image_surface) player_sprite = AnimatedSprite((400, 300), frames) all_sprites_group = pygame.sprite.Group(player_sprite) running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False dt = clock.tick(60)/1000 # 获取两次tick之间的时间差作为dt参数传递给update方法 all_sprites_group.update(dt) screen.fill((255, 255, 255)) all_sprites_group.draw(screen) pygame.display.flip() if __name__ == '__main__': main() ``` 这段代码展示了如何加载多张图片并将它们分配给一个名为 `AnimatedSprite` 的新中的 `self.images` 属性;之后每次调用 `update()` 函数都会根据设定好的间隔自动更换下一张待渲染的图片,进而模拟出流畅的人物移动或其他形式的变化过程[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值