mcpField
P
pixijs-scene-gif

pixijs-scene-gif

github.com/pixijs开发3585.7k 次安装4 周前更新
代码仓库

关于 pixijs-scene-gif

面向 PixiJS 开发者的 GIF 动画技能,介绍如何加载并用 GifSprite 显示动画,也涵盖播放控制、回调和共享帧数据管理。

主要功能

  1. 01使用 Assets.load 加载 GIF 资源
  2. 02控制循环与播放速度
  3. 03连接 Ticker 或手动驱动更新
  4. 04处理帧变化和完成回调
  5. 05共享源数据并克隆精灵

适用场景

  1. 01在 PixiJS 场景中添加 GIF 动画
  2. 02通过专用 Ticker 同步播放
  3. 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 新增的叶节点专属选项:

选项类型默认值说明
sourceGifSource—必填。由 Assets.load('file.gif') 返回的已解析 GIF 数据。可供多个 GifSprite 实例共享。
autoPlaybooleantrue构造时立即开始播放。若为 false,必须调用 gif.play() 才能开始播放。
loopbooleantrue到达最后一帧时重复播放动画。若为 false,精灵会停在最后一帧并触发 onComplete。
animationSpeednumber1GIF 原生帧计时的倍数。2 表示以双倍速度播放;0.5 表示以一半速度播放。
autoUpdatebooleantrue将播放连接到 Ticker.shared。设为 false 可通过 gif.update(ticker) 自行驱动更新。
fpsnumber30为未指定逐帧延迟的 GIF 提供的备用帧率。
onComplete() => void | nullnull非循环动画到达最后一帧时调用。
onLoop() => void | nullnull循环动画每次回到开头时调用。
onFrameChange(frame: number) => void | nullnull显示的帧索引每次变化时调用。
scaleModeSCALE_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);

API 参考

评论

支持 Markdown