Add particle systems and visual effects to an FXGL game — configure ParticleEmitter with function-based setters (setVelocityFunction, setAccelerationFunction, setExpireFunction, setScaleFunction, setSpawnPointFunction); use built-in factory emitters (fire, explosion, smoke, rain); apply image-textured particles with multiplyColor / toColor; write custom per-particle physics via setControl; attach TrailParticleComponent for motion trails; apply SlowTimeEffect for bullet-time; apply WobbleEffect for screen-shake; stack multiple effects with EffectComponent; build fireworks displays. Use this skill when adding explosions, fire, smoke, rain, motion trails, impact bursts, bullet-time slow-motion, screen shake, or any particle-based visual polish.
Add particle systems and visual effects to an FXGL game — configure ParticleEmitter with function-based setters (setVelocityFunction, setAccelerationFunction, setExpireFunction, setScaleFunction, setSpawnPointFunction); use built-in factory emitters (fire, explosion, smoke, rain); apply image-textured particles with multiplyColor / toColor; write custom per-particle physics via setControl; attach TrailParticleComponent for motion trails; apply SlowTimeEffect for bullet-time; apply WobbleEffect for screen-shake; stack multiple effects with EffectComponent; build fireworks displays. Use this skill when adding explosions, fire, smoke, rain, motion trails, impact bursts, bullet-time slow-motion, screen shake, or any particle-based visual polish.
// --- velocity: Function<Integer, Point2D> (i = particle index) ---
1
45
// --- acceleration: Supplier<Point2D> ---
new
Point2D
0
9.8
// downward gravity
// --- scale delta per frame: Function<Integer, Point2D> ---
0.01
// --- lifetime: Function<Integer, Duration> ---
0.25
2.5
// --- spawn offset from entity origin: Function<Integer, Point2D> ---
new
Point2D
5
5
5
5
// --- color ---
1
0
0
0
// fade to transparent
// --- blend mode ---
// ADD = glow; SRC_OVER = normal
// --- rotation ---
true
// --- interpolation curve ---
Attaching an Emitter to an Entity
import com.almasb.fxgl.particle.ParticleComponent;
// Continuous effect — lives as long as the entity
entityBuilder()
.at(torchX, torchY)
.with(newParticleComponent(ParticleEmitters.newFireEmitter()))
.buildAndAttach();
One-Shot Burst (Explosion / Impact)
import com.almasb.fxgl.dsl.components.ExpireCleanComponent;
ParticleEmitterburst= ParticleEmitters.newExplosionEmitter(80);
burst.setBlendMode(BlendMode.ADD);
burst.setStartColor(FXGLMath.randomColor());
burst.setEndColor(Color.color(1, 1, 0, 0));
burst.setExpireFunction(i -> Duration.seconds(random(1.25, 2.5)));
entityBuilder()
.at(hitX, hitY)
.with(newParticleComponent(burst))
.with(newExpireCleanComponent(Duration.seconds(3)).animateOpacity())
.zIndex(100)
.buildAndAttach();
// ExpireCleanComponent is required — without it the entity stays in the world forever.
Image-Textured Particles
Particles can use a source image instead of a solid rectangle.
Use texture().multiplyColor(color) to tint while preserving shape, or
texture().toColor(color) to fully recolor.
import javafx.scene.paint.Color;
Colorc= FXGLMath.randomColor();
// Tint: preserves the image shape, multiplies each pixel by the color
emitter.setSourceImage(texture("particles/flare_01.png", 64, 64).multiplyColor(c));
// Flat recolor: replaces all non-transparent pixels with the given color
emitter.setSourceImage(texture("particles/rain.png").toColor(Color.YELLOW));
setControl receives a Consumer<Particle> called every frame for every live particle.
Use the mutable Particle fields to implement noise fields, attractors, boundary bounce, etc.
ParticleEmitterrain= ParticleEmitters.newRainEmitter(getAppWidth() / 2);
rain.setSourceImage(texture("rain.png").multiplyColor(Color.BLUE));
entityBuilder()
.with(newParticleComponent(rain))
.buildAndAttach();
// Second lane with different color and interpolatorParticleEmitterrain2= ParticleEmitters.newRainEmitter(getAppWidth() / 2);
rain2.setSourceImage(texture("rain.png").toColor(Color.YELLOW));
rain2.setInterpolator(Interpolators.EXPONENTIAL.EASE_OUT());
entityBuilder()
.at(getAppWidth() / 2, 0)
.with(newParticleComponent(rain2))
.buildAndAttach();
ExpireCleanComponent is mandatory for one-shot emitters. Without it the entity
persists forever consuming memory. Always pair with burst emitters.
BlendMode.ADD washes out on light backgrounds. Switch to BlendMode.SRC_OVER
for effects on non-black scenes.
No setVelocityX/Y, setGravityX/Y, or setLifetime methods exist. Use
setVelocityFunction, setAccelerationFunction, and setExpireFunction instead.
newRainEmitter takes a width argument — newRainEmitter(int widthPx). Calling it
without an argument compiles but uses a zero-width lane.
setControl runs every frame per particle — keep its lambda fast. Avoid allocations
inside it; use Vec2.set() to mutate rather than creating new objects.
TrailParticleComponent spawns one entity per particle — high emission intervals with
many fast entities push entity counts into the thousands. Profile if FPS drops.
SlowTimeEffect does not affect run() / runOnce() timers, JavaFX transitions, or
UI animations. Only entity Component.onUpdate() sees the scaled tpf.
newExplosionEmitter(radius) — radius controls spread width, not particle count.
Increase setNumParticles() separately for a denser burst.