粒子系统
Estella 提供基于 GPU 实例化渲染的 2D 粒子系统,使用 C++ 后端模拟。ParticlePlugin 由引擎默认包含。
ParticleEmitter 组件
在带有 Transform 的实体上添加 ParticleEmitter 即可从该位置发射粒子。
通用
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | boolean | true | 组件激活 |
playOnStart | boolean | true | 实体加载时自动播放 |
looping | boolean | true | 持续时间结束后重新开始 |
duration | number | 5 | 发射持续时间(秒) |
发射
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
rate | number | 10 | 每秒发射粒子数 |
burstCount | number | 0 | 每次爆发发射粒子数(0 = 禁用) |
burstInterval | number | 1 | 爆发间隔(秒) |
maxParticles | number | 1000 | 最大存活粒子数 |
生命周期
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
lifetimeMin | number | 5 | 最小粒子寿命(秒) |
lifetimeMax | number | 5 | 最大粒子寿命(秒) |
形状
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
shape | number | 3 | 发射形状(见下方) |
shapeRadius | number | 100 | 圆形和锥形的半径 |
shapeSize | Vec2 | {100, 100} | 矩形的宽高 |
shapeAngle | number | 25 | 锥形的半角(度,0–360) |
发射形状:
| 值 | 形状 | 说明 |
|---|---|---|
0 | 点 | 从单个点发射 |
1 | 圆形 | 从圆形区域内随机位置发射 |
2 | 矩形 | 从矩形区域内随机位置发射 |
3 | 锥形 | 从发射器原点以锥形方向发射 |
速度
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
speedMin | number | 500 | 最小初始速度 |
speedMax | number | 500 | 最大初始速度 |
angleSpreadMin | number | 0 | 最小发射角度(度,0–360) |
angleSpreadMax | number | 360 | 最大发射角度(度,0–360) |
大小随生命变化
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
startSizeMin | number | 100 | 出生时最小尺寸 |
startSizeMax | number | 100 | 出生时最大尺寸 |
endSizeMin | number | 100 | 消亡时最小尺寸 |
endSizeMax | number | 100 | 消亡时最大尺寸 |
sizeEasing | number | 0 | 插值曲线(0=Linear, 1=EaseIn, 2=EaseOut, 3=EaseInOut) |
颜色随生命变化
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
startColor | Color | {1,1,1,1} | 出生时颜色(RGBA) |
endColor | Color | {1,1,1,0} | 消亡时颜色(RGBA,默认淡出) |
colorEasing | number | 0 | 插值曲线(0=Linear, 1=EaseIn, 2=EaseOut, 3=EaseInOut) |
旋转
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
rotationMin | number | 0 | 最小初始旋转角度(度) |
rotationMax | number | 0 | 最大初始旋转角度(度) |
angularVelocityMin | number | 0 | 最小旋转速度(度/秒) |
angularVelocityMax | number | 0 | 最大旋转速度(度/秒) |
作用力
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
gravity | Vec2 | {0, 0} | 每帧施加的重力 |
damping | number | 0 | 速度阻尼系数(摩擦) |
纹理与精灵表
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
texture | TextureHandle | — | 粒子纹理 |
spriteColumns | number | 1 | 精灵表列数 |
spriteRows | number | 1 | 精灵表行数 |
spriteFPS | number | 10 | 精灵表动画帧率 |
spriteLoop | boolean | true | 循环播放精灵表动画 |
渲染
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
blendMode | number | 1 | 0 = 正常, 1 = 叠加(默认) |
layer | number | 0 | 渲染层级(-1000 到 1000) |
material | number | 0 | 自定义材质 ID(0 = 默认) |
simulationSpace | number | 0 | 0 = 世界空间, 1 = 本地空间 |
运行时 API
使用静态 Particle 对象从代码控制发射器:
import { Particle } from 'esengine';
// 开始发射Particle.play(entity);
// 停止发射(已存在的粒子继续其生命周期)Particle.stop(entity);
// 重置发射器状态并清除所有存活粒子Particle.reset(entity);
// 查询存活粒子数const count = Particle.getAliveCount(entity);控制发射器属性
在系统中查询和修改 ParticleEmitter:
import { defineSystem, addSystem, Query, Mut, ParticleEmitter } from 'esengine';
addSystem(defineSystem( [Query(Mut(ParticleEmitter))], (query) => { for (const [entity, emitter] of query) { emitter.rate = 50; emitter.startColor = { r: 1, g: 0.5, b: 0, a: 1 }; emitter.endColor = { r: 1, g: 0, b: 0, a: 0 }; emitter.gravity = { x: 0, y: -500 }; } }));自定义材质
为粒子指定自定义材质以实现特殊渲染效果:
emitter.material = myMaterialHandle;粒子渲染器会对指定材质调用 getMaterialDataWithUniforms,因此你定义的任何 Shader Uniform 都会按发射器生效。
UIMask 兼容
粒子遵守 UIMask 的裁剪区域。在可滚动 UI 面板中使用粒子:
- 在面板实体上添加
UIMask组件(Scissor 模式) - 将
ParticleEmitter实体作为遮罩容器的子实体 - 粒子将被裁剪到遮罩区域内
编辑器集成
- 检查器 — 属性按可折叠分组展示(发射、生命周期、形状、速度、大小、颜色、旋转、作用力、纹理、渲染),数值输入带约束
- Scene View 叠加层 — 选中
ParticleEmitter实体时,Scene View 会绘制发射形状的 Gizmo:- 点:十字标记
- 圆形:虚线圆轮廓
- 矩形:虚线矩形轮廓
- 锥形:扇形展示发射角度范围
- Hierarchy — 右键 → 创建 → Particle 可添加新的粒子实体
枚举常量
使用命名常量提高可读性:
import { EmitterShape, SimulationSpace, ParticleEasing } from 'esengine';
emitter.shape = EmitterShape.Circle;emitter.simulationSpace = SimulationSpace.Local;emitter.sizeEasing = ParticleEasing.EaseOut;emitter.colorEasing = ParticleEasing.EaseInOut;| 枚举 | 值 |
|---|---|
EmitterShape | Point (0), Circle (1), Rectangle (2), Cone (3) |
SimulationSpace | World (0), Local (1) |
ParticleEasing | Linear (0), EaseIn (1), EaseOut (2), EaseInOut (3) |
示例:火焰效果
import { defineSystem, addStartupSystem, Commands, Transform, ParticleEmitter, EmitterShape, ParticleEasing} from 'esengine';
addStartupSystem(defineSystem( [Commands()], (commands) => { commands.spawn() .insert(Transform, { position: { x: 400, y: 300, z: 0 } }) .insert(ParticleEmitter, { rate: 30, lifetimeMin: 0.5, lifetimeMax: 1.5, shape: EmitterShape.Circle, shapeRadius: 20, speedMin: 100, speedMax: 200, angleSpreadMin: 250, angleSpreadMax: 290, startSizeMin: 40, startSizeMax: 60, endSizeMin: 5, endSizeMax: 10, sizeEasing: ParticleEasing.EaseIn, startColor: { r: 1, g: 0.8, b: 0.2, a: 1 }, endColor: { r: 1, g: 0.2, b: 0, a: 0 }, colorEasing: ParticleEasing.EaseOut, gravity: { x: 0, y: -50 }, blendMode: 1, }); }));