关于 pixijs-scene-gif
面向 PixiJS 开发者的 GIF 动画技能,介绍如何加载并用 GifSprite 显示动画,也涵盖播放控制、回调和共享帧数据管理。
主要功能
- 01使用 Assets.load 加载 GIF 资源
- 02控制循环与播放速度
- 03连接 Ticker 或手动驱动更新
- 04处理帧变化和完成回调
- 05共享源数据并克隆精灵
适用场景
- 01在 PixiJS 场景中添加 GIF 动画
- 02通过专用 Ticker 同步播放
- 03让多个精灵复用 GIF 源数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pixijs/ pixijs-skills --skill pixijs-scene-gif安装后在 Claude Code 中输入/pixijs-scene-gif确认已加载。
详细介绍
GifSprite 会将动画 GIF 作为显示对象播放。Assets.load('animation.gif') 返回的是 GifSource(而非 Texture),你需要将它传入 GifSprite。需要通过副作用导入 import 'pixi.js/gif' 来注册加载器扩展。
假设你熟悉 pixijs-scene-core-concepts。GifSprite 扩展自 Sprite,因此它是叶节点:不要在其中嵌套子对象。将多个 GifSprite 实例包装在 Container 中进行分组。
快速开始
import "pixi.js/gif";
import { GifSprite } from "pixi.js/gif";
const source = await Assets.load("animation.gif");
const gif = new GifSprite({
source,
autoPlay: true,
loop: true,
animationSpeed: 1,
});
gif.anchor.set(0.5);
gif.x = app.screen.width / 2;
gif.y = app.screen.height / 2;
app.stage.addChild(gif);
说明
GIF 的每一帧都会解码为单独的画布纹理。对于包含许多帧且对性能要求较高的动画,建议使用带
AnimatedSprite的精灵表——它使用单张图集纹理,在 GPU 上的批处理效果更好。
相关技能: pixijs-scene-core-concepts(场景图基础知识)、pixijs-scene-sprite(用于基于精灵表的动画的 AnimatedSprite)、pixijs-assets(Assets.load、缓存、卸载)、pixijs-ticker(帧计时)、pixijs-performance(纹理内存)。
构造函数选项
GifSpriteOptions 扩展自 Omit<SpriteOptions, 'texture'>;texture 由内部管理(从 source.textures[0] 设置,并在每帧切换)。所有其他 Sprite 选项(anchor、scale、tint、roundPixels 等)均有效,所有 Container 选项(position、scale、tint、label、filters、zIndex 等)在此处也均有效——请参阅 skills/pixijs-scene-core-concepts/references/constructor-options.md。
GifSpriteOptions 新增的叶节点专属选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
source | GifSource | — | 必填。由 Assets.load('file.gif') 返回的已解析 GIF 数据。可供多个 GifSprite 实例共享。 |
autoPlay | boolean | true | 构造时立即开始播放。若为 false,必须调用 gif.play() 才能开始播放。 |
loop | boolean | true | 到达最后一帧时重复播放动画。若为 false,精灵会停在最后一帧并触发 onComplete。 |
animationSpeed | number | 1 | GIF 原生帧计时的倍数。2 表示以双倍速度播放;0.5 表示以一半速度播放。 |
autoUpdate | boolean | true | 将播放连接到 Ticker.shared。设为 false 可通过 gif.update(ticker) 自行驱动更新。 |
fps | number | 30 | 为未指定逐帧延迟的 GIF 提供的备用帧率。 |
onComplete | () => void | null | null | 非循环动画到达最后一帧时调用。 |
onLoop | () => void | null | null | 循环动画每次回到开头时调用。 |
onFrameChange | (frame: number) => void | null | null | 显示的帧索引每次变化时调用。 |
scaleMode | SCALE_MODE | 'linear' | 自 8.13.0 起已弃用——请改为通过 Assets.load(..., { data: { scaleMode } }) 传入 scaleMode。 |
构造函数也接受单独的 GifSource 作为唯一参数(new GifSprite(source)),这相当于使用上述默认值调用 new GifSprite({ source })。
核心模式
设置和副作用导入
import "pixi.js/gif";
import { Assets } from "pixi.js";
import { GifSprite } from "pixi.js/gif";
const source = await Assets.load("animation.gif");
const gif = new GifSprite({ source });
pixi.js/gif 会调用 extensions.add(GifAsset),向资源加载器注册 .gif。如果不导入它,Assets.load 就无法识别 GIF 文件。GifSprite 和 GifSource 从 pixi.js/gif 导出,而不是从 pixi.js 导出。
从 pixi.js/gif 导入命名导出也会触发副作用,因此只有在不从该路径导入任何内容时,才需要单独使用 import 'pixi.js/gif'。
播放控制
const gif = new GifSprite({ source });
gif.play();
gif.stop();
gif.currentFrame = 5;
gif.animationSpeed = 2;
gif.animationSpeed = 0.5;
gif.playing; // read-only
gif.progress; // 0-1 playback position
gif.totalFrames; // number of frames
gif.duration; // total duration in ms
autoPlay: true(默认值)会立即开始播放;loop: true(默认值)会重复播放。animationSpeed 是 GIF 原生帧时长的倍率。currentFrame 从 0 开始计数。
加载选项
const source = await Assets.load({
src: "animation.gif",
data: {
fps: 12,
scaleMode: "nearest",
resolution: 2,
},
});
const fromDataUri = await Assets.load("data:image/gif;base64,R0lGODlh...");
data 中的选项会传递给 GifSource.from。对于未指定时序的 GIF,fps 用于设置备用帧延迟。scaleMode 和 resolution 用于控制为每一帧创建的画布纹理。加载器既能匹配 .gif 文件扩展名,也能匹配 data:image/gif URI。
回调
const gif = new GifSprite({
source,
loop: false,
onComplete: () => console.log("animation finished"),
onLoop: () => console.log("loop completed"),
onFrameChange: (frame) => console.log("now on frame", frame),
});
- 非循环动画到达最后一帧时触发
onComplete。 - 循环动画每次循环时触发
onLoop。 - 显示帧每次变化时触发
onFrameChange。
手动更新模式
const gif = new GifSprite({ source, autoUpdate: false });
app.ticker.add((ticker) => {
gif.update(ticker);
});
autoUpdate: false 会断开与 Ticker.shared 的连接。你需要自行调用 gif.update(ticker),并传入任意 Ticker 实例。适用于需要由私有 ticker 驱动动画的情况(例如支持暂停的游戏 ticker)。
共享源数据和克隆
const source = await Assets.load("animation.gif");
const gif1 = new GifSprite({ source, autoPlay: true });
const gif2 = new GifSprite({ source, autoPlay: false });
const gif3 = gif1.clone();
gif3.animationSpeed = 0.5;
多个 GifSprite 实例可以共享同一个 GifSource;每个精灵都有独立的播放状态。clone() 会复制所有播放设置,但创建独立实例。
常见错误
[HIGH] 未导入 pixi.js/gif
错误:
import { Assets } from "pixi.js";
const gif = await Assets.load("animation.gif");
正确:
import "pixi.js/gif";
import { Assets } from "pixi.js";
const source = await Assets.load("animation.gif");
必须先注册 GIF 加载器扩展,再加载 GIF。若未进行副作用导入,加载器就无法识别 .gif 文件,导致加载失败或返回原始数据。
[MEDIUM] 误以为 Assets.load 会返回 Texture
错误:
const texture = await Assets.load("animation.gif");
const sprite = new Sprite(texture);
正确:
const source = await Assets.load("animation.gif");
const gif = new GifSprite({ source });
对 GIF 使用 Assets.load 会返回一个 GifSource,其中包含帧纹理和时序数据。将该源传递给 GifSprite;若只需要单帧静态图像,则读取 source.textures[0]。
[MEDIUM] 销毁时未释放 GIF 内存
错误:
gif.destroy();
// GifSource and frame textures remain in memory
正确:
gif.destroy(true);
// or
await Assets.unload("animation.gif");
GIF 帧会以独立画布纹理的形式持有已解码的像素数据。gif.destroy()(或 destroy(false))会销毁精灵,但保留 GifSource。传入 true 也会销毁源数据。如果源数据被共享,请等最后一个使用者完成后再销毁,或调用 Assets.unload 让资源缓存处理。
[LOW] 不要在 GifSprite 中嵌套子项
GifSprite 继承自 Sprite,后者会设置 allowChildren = false。它是一个叶节点。若要将 GIF 与其他显示对象组合,请将它们全部放入普通的 Container 中:
const group = new Container();
group.addChild(gif, label);