关于 particle-system
面向 Decentraland SDK7 ParticleSystem 的配置指南,涵盖发射器设置、粒子行为、编辑器调节及实用限制,适用于制作场景特效的创作者。
主要功能
- 01点、球体、圆锥和方盒发射器
- 02连续发射与爆发发射
- 03颜色、尺寸、运动和序列帧控制
- 04播放状态与模拟空间设置
- 05Creator Hub 检视器使用指南
适用场景
- 01创建循环或单次场景特效
- 02制作轨迹、降雪、火花或烟花
- 03在 Creator Hub 调节粒子发射器
- 04将粒子数量控制在场景预算内
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ decentraland/ sdk-skills --skill particle-system安装后在 Claude Code 中输入/particle-system确认已加载。
附带文件references/particle-presets.md
详细介绍
ParticleSystem(SDK7)
从实体发射粒子。每个实体只能有一个 ParticleSystem 组件,并与 Transform 一同附加。无需网格——粒子直接由组件渲染。
规则:Transform.scale 不会缩放粒子
粒子大小仅由 initialSize 和 sizeOverTime(FloatRange)控制。ParticleSystem 还会设置发射器形状的空间尺寸(当形状包含尺寸字段时,例如 Sphere 的 radius、Box 的 size、Cone 的 radius)。这些尺寸不受实体 Transform.scale 影响。增大 Transform.scale 不会让粒子变大。
规则:粒子只会渲染给位于场景地块内的玩家
从场景地块外观看场景的玩家看不到粒子。粒子不属于场景 LOD 轮廓。请将发射器放置在地块范围内。
规则:引擎将粒子总数限制在约 1000 个
引擎会强制执行每个场景的粒子预算;如果所有活动粒子的总数可能超过限制,就会降低所有活动粒子系统的发射率。请为每个系统设置 maxParticles,并优先使用少量效果显著的系统,而不是许多小型系统。
移动端预算(已发布的数据)
移动端客户端公布了明确的数据(文档提交 8139a7f,2026 年 10 月):
| 软限制 | 硬限制 | |
|---|---|---|
| VFX 发射器(场景中的粒子系统) | 8 | 10 |
| 活动粒子 | 25,000 | 50,000 |
软限制 = 移动端性能面板中显示警告;硬限制 = 场景将无法加载。除场景限制外,移动端还会在运行时将每个发射器的粒子数限制为 5,000 个、每个场景限制为 50,000 个——超过这些上限的配置会被静默调低,因此将 maxParticles 设为高于 5,000 只会浪费预算,不会带来视觉效果。
实用目标:发射器不超过 8 个,每个发射器的 maxParticles 远低于 5,000,并控制同时活动粒子的总数。[未验证:上文“约 1000 个”的桌面端数据与这些移动端数据之间的关系——它们来自不同来源,因此跨平台场景应以较严格的限制作为设计目标。]
完整的移动端限制表以及灯光/粒子相关说明:optimize-scene → 移动端场景限制。移动端支持 ParticleSystem(它不再是兼容性差异)。
规则:预热要求 loop = true
prewarm: true 只有在 loop: true 时才会生效。对于单次播放系统(loop: false),预热会被静默忽略。
规则:faceTravelDirection 会覆盖 billboard
当 faceTravelDirection: true 时,粒子会沿其速度向量定向,并忽略 billboard。用于轨迹/拖尾效果(小行星、子弹、火花)。请显式设置 billboard: false,以免造成混淆。
导入
import { engine, Transform, ParticleSystem } from '@dcl/sdk/ecs'
import {
PBParticleSystem_BlendMode,
PBParticleSystem_PlaybackState,
PBParticleSystem_SimulationSpace,
} from '@dcl/sdk/ecs'
import { Color4, Vector3, Quaternion } from '@dcl/sdk/math'
ParticleSystemBlendMode 和 ParticleSystemPlaybackState 别名也从 @dcl/sdk/ecs 导出,可与带 PB 前缀的名称互换使用。没有 ParticleSystemSimulationSpace 别名——只有 PBParticleSystem_SimulationSpace。为保持一致,请始终优先使用带 PB 前缀的名称。
字段参考
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
active | boolean | true | 控制是否启用新粒子发射。 |
rate | number | 10 | 每秒发射的粒子数(连续发射)。使用 bursts 时设为 0。 |
maxParticles | number | 1000 | 此系统中同时存活的粒子数量上限。 |
lifetime | number | 5 | 粒子生命周期,单位为秒。 |
gravity | number | 0 | 场景重力的倍率(约为 -9.81 m/s²)。负值表示粒子上升。 |
additionalForce | Vector3 | — | 每帧施加的恒定力向量(世界空间)。 |
initialSize | FloatRange | {start:1, end:1} | 生成时的随机尺寸。 |
sizeOverTime | FloatRange | {start:1, end:1} | 粒子生命周期内从起始值到结束值插值的尺寸。 |
initialRotation | Quaternion | identity | 生成时的朝向(3D)。 |
rotationOverTime | Quaternion | identity | 各轴角速度(四元数转换为等效的 Euler XYZ 弧度/秒)。 |
faceTravelDirection | boolean | false | 沿速度方向调整朝向。优先于 billboard。 |
initialColor | ColorRange | {white,white} | 生成时的随机颜色。 |
colorOverTime | ColorRange | {white,white} | 生命周期内从起始颜色到结束颜色插值。将结束时的 alpha 设为 0 可淡出。 |
initialVelocitySpeed | FloatRange | {start:1, end:1} | 初始速度,单位为 m/s;每个粒子的速度随机生成。 |
texture | Texture | 白色四边形 | 粒子精灵图。与 Material 纹理使用相同的 Texture 结构。 |
blendMode | PBParticleSystem_BlendMode | PSB_ALPHA | PSB_ALPHA | PSB_ADD | PSB_MULTIPLY。 |
billboard | boolean | true | 粒子始终面向摄像机。对于具有 3D 朝向的粒子,请禁用此项。 |
spriteSheet | {tilesX, tilesY, framesPerSecond?} | — | 纹理图集帧动画。framesPerSecond 默认为 30。 |
shape | oneof Point/Sphere/Cone/Box | Point | 发射器几何形状 — 见下文。 |
loop | boolean | true | 循环发射周期。false 表示仅发射一次。 |
prewarm | boolean | false | 启动时视为已模拟完整个循环。要求 loop: true。 |
simulationSpace | PBParticleSystem_SimulationSpace | PSS_LOCAL | PSS_LOCAL(随实体移动)| PSS_WORLD(生成后保持原位)。 |
limitVelocity | {speed, dampen?} | — | 限制最高速度。dampen 范围为 0–1,默认为 1,表示硬性限制。 |
playbackState | PBParticleSystem_PlaybackState | PS_PLAYING | PS_PLAYING | PS_PAUSED | PS_STOPPED。 |
bursts | {values: Burst[]} | — | 离散发射事件(见 Bursts)。 |
FloatRange = { start: number, end: number } — 每个粒子采样一个随机值。 | |||
ColorRange = { start: Color4, end: Color4 } — 每个粒子采样一个随机颜色(范围两端的采样彼此独立于其他粒子的随机值)。 |
发射器形状
使用 ParticleSystem.Shape.* 辅助函数构建 — 切勿手动组装 oneof:
shape: ParticleSystem.Shape.Point()
shape: ParticleSystem.Shape.Sphere({ radius: 1 }) // default radius=1
shape: ParticleSystem.Shape.Cone({ angle: 25, radius: 1 }) // angle = half-angle in degrees
shape: ParticleSystem.Shape.Box({ size: Vector3.create(1, 1, 1) })
- Point — 从实体原点发射。
- Sphere — 在
radius指定的球体内随机取点。 - Cone — 从底面圆盘发射,并在半角
angle范围内向外投射。圆锥的默认方向为实体的局部前向;旋转父级 Transform 即可调整发射方向。 - Box — 在
size指定的轴对齐方框内随机取点。
若要旋转发射方向(例如让圆锥朝下发射雪花或雨滴),请旋转父实体的 Transform.rotation。例如,圆锥向下飘雪时,可在实体上设置 rotation: Quaternion.fromEulerDegrees(180, 0, 0),或使用任何能翻转圆锥轴的朝向。
爆发
在特定时间发生的离散发射事件。将 rate: 0 设为仅使用爆发,或与 rate > 0 组合以实现连续发射与爆发发射。
bursts: {
values: [{ time: 0, count: 100, cycles: 1, interval: 0.01, probability: 1.0 }]
}
爆发字段:time(从循环开始计算的秒数)、count(每次爆发的粒子数)、cycles(默认值为 1,0 = 无限循环)、interval(循环间隔秒数,默认值为 0.01)、probability(每次循环触发的概率,范围为 0–1,默认值为 1)。
同一循环中的多次爆发 = 错落点火模式(烟花)。
常见模式
ParticleSystem 定义的组成 — 附加到同时具有 Transform 的实体上:
const emitter = engine.addEntity()
Transform.create(emitter, { position: Vector3.create(8, 1, 8) })
ParticleSystem.create(emitter, {
rate: 20, // particles per second
lifetime: 2, // seconds each particle lives
maxParticles: 100,
initialSize: { start: 0.1, end: 0.3 }, // FloatRange sampled per particle
sizeOverTime: { start: 1.0, end: 0.0 }, // shrink to nothing over lifetime
initialVelocitySpeed: { start: 1, end: 2 },
colorOverTime: {
// fade out via alpha = 0 at end
start: Color4.create(1, 1, 1, 1),
end: Color4.create(1, 1, 1, 0),
},
shape: ParticleSystem.Shape.Point(), // emitter geometry
})
完整的生产级配置请参阅 {baseDir}/references/particle-presets.md — 共 17 个预设:Fire Ember、Magic Aura、Snowfall、Vortex Spiral、Gravity Fountain、Bat Swarm、Tumbling Leaves、Lightning Sparks、Heavy Rain、One-Shot Burst、Asteroid Trail、Purple Swirl、Bee Swarm、Fireworks Loop、Campfire、Flame Wisps、Moving Trail。爆炸/拾取物 VFX(Point/Cone + ADD 火焰、单次 Sphere 爆发)都在其中 — 例如 Fire Ember(预设 1)、One-Shot Burst 爆炸(预设 10)以及循环播放的 Fireworks Loop(预设 14)。
Creator Hub 编辑器集成
Creator Hub 检查器提供专用的 ParticleSystem 面板(已验证源码:ParticleSystemInspector.tsx,支持多实体,已在 EntityInspector.tsx 中注册)。在 Creator Hub 场景中创建和调整粒子效果,推荐使用以下方式:
- 在编辑器中为实体添加
ParticleSystem组件。 - 在检查器面板中实时调整所有字段 -- 无需编写代码,也无需重新加载场景。
仅在动态运行时行为需要时使用代码(在 src/ 中调用 ParticleSystem.create/getMutable,或通过 Script 组件):例如通过游戏逻辑切换发射器、将播放/停止绑定到触发器/操作,或在运行时计算配置。
程序化 / 复合组件名称
- 组件名称:
core::ParticleSystem(组件 ID1217)。 shape是 protobuf oneof,序列化为{"$case":"sphere","sphere":{"radius":1}}、{"$case":"cone","cone":{"angle":25,"radius":1}}、{"$case":"box","box":{"size":{"x":1,"y":1,"z":1}}}或{"$case":"point","point":{}}。texture是扁平的Texture(不是TextureUnion),序列化为{"src":"assets/Images/spark.png"}。Material使用的$case/tex封装不适用于此处。
播放控制
const ps = ParticleSystem.getMutable(entity)
// Pause emission and freeze existing particles
ps.playbackState = PBParticleSystem_PlaybackState.PS_PAUSED
// Resume
ps.playbackState = PBParticleSystem_PlaybackState.PS_PLAYING
// Stop and clear all live particles
ps.playbackState = PBParticleSystem_PlaybackState.PS_STOPPED
// Disable new emission (existing particles continue to live out their lifetime)
ps.active = false
使用 playbackState = PS_STOPPED 可立即停止。使用 active = false 可平缓结束粒子尾迹。
精灵表动画
纹理图集中的帧按网格排列(从左到右、从上到下)。总帧数 = tilesX * tilesY。
texture: { src: 'assets/Images/flame-sheet.png' },
spriteSheet: { tilesX: 4, tilesY: 3, framesPerSecond: 12 } // 12 frames, plays at 12fps
测试场景示例使用 4x4(16 帧,蝙蝠群 @24fps)、4x3(12 帧,火焰/焰苗 @10–12fps)和 1x20(20 帧条带,蜜蜂 @30fps)精灵表。
模拟空间(本地与世界)
PSS_LOCAL(默认)——粒子随发射器移动。发射器移动时,会带动粒子群一起移动。适合用于移动实体上的光环效果。PSS_WORLD——粒子会停留在生成时的世界空间位置,因此发射器移动时会在身后留下轨迹。
对于由 Tween 驱动的发射器(已在 0,7-particle-system 的“Moving Trail”中验证):PSS_LOCAL 会让粒子群在实体移动时始终附着在实体上;如果希望生成的粒子停留在原地并形成持久轨迹,则切换为 PSS_WORLD。测试场景展示了使用 PSS_LOCAL 的效果——根据你想要的视觉效果选择空间,而非将其视为硬性要求。
纹理字段
texture 字段使用与 Material 相同的 Texture 类型。常见情况(本地文件):
texture: {
src: 'assets/Images/spark.png'
}
完整的 Texture 格式支持 filterMode/wrapMode,但粒子系统通常只需要 src。粒子上的 Avatar/Video 纹理尚未验证——请使用文件纹理。
注意事项
- 纹理路径——粒子纹理默认使用
assets/Images/。路径约定与 Material 纹理相同。旧场景可能将纹理放在assets/scene/Images/或assets/scene/textures/下(仍可使用);Creator Hub 资源包中的纹理会放在assets/asset-packs/,自定义项则放在assets/custom/——按原路径引用即可。 - 四元数旋转字段——
rotationOverTime会被解释为各轴的角速度(四元数 → Euler XYZ)。Quaternion.fromEulerDegrees(0, 90, 0)= 绕 Y 轴以 90°/s 旋转。单位四元数 = 不旋转。 - 即使
simulationSpace = PSS_LOCAL,additionalForce仍使用世界空间。无论发射器如何旋转,风力/漂移方向都保持不变。 limitVelocity.dampen = 1= 硬性限速(粒子速度不会超过speed)。较低的值允许速度短暂超过上限,随后再衰减。- 在
colorOverTime末尾将 Color.alpha 设为 0 是淡出粒子的标准方式——不要只依赖sizeOverTime以 0 结束。 - 评估时,爆发会忽略
active = false——active每帧只检查一次,用于连续发射速率;在爆发时间之后设置该值不会追溯取消爆发。 - 发射器实体上无需附加网格——添加
MeshRenderer并无关联;粒子由 ParticleSystem 组件本身渲染。
性能
- 尽量降低
lifetime * rate;该乘积就是稳定状态下的存活粒子数。 - 通过
playbackState = PS_STOPPED或active = false禁用视野外的系统。 - 对于不透明/半透明效果,优先使用
PSB_ALPHA。PSB_ADD最适合发光/火焰效果(视觉上会叠加),但多层加法混合过度绘制是开销最大的情况。 - 精灵表开销较低;不支持在单个系统中使用多个纹理(每个系统只能使用一个纹理)。
资源
{baseDir}/references/particle-presets.md— 来自 SDK7 测试场景的 17 种即用型预设配置(火焰、魔法、降雪、漩涡、喷泉、群集、火花、雨、爆发、烟花、营火、轨迹)。- 在线调节器:
ParticleLab.dcl.eth(使用 Decentraland 客户端打开)。
示例场景
https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/0,7-particle-system— 引擎团队的权威示例:上述全部 17 种预设、所有形状(Point/Sphere/Cone/Box)、PSB_ADD/PSB_ALPHA、连续rate与bursts(单次 + 循环烟花)、spriteSheet(4×4/4×3/1×20)、limitVelocity、billboard: false时的initialRotation/rotationOverTime、faceTravelDirection、additionalForce,以及展示simulationSpace的 Tween 驱动发射器。