@pixi/particle-emitter

repository·master·Indexed 21 days ago

https://github.com/pixijs-userland/particle-emitter

A particle system library for PixiJS (version 5.0.10) that enables the creation of complex effects like explosions, rain, and flames using a behavior-based configuration system. It features a flexible Emitter class, support for animated textures via RandomAnimatedTextureBehavior and SingleAnimatedTextureBehavior, and an extensible IEmitterBehavior interface for custom particle logic. Includes tools for migrating v4 configurations to v5 using upgradeConfig().

Tokens
11.7K
Snippets
34
Records
53
Agent score
74%

What's inside @pixi/particle-emitter

  1. Migrating from v4 to v5

    master

    If you are upgrading from version 4 to version 5, be aware of the following breaking changes:

    • Package Name: The project has been renamed from pixi-particles to @pixi/particle-emitter.
    • Configuration: The Emitter configuration format has changed significantly. Use upgradeConfig() to automate conversion.
    • Removed Particle Types: PathParticle and AnimatedParticle no longer exist; use the new behaviors instead.
    • PixiJS Compatibility: Support for PixiJS v4 has been dropped. It is recommended to use PixiJS v6. While v5 might work, TypeScript definitions will not be compatible.
    • Module Format: The library now outputs ES6 code. If you require ES5, you must transpile it in your build process.
  2. Define behavior entries in EmitterConfigV3

    master

    In EmitterConfigV3, all particle properties are defined via BehaviorEntry objects within the behaviors array. A BehaviorEntry consists of:

    • type: A string identifying the behavior (e.g., 'alpha', 'moveSpeed', 'scale', 'color', 'rotation', 'textureSingle').
    • config: An object containing the parameters for that specific behavior.

    This modular approach allows for custom behaviors to be registered via Emitter.registerBehavior and used in the configuration.

  3. Configure animated textures for particles

    master

    To create animated particles, use either RandomAnimatedTextureBehavior or SingleAnimatedTextureBehavior. Both behaviors require an AnimatedParticleArt configuration object to define the animation sequence, framerate, and looping behavior.

    AnimatedParticleArt Configuration

    KeyTypeDescription
    framerate-1 or numberFrames per second. Use -1 to tie the animation duration exactly to the particle's lifetime.
    loopboolean (optional)Whether the animation should loop. Defaults to false.
    textures(string|Texture|{texture: string|Texture; count: number})[]An array of textures or frame descriptions. You can use strings (which are converted via ParticleUtils.GetTextureFromString), direct Texture objects, or objects to repeat a texture for a specific number of frames.

    Example of repeating textures:

    // A texture repeated for 5 frames, followed by a second texture for one frame
    [{texture: 'myFirstTex', count: 5}, 'mySecondTex']
    // Example of AnimatedParticleArt configuration
    {
        framerate: 25,
        loop: true,
        textures: ['frame1', 'frame2', 'frame3']
    }
  4. Use different particle spawn shapes

    master

    The @pixi/particle-emitter package provides several shapes that define the area or path where particles are spawned. You can use these shapes to control the initial distribution of particles in your emitter.

    Available shapes include:

    • Rectangle: Spawns particles within a rectangular area.
    • Torus: Spawns particles on the surface of a torus (doughnut shape).
    • PolygonalChain: Spawns particles along a path defined by a series of connected points.
  5. Configure PropertyList interpolation behavior

    master

    The PropertyList class determines how values change over time based on the configuration of the PropertyNode objects passed to reset().

    Interpolation Logic Selection

    When reset(first: PropertyNode<V>) is called, the interpolate method is assigned based on these rules:

    1. Simple Interpolation: If first.next exists and first.next.time >= 1, it uses a simple linear interpolation between the first and second nodes.
    2. Stepped Interpolation: If first.isStepped is true, the value remains constant until the next node's time is reached.
    3. Complex Interpolation: Otherwise, it performs complex interpolation, traversing multiple segments to find the correct time window for the current lerp value.

    Color Handling

    If the PropertyList was instantiated with isColor = true, the interpolate method will return a number representing the combined RGB components (hex value) instead of the raw type V.

  6. Control behavior execution order with BehaviorOrder

    master

    The order property on an IEmitterBehavior determines when its logic is applied relative to other behaviors and the emitter's own transformations. Use the BehaviorOrder enum to set standard priorities:

    • BehaviorOrder.Spawn (0): Applied during initial placement/rotation. This is handled specially and occurs before the Emitter's own transformation (rotation/position) is applied.
    • BehaviorOrder.Normal (2): Standard priority for general particle updates.
    • BehaviorOrder.Late (5): Delayed priority, used for behaviors that need to read values updated by other behaviors to function correctly.

    Note: Behaviors with the same order value are processed in an undefined order.

    import { BehaviorOrder } from '@pixi/particle-emitter';
    
    // Example usage in a behavior implementation
    class MyBehavior implements IEmitterBehavior {
        order = BehaviorOrder.Spawn;
        // ...
    }
  7. Create and update a new Emitter

    master

    To use the particle system, instantiate a new Emitter by passing a PIXI.Container and a configuration object. You must manually call emitter.update(deltaTime) in your animation loop, where deltaTime is the elapsed time in seconds since the last update. To start the emission process, set emitter.emit = true.

    // Create a new emitter
    // note: if importing library like "import * as particles from '@pixi/particle-emitter'"
    // or "const particles = require('@pixi/particle-emitter)", the PIXI namespace will
    // not be modified, and may not exist - use "new particles.Emitter()", or whatever
    // your imported namespace is
    var emitter = new PIXI.particles.Emitter(
    
        // The PIXI.Container to put the emitter in
        // if using blend modes, it's important to put this
        // on top of a bitmap, and not use the root stage Container
        container,
        // Emitter configuration, edit this to change the look
        // of the emitter
        {
            lifetime: {
                min: 0.5,
                max: 0.5
            },
            frequency: 0.008,
            spawnChance: 1,
            particlesPerWave: 1,
            emitterLifetime: 0.31,
            maxParticles: 1000,
            pos: {
                x: 0,
                y: 0
            },
            addAtBack: false,
            behaviors: [
                {
                    type: 'alpha',
                    config: {
                        alpha: {
                            list: [
                                { value: 0.8, time: 0 },
                                { value: 0.1, time: 1 }
                            ],
                        },
                    }
                },
                {
                    type: 'scale',
                    config: {
                        scale: {
                            list: [
                                { value: 1, time: 0 },
                                { value: 0.3, time: 1 }
                            ],
                        },
                    }
                },
                {
                    type: 'color',
                    config: {
                        color: {
                            list: [
                                { value: "fb1010", time: 0 },
                                { value: "f5b830", time: 1 }
                            ],
                        },
                    }
                },
                {
                    type: 'moveSpeed',
                    config: {
                        speed: {
                            list: [
                                { value: 200, time: 0 },
                                { value: 100, time: 1 }
                            ],
                            isStepped: false
                        },
                    }
                },
                {
                    type: 'rotationStatic',
                    config: {
                        min: 0,
                        max: 360
                    }
                },
                {
                    type: 'spawnShape',
                    config: {
                        type: 'torus',
                        data: {
                            x: 0,
                            y: 0,
                            radius: 10
                        }
                    }
                },
                {
                    type: 'textureSingle',
                    config: {
                        texture: PIXI.Texture.from('image.jpg')
                    }
                }
            ],
        }
    );
    
    // Calculate the current time
    var elapsed = Date.now();
    
    // Update function every frame
    var update = function(){
    
    	// Update the next frame
    	requestAnimationFrame(update);
    
    	var now = Date.now();
    
    	// The emitter requires the elapsed
    	// number of seconds since the last update
    	emitter.update((now - elapsed) * 0.001);
    	elapsed = now;
    };
    
    // Start emitting
    emitter.emit = true;
    
    // Start the update
    update();
  8. Convert old v4 configurations using upgradeConfig()

    master
    The configuration format for Emitter changed drastically in v5. If you are using configurations generated by the older interactive particle editor or from a v4 project, you must use the upgradeConfig() function to convert them to the new format.
  9. Configure an Emitter using EmitterConfigV3

    master

    The EmitterConfigV3 interface is the current standard for initializing an Emitter instance. Unlike older versions that used top-level properties for properties like alpha or speed, v3 uses a behaviors array to define particle characteristics.

    Key configuration properties include:

    • lifetime: A RandNumber defining the particle lifetime.
    • frequency: How often to spawn particles (in seconds).
    • pos: The { x, y } position to spawn particles from.
    • maxParticles: Maximum number of concurrent particles.
    • behaviors: An array of BehaviorEntry objects defining particle movement, color, scale, etc.

    Each behavior in the array requires a type (string) and a config (object) specific to that behavior.

    const config: EmitterConfigV3 = {
        lifetime: { min: 1, max: 2 },
        frequency: 0.5,
        pos: { x: 100, y: 100 },
        behaviors: [
            { type: 'alphaStatic', config: { alpha: 0.5 } },
            { type: 'moveSpeedStatic', config: { min: 50, max: 100 } }
        ]
    };
  10. Configure particle property value lists

    master

    When defining particle properties that change over time (like color or scale), you can use a ValueList<T> to define a sequence of values.

    Each value in the list is associated with a time (a percentage of the particle's lifespan from 0 to 1). You can choose between two behaviors:

    • Interpolated (Default): The property smoothly transitions between the values in the list.
    • Stepped: By setting isStepped: true, the property will jump to the next value and hold it until the next time step is reached, rather than transitioning smoothly.

    You can also apply an ease function or EaseSegment[] to the entire list to control the progression speed of the transitions.

    // Example of an interpolated color list
    const colorList: ValueList<string> = {
      list: [
        { value: '#ff0000', time: 0 },
        { value: '#0000ff', time: 1 }
      ],
      isStepped: false
    };
    
    // Example of a stepped numeric list
    const scaleList: ValueList<number> = {
      list: [
        { value: 1, time: 0 },
        { value: 2, time: 0.5 },
        { value: 0, time: 1 }
      ],
      isStepped: true
    };