Particles and Effects¶
The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.
ParticleEmitter Basics¶
A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.
Creating a Particle Emitter¶
#include <graphics/particles/ParticleEmitter.h>
#include <graphics/particles/ParticleConfig.h>
// Create particle configuration
pixelroot32::graphics::particles::ParticleConfig config;
config.startColor = pixelroot32::graphics::Color::Red;
config.endColor = pixelroot32::graphics::Color::Yellow;
config.lifetime = 1.0f; // 1 second
config.speed = 50.0f;
config.gravity = -100.0f; // Upward (negative = up)
// Create emitter
pixelroot32::graphics::particles::ParticleEmitter* emitter =
new pixelroot32::graphics::particles::ParticleEmitter(100, 100, config);
// Add to scene
addEntity(emitter);
Emitting Particles¶
// Emit a burst of particles
emitter->burst(100, 100, 10); // x, y, particle count
// Particles will automatically update and draw
// No additional code needed!
ParticleConfig¶
ParticleConfig defines how particles behave:
#include <graphics/particles/ParticleConfig.h>
pixelroot32::graphics::particles::ParticleConfig config;
// Colors
config.startColor = pixelroot32::graphics::Color::Red; // Color at spawn
config.endColor = pixelroot32::graphics::Color::Yellow; // Color at death
// Lifetime
config.lifetime = 0.5f; // Duration in seconds
// Velocity
config.speed = 100.0f; // Base speed
config.speedVariation = 20.0f; // Random variation
config.direction = 90.0f; // Direction in degrees (0 = right, 90 = up)
config.directionVariation = 45.0f; // Random direction spread
// Physics
config.gravity = 200.0f; // Gravity force (positive = down)
config.friction = 0.95f; // Friction (0.0 to 1.0, 1.0 = no friction)
// Size
config.startSize = 2; // Size at spawn (pixels)
config.endSize = 1; // Size at death
Complete Config Example¶
pixelroot32::graphics::particles::ParticleConfig fireConfig;
// Fire colors (red to yellow)
fireConfig.startColor = pixelroot32::graphics::Color::Red;
fireConfig.endColor = pixelroot32::graphics::Color::Yellow;
// Short lifetime
fireConfig.lifetime = 0.3f;
// Upward movement with variation
fireConfig.speed = 80.0f;
fireConfig.speedVariation = 30.0f;
fireConfig.direction = 90.0f; // Up
fireConfig.directionVariation = 30.0f; // Spread
// Upward gravity (negative)
fireConfig.gravity = -50.0f;
// Slight friction
fireConfig.friction = 0.98f;
// Size
fireConfig.startSize = 3;
fireConfig.endSize = 1;
Built-in Presets¶
PixelRoot32 includes several particle presets for common effects:
Fire¶
#include <graphics/particles/ParticlePresets.h>
// Create fire emitter
pixelroot32::graphics::particles::ParticleEmitter* fire =
new pixelroot32::graphics::particles::ParticleEmitter(
100, 100,
pixelroot32::graphics::particles::ParticlePresets::Fire()
);
// Emit continuous fire
void update(unsigned long deltaTime) override {
fire->burst(100, 100, 2); // Emit 2 particles per frame
Scene::update(deltaTime);
}
Explosion¶
// Create explosion emitter
pixelroot32::graphics::particles::ParticleEmitter* explosion =
new pixelroot32::graphics::particles::ParticleEmitter(
100, 100,
pixelroot32::graphics::particles::ParticlePresets::Explosion()
);
// Emit explosion burst
explosion->burst(100, 100, 20); // 20 particles at once
Sparks¶
// Create sparks emitter
pixelroot32::graphics::particles::ParticleEmitter* sparks =
new pixelroot32::graphics::particles::ParticleEmitter(
100, 100,
pixelroot32::graphics::particles::ParticlePresets::Sparks()
);
// Emit sparks
sparks->burst(100, 100, 10);
Smoke¶
// Create smoke emitter
pixelroot32::graphics::particles::ParticleEmitter* smoke =
new pixelroot32::graphics::particles::ParticleEmitter(
100, 100,
pixelroot32::graphics::particles::ParticlePresets::Smoke()
);
// Emit smoke
smoke->burst(100, 100, 3);
Dust¶
// Create dust emitter
pixelroot32::graphics::particles::ParticleEmitter* dust =
new pixelroot32::graphics::particles::ParticleEmitter(
100, 100,
pixelroot32::graphics::particles::ParticlePresets::Dust()
);
// Emit dust
dust->burst(100, 100, 5);
Complete Example: Explosion Effect¶
#include <core/Scene.h>
#include <graphics/particles/ParticleEmitter.h>
#include <graphics/particles/ParticlePresets.h>
class ExplosionEffect : public pixelroot32::core::Entity {
private:
pixelroot32::graphics::particles::ParticleEmitter* explosion;
bool active = false;
public:
ExplosionEffect()
: Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {
setRenderLayer(1);
// Create explosion emitter
explosion = new pixelroot32::graphics::particles::ParticleEmitter(
0, 0,
pixelroot32::graphics::particles::ParticlePresets::Explosion()
);
}
void trigger(float x, float y) {
active = true;
this->x = x;
this->y = y;
// Emit explosion burst
explosion->burst(x, y, 25);
}
void update(unsigned long deltaTime) override {
explosion->update(deltaTime);
}
void draw(pixelroot32::graphics::Renderer& renderer) override {
explosion->draw(renderer);
}
};
// Usage in scene
void MyScene::init() override {
explosionEffect = new ExplosionEffect();
addEntity(explosionEffect);
}
void MyScene::update(unsigned long deltaTime) override {
auto& input = engine.getInputManager();
// Trigger explosion on button press
if (input.isButtonPressed(4)) { // Button A
explosionEffect->trigger(player->x, player->y);
}
Scene::update(deltaTime);
}
Continuous Effects¶
For continuous effects like fire or smoke:
class FireEffect : public pixelroot32::core::Entity {
private:
pixelroot32::graphics::particles::ParticleEmitter* fire;
unsigned long emitTimer = 0;
const unsigned long EMIT_INTERVAL_MS = 50; // Emit every 50ms
public:
FireEffect(float x, float y)
: Entity(x, y, 1, 1, pixelroot32::core::EntityType::GENERIC) {
setRenderLayer(1);
fire = new pixelroot32::graphics::particles::ParticleEmitter(
x, y,
pixelroot32::graphics::particles::ParticlePresets::Fire()
);
}
void update(unsigned long deltaTime) override {
// Emit particles continuously
emitTimer += deltaTime;
if (emitTimer >= EMIT_INTERVAL_MS) {
emitTimer -= EMIT_INTERVAL_MS;
fire->burst(x, y, 2); // 2 particles per interval
}
fire->update(deltaTime);
}
void draw(pixelroot32::graphics::Renderer& renderer) override {
fire->draw(renderer);
}
};
Custom Particle Effects¶
Create your own particle effects by customizing ParticleConfig:
Magic Spell Effect¶
pixelroot32::graphics::particles::ParticleConfig magicConfig;
// Magical colors (purple to cyan)
magicConfig.startColor = pixelroot32::graphics::Color::Purple;
magicConfig.endColor = pixelroot32::graphics::Color::Cyan;
// Medium lifetime
magicConfig.lifetime = 0.8f;
// Outward spread
magicConfig.speed = 60.0f;
magicConfig.speedVariation = 20.0f;
magicConfig.direction = 0.0f; // Right
magicConfig.directionVariation = 360.0f; // Full circle
// Slight upward float
magicConfig.gravity = -30.0f;
// Low friction (floaty)
magicConfig.friction = 0.92f;
// Size
magicConfig.startSize = 2;
magicConfig.endSize = 1;
Rain Effect¶
pixelroot32::graphics::particles::ParticleConfig rainConfig;
// Rain color (light blue)
rainConfig.startColor = pixelroot32::graphics::Color::LightBlue;
rainConfig.endColor = pixelroot32::graphics::Color::LightBlue;
// Long lifetime
rainConfig.lifetime = 2.0f;
// Downward movement
rainConfig.speed = 150.0f;
rainConfig.speedVariation = 20.0f;
rainConfig.direction = 270.0f; // Down
rainConfig.directionVariation = 5.0f; // Slight angle variation
// Downward gravity
rainConfig.gravity = 200.0f;
// No friction
rainConfig.friction = 1.0f;
// Small size
rainConfig.startSize = 1;
rainConfig.endSize = 1;
Best Practices¶
Performance¶
- Limit particle count: Each emitter has MAX_PARTICLES_PER_EMITTER (50)
- Reuse emitters: Don't create new emitters every frame
- Disable when not visible: Set
isVisible = falsewhen off-screen - Limit active emitters: Too many emitters can impact performance
Visual Design¶
- Match game style: Particle effects should fit your game's aesthetic
- Use appropriate colors: Match particle colors to game palette
- Test on hardware: ESP32 may render particles differently
- Keep it simple: Simple effects often look better than complex ones
Timing¶
- Burst timing: Space out bursts for better visual effect
- Continuous effects: Use timers to control emission rate
- Lifetime: Adjust lifetime to match effect duration
- Cleanup: Particles automatically clean up when lifetime expires
Common Patterns¶
One-Shot Effect¶
class OneShotEffect : public pixelroot32::core::Entity {
private:
pixelroot32::graphics::particles::ParticleEmitter* emitter;
bool hasEmitted = false;
public:
void trigger(float x, float y) {
if (!hasEmitted) {
emitter->burst(x, y, 20);
hasEmitted = true;
}
}
void reset() {
hasEmitted = false;
}
};
Attached Effect¶
class AttachedParticleEffect : public pixelroot32::core::Entity {
private:
pixelroot32::graphics::particles::ParticleEmitter* emitter;
pixelroot32::core::Actor* target;
public:
void update(unsigned long deltaTime) override {
// Update emitter position to follow target
emitter->x = target->x;
emitter->y = target->y;
// Emit particles
emitter->burst(target->x, target->y, 1);
emitter->update(deltaTime);
}
};
Troubleshooting¶
Particles Not Appearing¶
- Verify emitter is added to scene
- Check particle config is valid
- Ensure
burst()is being called - Verify emitter position is on-screen
Performance Issues¶
- Reduce particle count per burst
- Limit number of active emitters
- Use simpler particle configs
- Disable emitters when not visible
Particles Not Moving¶
- Check gravity value (positive = down, negative = up)
- Verify speed is not 0
- Check friction isn't too high (1.0 = no movement)
- Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)
Next Steps¶
Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation
See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering