关于 pixijs-scene-particle-container
面向 PixiJS 开发者的技能,介绍如何用 ParticleContainer 批量渲染共享纹理的轻量粒子。内容涵盖粒子管理、GPU 更新设置,以及这种专用容器的功能取舍。
主要功能
- 01批量渲染共享纹理的粒子
- 02创建和批量管理粒子
- 03配置动态 GPU 属性
- 04自定义粒子着色器
- 05在容器级设置色调、透明度和混合模式
适用场景
- 01渲染包含大量精灵的粒子效果
- 02使用共享纹理制作弹幕
- 03通过标记动画属性优化更新
- 04为整批粒子调整色调或淡出
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pixijs/ pixijs-skills --skill pixijs-scene-particle-container安装后在 Claude Code 中输入/pixijs-scene-particle-container确认已加载。
详细介绍
ParticleContainer 是一种专用容器,可通过一次绘制调用渲染数百到数万个轻量级精灵。它适用于粒子效果、子弹阵列,或任何需要大量外观相似对象且希望尽量减少单对象开销的场景。粒子共用一个基础纹理,并且可使用的变换有限;它们不是完整的 Container 子对象。
假设你已熟悉 pixijs-scene-core-concepts。从另一个角度来说,ParticleContainer 是一种特殊的叶节点:它将 Particle 实例存放在自己的 particleChildren 数组中,并拒绝普通的 PixiJS 子对象。请使用 addParticle,而非 addChild;如果需要将整个 ParticleContainer 与其他场景对象编组,请将它包装在一个 Container 中。
Particle API 在 v8 中是新增的,但已稳定,可用于生产环境。
快速入门
const texture = await Assets.load("particle.png");
const container = new ParticleContainer({
texture,
boundsArea: new Rectangle(0, 0, app.screen.width, app.screen.height),
dynamicProperties: {
position: true,
rotation: false,
color: false,
},
});
for (let i = 0; i < 10000; i++) {
container.addParticle(
new Particle({
texture,
x: Math.random() * app.screen.width,
y: Math.random() * app.screen.height,
}),
);
}
app.stage.addChild(container);
相关技能: pixijs-scene-core-concepts(场景图基础知识)、pixijs-scene-sprite(需要为每个对象使用完整功能时)、pixijs-assets(共享纹理、图集)、pixijs-performance(批处理、纹理优化)、pixijs-scene-container(与其他显示对象一起包装)。
构造函数选项
ParticleContainerOptions
所有 Container 选项(position、scale、tint、label、filters、zIndex 等)在此处同样有效,详见 skills/pixijs-scene-core-concepts/references/constructor-options.md。请注意,children 已省略:请改用 particles。
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
texture | Texture | null | 所有粒子共用的基础纹理。如果省略,容器会回退到添加的第一个粒子的纹理;每个粒子都必须共用相同的基础纹理源。 |
particles | T[] | [] | 初始 Particle(或 IParticle)实例数组。相当于对每个实例调用 addParticle,但会跳过逐次调用时的视图更新。 |
dynamicProperties | ParticleProperties | { vertex: false, position: true, rotation: false, uvs: false, color: false } | 标记每帧重新上传到 GPU 的粒子属性。默认只有 position 是动态的;请将需要进行动画处理的属性标记为动态,其余属性保持静态以提升速度。 |
roundPixels | boolean | false | 将粒子位置四舍五入到最近的像素。对于像素艺术风格,这能让渲染更清晰,但会牺牲平滑的亚像素运动。 |
shader | Shader | 默认粒子着色器 | 替换默认粒子着色器。自定义着色器必须声明 aPosition、aUV、aColor,以及通过 dynamicProperties 启用的任何仅动态属性。 |
boundsArea 继承自 Container,但对于 ParticleContainer 来说实际上是必需的:为了提升性能,容器默认返回空边界 (0, 0, 0, 0);因此,在启用剔除时,如果没有设置 boundsArea,容器会被当作不可见对象剔除,而且 containsPoint 始终判定为未命中。
ParticleOptions
Particle 是轻量级结构体,而非 Container 子类,因此 ContainerOptions 中的字段均不适用。完整选项列表如下:
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
texture | Texture | — | 必填。用于渲染此粒子的纹理。同一 ParticleContainer 中的所有粒子必须共享相同的基础纹理源。 |
x | number | 0 | 容器局部空间中的 X 坐标。 |
y | number | 0 | 容器局部空间中的 Y 坐标。 |
scaleX | number | 1 | 水平缩放系数。 |
scaleY | number | 1 | 垂直缩放系数。 |
anchorX | number | 0 | 0–1 范围内的水平锚点;0 表示左侧,0.5 表示中心,1 表示右侧。 |
anchorY | number | 0 | 0–1 范围内的垂直锚点;0 表示顶部,0.5 表示中心,1 表示底部。 |
rotation | number | 0 | 旋转角度,单位为弧度。 |
tint | ColorSource | 0xffffff | 色调颜色,可使用十六进制数或 CSS 颜色字符串。与 alpha 合并后写入内部 color 字段。 |
alpha | number | 1 | 透明度(0–1)。超出范围的值会被限制在范围内。与 tint 合并后写入内部 color 字段。 |
构造函数也接受一个直接传入的 Texture 作为唯一参数(new Particle(texture)),这等同于使用上述默认值调用 new Particle({ texture })。
Particle.defaultOptions 是一个静态对象,可重新赋值以全局更改默认值;请参见下文的“创建粒子”部分。
核心模式
创建粒子
const particle = new Particle({
texture,
x: 100,
y: 200,
scaleX: 0.5,
scaleY: 0.5,
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 4,
tint: 0xff0000,
alpha: 0.8,
});
container.addParticle(particle);
Particle 是具有扁平数值字段的轻量级结构体:x、y、scaleX、scaleY、anchorX、anchorY、rotation、color、texture。它还提供 tint(十六进制/CSS 颜色)和 alpha(0-1)设置器,这些设置器会将值合并到内部 color 字段中。它没有变换层级、事件或滤镜。
你可以直接传入一个 Texture 作为唯一参数:new Particle(texture)。
重写 Particle.defaultOptions 可全局更改默认值:
Particle.defaultOptions = {
...Particle.defaultOptions,
anchorX: 0.5,
anchorY: 0.5,
};
使用 particles 选项预先填充
const particles = Array.from(
{ length: 10000 },
() =>
new Particle({
texture,
x: Math.random() * 800,
y: Math.random() * 600,
}),
);
const container = new ParticleContainer({
texture,
boundsArea: new Rectangle(0, 0, 800, 600),
particles,
});
在构造函数中传入 particles,等同于创建一个空容器并逐个调用 addParticle,但可以避免每次调用都更新视图。
动态属性与静态属性及 update()
const container = new ParticleContainer({
dynamicProperties: {
rotation: true,
},
});
dynamicProperties 控制每帧重新上传到 GPU 的粒子属性。ParticleContainer.defaultOptions.dynamicProperties 的默认值为:
{ vertex: false, position: true, rotation: false, uvs: false, color: false }
你只需覆盖正在动画的属性,其余属性会沿用默认值(位置为动态,其他属性均为静态)。总共有五种属性:
vertex:缩放/锚点顶点position:位置rotation:旋转uvs:纹理坐标(用于帧切换的粒子)color:色调和透明度
只标记正在动画的属性;静态属性开销更低。如果在运行时更改静态属性,请调用 container.update() 重新上传:
container.particleChildren.forEach((p) => {
p.tint = 0x00ff00;
});
container.update();
对 particleChildren 执行批量操作
// Bulk add
const batch = [];
for (let i = 0; i < 5000; i++) {
batch.push(
new Particle({ texture, x: Math.random() * 800, y: Math.random() * 600 }),
);
}
container.particleChildren.push(...batch);
container.update();
// Bulk remove
container.particleChildren.length = 0;
container.update();
addParticle、addParticleAt、removeParticle、removeParticleAt 和 removeParticles 每次调用都会触发视图更新。对于大型批量操作,直接操作数组并只调用一次 update() 会更快。
纹理和着色器选项
ParticleContainerOptions 中的 texture 是可选的。如果省略,容器会回退到添加的第一个粒子的纹理;之后的每个粒子都必须共享相同的基础纹理源。如果要预先指定图集,或第一个粒子可能在运行过程中发生变化,请显式设置:
const container = new ParticleContainer({ texture });
shader 可用于将默认粒子着色器替换为任意 Shader 实例。自定义着色器必须声明粒子管线上传的属性(aPosition、aUV、aColor,以及通过 dynamicProperties 启用的任何仅动态属性)。可用于自定义混合运算、距离场精灵或非标准效果:
const container = new ParticleContainer({ texture, shader: myCustomShader });
淡化或着色整个粒子系统
const burst = new ParticleContainer({ texture, particles });
const layer = new Container();
layer.addChild(burst);
app.ticker.add(() => {
layer.alpha -= 0.01; // fades every particle
});
burst.tint = 0x66ccff; // tints every particle
容器的 alpha、tint 和 blendMode 会像应用于精灵一样级联到粒子,因此你可以淡化或重新着色整个系统,而无需操作 particleChildren。
限制
ParticleContainer 有意牺牲部分功能以提升速度:
- 不支持滤镜、遮罩或单个粒子的混合模式。混合模式应用于容器级别:在
ParticleContainer上设置blendMode,或让它从父级Container继承(默认值"inherit"会解析为祖先的混合模式,与Sprite和Mesh相同)。整个粒子批次共享一种混合模式。容器或任意祖先上的alpha和tint会与每个粒子自身的alpha/tint相乘。 - 粒子不支持嵌套子级。
- 不会自动计算边界。
- 所有粒子都必须共享相同的基础纹理源(支持图集;不支持多个互不相关的纹理)。
- 支持通过
shader选项使用自定义着色器。
容器方法迁移
ParticleContainer 使用单独的子级管理 API,以优化 GPU 缓冲区更新。在 ParticleContainer 上调用标准 Container 子级方法会抛出异常。
| 标准 Container 方法 | ParticleContainer 对应方法 |
|---|---|
addChild(child) | addParticle(particle) |
removeChild(child) | removeParticle(particle) |
addChildAt(child, index) | addParticleAt(particle, index) |
removeChildAt(index) | removeParticleAt(index) |
removeChildren(begin, end) | removeParticles(begin, end) |
getChildAt(index) | 直接访问 container.particleChildren[index] |
swapChildren() | 不可用 |
reparentChild() | 不可用 |
常见错误
[CRITICAL] 向 ParticleContainer 添加精灵
错误:
const container = new ParticleContainer();
const sprite = new Sprite(texture);
container.addChild(sprite);
正确:
const container = new ParticleContainer();
const particle = new Particle(texture);
container.addParticle(particle);
ParticleContainer 不接受 Sprite 子对象。addChild 会抛出错误。粒子必须是 Particle 实例(或任何实现了 IParticle 的对象),并通过 addParticle 添加。这是相较于 v7 的全面重构;在 v7 中,ParticleContainer 接受 Sprite 子对象。
[HIGH] 未在 ParticleContainer 上设置 boundsArea
错误:
const container = new ParticleContainer();
// bounds is always (0, 0, 0, 0) — culling and hit testing fail
正确:
const container = new ParticleContainer({
boundsArea: new Rectangle(0, 0, 800, 600),
});
为了提高性能,ParticleContainer 默认返回空边界 (0, 0, 0, 0)。如果未设置 boundsArea,启用剔除时容器会被视为不可见并被剔除,且 containsPoint 总会判定为未命中。请将 boundsArea 设置为粒子所在的区域。
[HIGH] 使用 children 而不是 particleChildren
错误:
container.addParticle(new Particle(texture));
console.log(container.children.length); // 0
正确:
container.addParticle(new Particle(texture));
console.log(container.particleChildren.length); // 1
粒子存储在 particleChildren 数组中,而非 children 中。ParticleContainer 的标准 Container.children 数组为空。所有粒子枚举、计数和操作都必须使用 particleChildren 以及 *Particle 方法。
[MEDIUM] 不要将 ParticleContainer 用作普通容器
ParticleContainer 包含的是粒子,而不是显示对象。如果需要将粒子系统与背景精灵或 UI 覆盖层组合在一起,请将 ParticleContainer 本身包装在一个普通的 Container 中:
const world = new Container();
world.addChild(backgroundSprite, particleContainer, uiLayer);