Python实现GIF动图加载和降帧的方法详解

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Python实现GIF动图加载和降帧的方法详解

神奇代码在哪里_   2023-03-21 我要评论

最近在使用pygame开发游戏,练习python编程。但遇到了一个问题,就是如何载入已有的GIF动图增强游戏的效果,在csdn搜索了一下,发现相关的文章比较少,缺少实例。于是自己研究了相关内容,找到了解决方案。本篇文章用游戏编程实例介绍pygame如何载入GIF动图。

一、准备一份透明背景的GIF动画素材

首先在网络上找一张背景透明的GIF动图,注意需要背景透明的,不然在游戏中就会显示一个矩形图片,会挡住游戏的背景。以下就是百度图片搜索找到的背景透明的GIF动图。

百度图片搜索的素材

二、使用pillow库对GIF动图进行解帧

使用pillow库的Image、ImageSequence包对图片进行解帧后发现,这张下载的GIF图片包含了10帧图片,图片以png格式保存在./images/bird/文件夹下面,文件名以gif1、gif2......等为后缀名。

GIF解帧后的文件情况

参考代码: 

from PIL import Image, ImageSequence
 
class GameGifSprite(pygame.sprite.Sprite):
    """
    小鸟游戏精灵
    """
    def __init__(self, image_name, speed=1):
        # 调用父类的初始化方法
        super().__init__()
        # 使用pillow的image打开GIF动图
        pillow_image = Image.open(image_name)
        index = 1
        # 使用pillow的ImageSequence获取GIF动图所有帧对应的迭代器
        for frame in ImageSequence.all_frames(pillow_image):
            # 以png格式保存在./images/bird/文件夹下面,文件名以gif1、gif2......等为后缀名
            frame.save(f"./images/bird/gif{index}.png", quality=100)
            index = index + 1

三、使用pygame.image.load()读取所有解出来的帧并存入列表

然后使用pygame.image.load()按文件名字顺序读取这10张图片,并把返回的10个图像对象添加到列表中。

1)all_frame为GIF动图所包含的所有帧数,这里index循环结束后为11,由于数组从0开始计算,所以为11-2=9。

2)now_frame为当前游戏的帧,一开始设置为0。

3)gif_images为存储GIF动图的帧列表。

4)循环读取所有帧,添加到gif_images[]中。

5)游戏开始时设置显示第一帧图片。

参考代码:

# 定义对象的属性
# 1.all_frame为GIF动图所包含的所有帧数,这里index循环结束后为11,由于数组从0开始计算,所以为11-2=9
self.all_frame = index - 2
# 2.now_frame为当前游戏的帧,一开始设置为0
self.now_frame = 0
# 3.gif_images为存储GIF动图的帧列表
self.gif_images = []
# 4.循环读取所有帧,添加到gif_images[]中
for i in range(1, index):
    self.gif_images.append(pygame.image.load(f"./images/bird/gif{i}.png"))
# 5.游戏开始时设置显示第一帧图片
self.image = self.gif_images[self.now_frame]

四、在精灵类的update()方法中循环播放列表中的帧

pygame在每次画面刷新时会调用每个精灵类的update()方法,所以我们只要在该方法下实现循环播放这10帧图片就可以实现含有GIF图片精灵的播放。以下是游戏运行效果图:

游戏运行效果图

1)当播放到gif最后一帧时,重置为gif第一帧

2)画面每次刷新更新gif的下一帧

参考代码:

    def update(self):
        # 在屏幕的水平方向上移动
        self.rect.x -= self.speed
        # 当播放到gif最后一帧时,重置为gif第一帧
        if self.now_frame < self.all_frame:
            # 画面每次刷新更新gif的下一帧
            self.now_frame = self.now_frame + 1
        else:
            self.now_frame = 1

五、避免精灵帧率过快对精灵进行降帧

实现GIF在游戏中显示后又产生了一个新问题,由于游戏设置是60FPS帧率播放的,那么显示这张GIF图片时就过快了,我们需要对精灵对象降低帧率,这里使用了我自己写的公式。

1)self.now_frame = self.now_frame + 1改为self.now_frame = self.now_frame + self.FPS

2)update()方法中增加self.image = self.gif_images[math.floor(self.now_frame)],使用math.floor向下取整达到降帧的效果

PS:当sefl.FPS设置为0.25时则相当于把帧率降低了4倍,现在看上去就正常多了。

降帧后的效果图

参考代码:

    def update(self):
        # 在屏幕的水平方向上移动
        self.rect.x -= self.speed
        # 当播放到gif最后一帧时,重置为gif第一帧
        if self.now_frame < self.all_frame:
            # 画面每次刷新更新gif的一下一帧
            self.now_frame = self.now_frame + self.FPS
        else:
            self.now_frame = 1
        # 设置pygame当前显示的gif帧
        # 使用math.floor向下取整达到降帧的效果
        self.image = self.gif_images[math.floor(self.now_frame)]

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们