Guides VFX & Particles Particles Script Particle Systems

VFX & Particles Particles 2 min read Updated Aug 2026

Script Particle Systems

Use PHP to control when particle effects play, how many particles are emitted, which profile is active, and which simple runtime values change during gameplay.

Author detailed module data in the editor or in .particle.json profiles. Script the effect's timing and game logic.

Get The Component

use Lenga\Engine\Core\Behaviour;
use Lenga\Engine\Core\ParticleSystem;

final class TorchEffect extends Behaviour
{
    private ?ParticleSystem $smoke = null;

    public function start(): void
    {
        $this->smoke = $this->getComponent(ParticleSystem::class);
    }
}

ParticleSystem is a component, so it is retrieved the same way as other scene components.

Playback

Use play() for continuous effects.

$particles->play();

Use pause() when you want to freeze simulation without clearing living particles.

$particles->pause();

Use stop() to stop emission. Pass true to clear particles immediately.

$particles->stop();
$particles->stop(true);

Use clear() to remove living particles without changing authored settings.

$particles->clear();

Bursts

Use emit() for immediate bursts.

$particles->emit(24);

For a one-shot effect, a common pattern is:

$particles->stop(true);
$particles->emit(32);
$particles->play();

Use restart() when the whole system should start over.

$particles->restart();
$particles->restart(keepSeed: true);

Keeping the seed is useful when you want the same burst pattern every time.

Manual Simulation

simulate() advances the particle system by a number of seconds.

$particles->simulate(0.5);
$particles->simulate(1.0, restart: true);

Use this for prewarming, deterministic setup, or custom preview behavior. For normal gameplay, let the engine update the system.

Profiles And Textures

Load a profile:

$particles->loadProfile('Assets/Particles/LandingDust.particle.json');

Load a texture:

$particles->loadTexture('Assets/Sprites/Effects/dust.png');

Profile swaps are usually better than setting many module values from PHP. A spell can switch from idle motes to a burst profile without hard-coding all of the shape, color, size, and renderer settings in gameplay code.

Simple Runtime Tuning

The PHP API exposes common values:

$particles->dimension = '3D';
$particles->emissionRate = 20.0;
$particles->lifetime = 0.75;
$particles->startSpeed = 8.0;
$particles->startSize = 0.3;
$particles->endSize = 0.0;
$particles->shapeType = 'Cone3D';

Use these for simple runtime adaptation. For example, increase emission rate when an engine overheats, or switch shape type for a special state.

Avoid using PHP as a full authoring layer for curves and gradients. Author those details in profiles through the editor workflow.

State Inspection

getState() returns diagnostic information.

$state = $particles->getState();
Debug::log('Alive particles: ' . $state['aliveParticleCount']);

Useful keys include:

  • dimension
  • isPlaying
  • aliveParticleCount
  • maxParticles
  • emissionRate
  • lifetime
  • startSpeed
  • startSize
  • texturePath
  • profilePath
  • shapeType
  • sortingLayer
  • orderInLayer

Use getState() for debugging, editor tools, or runtime UI. Prefer typed properties and methods for normal gameplay code.

Example: Landing Dust

use Lenga\Engine\Core\Behaviour;
use Lenga\Engine\Core\ParticleSystem;

final class LandingDust extends Behaviour
{
    private ?ParticleSystem $dust = null;

    public function start(): void
    {
        $this->dust = $this->getComponent(ParticleSystem::class);
        $this->dust?->loadProfile('Assets/Particles/LandingDust.particle.json');
        $this->dust?->stop(true);
    }

    public function onLanded(): void
    {
        $this->dust?->restart(true);
        $this->dust?->emit(18);
    }
}

This keeps authored VFX in the profile and gameplay timing in the script.