2D Particle System¶
Emitter API Method Reference¶
Core Emitter Methods¶
| Method Signature | Return Type | Description |
|---|---|---|
data() |
EmitterAttributes |
Accesses the configurable particle and spawn attributes object. |
activate() / deactivate() |
void |
Starts or stops particle emission and lifecycle processing. |
setPaused(boolean) / togglePaused() |
void |
Suspends/resumes particle updates and spawning without deallocating state. |
delete() |
void |
Deactivates and removes the emitter from the active environment. |
getParticles() |
List<Particle> |
Returns the active collection of living particles managed by this emitter. |
onFinished(EmitterFinishedListener listener) |
void |
Registers a callback invoked when a finite emitter completes and expires. |
Configurable Attributes (emitter.data())¶
| Method Signature | Return Type | Description |
|---|---|---|
setParticleType(ParticleType type) |
void |
Sets the particle primitive (RECTANGLE, ELLIPSE, TRIANGLE, DIAMOND, LINE, TEXT, SPRITE). |
setParticleWidth(RangeAttribute<Float>) |
void |
Sets particle width range in pixels (getParticleWidth().setMin() / setMax()). |
setParticleHeight(RangeAttribute<Float>) |
void |
Sets particle height range in pixels (getParticleHeight().setMin() / setMax()). |
getParticleTTL() |
RangeAttribute<Long> |
Configurable lifetime bounds (in milliseconds) per spawned particle. |
setMaxParticles(int count) |
void |
Limits maximum concurrent alive particles spawned by this emitter. |
setSpawnRate(int delayMs) |
void |
Sets the interval delay in milliseconds between successive spawn ticks. |
setSpawnAmount(int count) |
void |
Sets the number of particles spawned during each spawn tick. |
setEmitterDuration(int durationMs) |
void |
Emitter duration in milliseconds (0 for indefinite / continuous). |
setColors(Color... colors) |
void |
Configures the color palette from which particles randomly draw colors. |
setFade(boolean fade) |
void |
Linearly fades particle opacity to zero over its lifetime. |
setSpritesheet(Spritesheet / String) |
void |
Binds a spritesheet texture for SPRITE particle types. |
getVelocityX() / getVelocityY() |
RangeAttribute<Float> |
Initial horizontal and vertical velocities. |
getAccelerationX() / getAccelerationY() |
RangeAttribute<Float> |
Per-tick acceleration applied to velocity (e.g. gravity, wind). |
The LITIENGINE particle system allows you to create dynamic visual effects by emitting and animating large numbers of small sprites or shapes. Use it for fire, smoke, explosions, magic spells, and environmental effects.
How Particles Work¶
- An Emitter spawns particles at a defined rate
- Each Particle has properties like position, velocity, size, color, and lifetime
- Particles are updated every tick and rendered to the screen
- When a particle's lifetime expires, it is removed
Creating an Emitter¶
Using utiLITI¶
- Add an Emitter entity to your map
- Configure emitter properties in the Properties panel
- Set particle appearance, behavior, and timing
Using Code¶
import de.gurkenlabs.litiengine.attributes.RangeAttribute;
import de.gurkenlabs.litiengine.graphics.emitters.Emitter;
import de.gurkenlabs.litiengine.graphics.emitters.particles.ParticleType;
import de.gurkenlabs.litiengine.resources.Resources;
public class FireEmitter extends Emitter {
public FireEmitter(double x, double y) {
super(x, y);
// Configure emitter
this.data().setSpawnRate(30); // Milliseconds between spawns
this.data().setEmitterDuration(0); // 0 = infinite
this.data().setMaxParticles(100);
// Configure particles
this.data().setParticleWidth(new RangeAttribute<>(12f, 16f));
this.data().setParticleHeight(new RangeAttribute<>(12f, 16f));
this.data().getParticleTTL().setMin(500L); // Min lifetime (ms)
this.data().getParticleTTL().setMax(1000L); // Max lifetime (ms)
// Particle appearance
this.data().setParticleType(ParticleType.SPRITE);
this.data().setSpritesheet(Resources.spritesheets().get("fire-particle"));
// Start emitting
this.activate();
}
}
Particle Properties¶
Lifetime¶
// Particle lives between 500-1000ms
emitter.data().getParticleTTL().setMin(500L);
emitter.data().getParticleTTL().setMax(1000L);
Velocity and Movement¶
// Upward movement with random variance
emitter.data().getVelocityX().setMin(-20f);
emitter.data().getVelocityX().setMax(20f);
emitter.data().getVelocityY().setMin(-50f);
emitter.data().getVelocityY().setMax(-30f);
// Acceleration (gravity, wind)
emitter.data().getAccelerationX().setMin(-5f);
emitter.data().getAccelerationX().setMax(5f);
emitter.data().getAccelerationY().setMin(-10f);
emitter.data().getAccelerationY().setMax(-5f);
Size and Scale¶
// Particle size range (min/max in pixels)
emitter.data().setParticleWidth(new RangeAttribute<>(4f, 8f));
emitter.data().setParticleHeight(new RangeAttribute<>(4f, 8f));
// Or adjust existing range bounds directly:
emitter.data().getParticleWidth().setMin(4f);
emitter.data().getParticleWidth().setMax(8f);
Color and Opacity¶
// Base particle colors (emitter randomly samples from configured palette)
emitter.data().setColors(Color.ORANGE, Color.YELLOW, Color.RED);
// Enable linear opacity fade-out towards zero over particle lifespan
emitter.data().setFade(true);
Particle Types¶
Sprite Particles¶
// Use a spritesheet for particle visuals
Spritesheet sheet = Resources.spritesheets().get("sparkle");
emitter.data().setSpritesheet(sheet);
emitter.data().setParticleType(ParticleType.SPRITE);
Shape Particles¶
// Render particles as shapes
emitter.data().setParticleType(ParticleType.RECTANGLE);
emitter.data().setParticleType(ParticleType.ELLIPSE);
emitter.data().setParticleType(ParticleType.TRIANGLE);
emitter.data().setParticleType(ParticleType.DIAMOND);
Text Particles¶
// Render particles as text drawn from configured string options
emitter.data().setParticleType(ParticleType.TEXT);
emitter.data().setTexts(List.of("CRIT!", "150", "MISS"));
Emitter Behavior¶
One-Shot Effect¶
// Emit burst of particles once
emitter.data().setSpawnAmount(50);
emitter.data().setEmitterDuration(100);
Continuous Effect¶
// Continuous emission
emitter.data().setSpawnRate(20); // Milliseconds between spawns
emitter.data().setEmitterDuration(0); // Infinite
Adding Emitters to Environment¶
Custom Particles¶
Create custom particle rendering and behavior by extending Particle and implementing its render and update methods:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import de.gurkenlabs.litiengine.attributes.RangeAttribute;
import de.gurkenlabs.litiengine.graphics.emitters.Emitter;
import de.gurkenlabs.litiengine.graphics.emitters.particles.Particle;
public class SparkParticle extends Particle {
public SparkParticle(float width, float height) {
super(width, height);
this.setColor(Color.YELLOW);
}
@Override
public void update(Point2D emitterOrigin, float updateRatio) {
super.update(emitterOrigin, updateRatio);
// Custom particle logic on update ticks
}
@Override
public void render(Graphics2D g, Point2D emitterOrigin) {
Point2D loc = this.getRenderLocation(emitterOrigin);
g.setColor(this.getColor());
g.fillRect((int) loc.getX(), (int) loc.getY(), (int) this.getWidth(), (int) this.getHeight());
}
}
// Override createNewParticle() on a custom Emitter to spawn your custom particle:
public class SparkEmitter extends Emitter {
public SparkEmitter(double x, double y) {
super(x, y);
this.data().setParticleWidth(new RangeAttribute<>(4f, 6f));
this.data().setParticleHeight(new RangeAttribute<>(4f, 6f));
}
@Override
protected Particle createNewParticle() {
float width = this.data().getParticleWidth().getRandomNumber().floatValue();
float height = this.data().getParticleHeight().getRandomNumber().floatValue();
return new SparkParticle(width, height).init(this.data());
}
}
Particle Recipes Cookbook¶
Below are complete, copy-paste ready emitter classes for common 2D visual effects:
1. Torch & Campfire Flame¶
import java.awt.Color;
import de.gurkenlabs.litiengine.attributes.RangeAttribute;
import de.gurkenlabs.litiengine.graphics.emitters.Emitter;
import de.gurkenlabs.litiengine.graphics.emitters.particles.ParticleType;
public class CampfireEmitter extends Emitter {
public CampfireEmitter(double x, double y) {
super(x, y);
this.setWidth(16);
this.setHeight(16);
this.data().setParticleType(ParticleType.ELLIPSE);
this.data().setParticleWidth(new RangeAttribute<>(4f, 8f));
this.data().setParticleHeight(new RangeAttribute<>(4f, 8f));
this.data().setSpawnRate(25);
this.data().getParticleTTL().setMin(400L);
this.data().getParticleTTL().setMax(800L);
// Float upwards with slight horizontal jitter
this.data().getVelocityX().setMin(-10f);
this.data().getVelocityX().setMax(10f);
this.data().getVelocityY().setMin(-45f);
this.data().getVelocityY().setMax(-20f);
// Warm embers that fade out over time
this.data().setColors(new Color(255, 200, 50, 220), new Color(255, 100, 30, 220));
this.data().setFade(true);
}
}
2. Explosion / Impact Burst¶
import java.awt.Color;
import de.gurkenlabs.litiengine.attributes.RangeAttribute;
import de.gurkenlabs.litiengine.graphics.emitters.Emitter;
import de.gurkenlabs.litiengine.graphics.emitters.particles.ParticleType;
public class ExplosionEmitter extends Emitter {
public ExplosionEmitter(double x, double y) {
super(x, y);
this.setWidth(10);
this.setHeight(10);
this.data().setParticleType(ParticleType.RECTANGLE);
this.data().setParticleWidth(new RangeAttribute<>(3f, 6f));
this.data().setParticleHeight(new RangeAttribute<>(3f, 6f));
this.data().setSpawnAmount(60);
this.data().setEmitterDuration(150);
this.data().getParticleTTL().setMin(200L);
this.data().getParticleTTL().setMax(500L);
// Radial explosive velocity in all directions
this.data().getVelocityX().setMin(-120f);
this.data().getVelocityX().setMax(120f);
this.data().getVelocityY().setMin(-120f);
this.data().getVelocityY().setMax(120f);
this.data().setColors(new Color(255, 120, 0, 255), new Color(255, 200, 50, 255));
this.data().setFade(true);
}
}
3. Rain Weather Emitter¶
import java.awt.Color;
import de.gurkenlabs.litiengine.Game;
import de.gurkenlabs.litiengine.attributes.RangeAttribute;
import de.gurkenlabs.litiengine.graphics.emitters.Emitter;
import de.gurkenlabs.litiengine.graphics.emitters.particles.ParticleType;
public class RainEmitter extends Emitter {
public RainEmitter() {
super(0, 0);
// Span across the map or active camera viewport
this.setWidth(Game.world().environment().getMap().getSizeInPixels().getWidth());
this.setHeight(10);
this.data().setParticleType(ParticleType.RECTANGLE);
this.data().setParticleWidth(new RangeAttribute<>(1f, 1f));
this.data().setParticleHeight(new RangeAttribute<>(6f, 10f));
this.data().setSpawnRate(80);
// Fall downwards with slight wind angle
this.data().getVelocityX().setMin(-15f);
this.data().getVelocityX().setMax(-5f);
this.data().getVelocityY().setMin(180f);
this.data().getVelocityY().setMax(240f);
this.data().setColors(new Color(150, 190, 255, 160));
}
}
Performance Tips¶
- Limit max particles: Set reasonable
maxParticlesvalues - Use sprite sheets: More efficient than shapes for complex particles
- Recycle emitters: Reuse emitters instead of creating new ones
- Suspend when off-screen: Emitters outside camera view should be suspended
See Also¶
- Dynamic Lighting - Lighting effects
- Render Engine - Rendering system