ParticleEmitter
ParticleEmitter manages a Tier 2 (Jolt physics) particle system. Each particle is a Jolt dynamic body that collides with the world. Particles are rendered via InstancedMesh internally. Create via Scene.createParticleEmitter.
An emitter can also render its particles as non-physics sprites — surface-pinned rings and camera-facing sparkles that back water splashes and ripples. See Sprite render modes.
Creating an emitter
Section titled “Creating an emitter”scene.createParticleEmitter(name, maxBodies, size, mass, lifetime, emissionRate, x, y, z)
Section titled “scene.createParticleEmitter(name, maxBodies, size, mass, lifetime, emissionRate, x, y, z)”Returns: ParticleEmitter — A new emitter registered with the scene.
Parameters:
name(String) — Identifier for this emitter.maxBodies(Num) — Maximum particle pool size (number of simultaneous physics bodies).size(Num) — Particle size in metres.mass(Num) — Particle mass in kg.lifetime(Num) — Particle lifetime in seconds.emissionRate(Num) — Particles emitted per second.x,y,z(Num) — Initial emitter position.
_emitter = _scene.createParticleEmitter("sparks", 128, 0.05, 0.1, 2.0, 50, 0, 3, 0)Emitters can also be loaded automatically from .blend particle systems when instantiating with Resource.loadBlend.
Playback control
Section titled “Playback control”| Method | Description |
|---|---|
play() | Start emitting particles continuously at emissionRate. |
stop() | Stop emitting new particles (existing ones continue until their lifetime expires). |
pause() | Pause all simulation (freeze existing particles in place). |
resume() | Resume from a paused state. |
burst(count) | Immediately spawn count particles at the emitter position, ignoring emission rate. |
_emitter.play()
// On explosion:_emitter.burst(64)Properties
Section titled “Properties”| Property | Returns | Description |
|---|---|---|
isPlaying | Bool | true if emitting (not stopped or paused) |
isPaused | Bool | true if paused |
activeCount | Num | Current live particle count |
maxBodies | Num | Maximum pool size (set at creation) |
name | String | Emitter name |
emissionRate=(rate) | — | Set particles per second |
Emitter position & orientation
Section titled “Emitter position & orientation”setPosition(x, y, z)
Section titled “setPosition(x, y, z)”Move the emitter origin. New particles spawn from this position.
setNormal(nx, ny, nz)
Section titled “setNormal(nx, ny, nz)”Set the emission direction normal. Particles are given initial velocity along this direction (plus any random/tangential factors configured in the blend).
// Follow a nodevar pos = _nozzleNode.getWorldPosition()_emitter.setPosition(pos[0], pos[1], pos[2])
var fwd = _nozzleNode.getForward()_emitter.setNormal(fwd[0], fwd[1], fwd[2])Custom mesh
Section titled “Custom mesh”setMeshFromNode(node)
Section titled “setMeshFromNode(node)”Use the mesh from a Node to render particles instead of the default sphere.
_emitter.setMeshFromNode(_sparkMeshNode)Sprite render modes
Section titled “Sprite render modes”(engine main, ADR 0102)
An emitter can render its particles as non-physics sprites instead of physics-body meshes — the render path that backs water splashes and ripples. The sprite modes reuse the existing sprite pipeline, so there is no Vulkan renderer change. A sprite particle is a pinned kinematic decal: it has no Jolt body, stays where it spawns, and animates only via a scale-over-life and an alpha-over-life curve.
setRenderMode(mode)
Section titled “setRenderMode(mode)”Select how the emitter’s particles are drawn:
mode | Name | What it is |
|---|---|---|
0 | PhysicsMesh | (default) Jolt dynamic body + instanced mesh — the Tier 2 physics particles described above. Splash spray stays this mode. |
1 | SpriteGround | A soft sprite laid flat on the world XZ plane (BillboardMode::Ground). Burst one per beat for concentric, expanding, fading rings — a raindrop / footfall / floating object hitting water. |
2 | SpriteBillboard | The same sprite, camera-facing — e.g. a twinkling sparkle above the surface. |
setScaleCurve(startHalfSize, endHalfSize)
Section titled “setScaleCurve(startHalfSize, endHalfSize)”World-unit sprite half-size from spawn to death. Growing it (e.g. 0.25 → 3.2) turns a
point into a wide ring.
setAlphaCurve(startAlpha, endAlpha)
Section titled “setAlphaCurve(startAlpha, endAlpha)”Sprite opacity from spawn to death (e.g. 0.9 → 0.0 fades out over the particle’s life).
setColor(r, g, b)
Section titled “setColor(r, g, b)”Sprite RGB tint, each channel in [0, 1]. Alpha comes from the alpha curve, not from
this call.
setTexture(texture)
Section titled “setTexture(texture)”The sprite texture — typically a soft ring — a Texture obtained from
Texture.load(path).
// A surface-pinned ripple ring: flat on the water, grows + fades.// Args: name, maxBodies, size, mass, lifetime, emissionRate, x, y, z_ripples = _scene.createParticleEmitter("ripples", 64, 0.1, 0.0, 1.8, 0.0, 0, 0.02, 0)_ripples.setRenderMode(1) // SpriteGround — flat on the XZ plane_ripples.setTexture(Texture.load("textures/ring.png"))_ripples.setScaleCurve(0.25, 3.2) // half-size: spawn → death_ripples.setAlphaCurve(0.9, 0.0) // fade out_ripples.setColor(0.72, 0.90, 1.0) // pale cyan_ripples.play()
// Each beat, pin a fresh ring at the impact point:_ripples.setPosition(x, 0.02, z)_ripples.burst(1)Sprite particles are submitted through the sprite pipeline when the scene is drawn
(Scene.draw()). See the Particle FX Demo example.
See InstancedMesh for non-physics GPU instancing. See Scene for createParticleEmitter. See Physics for body configuration details (collision layers in game.toml apply to particle bodies).