Jump to content

PIXI Particles and subemitters


Jonny Shaw
 Share

Recommended Posts

Hi all, was just having a play with an effect for an explosion, and thought it would be cool to trial out some fireball style effects with some sort of simulated gravity.

eg. 4 or 5 fireballs, with smoke trails behind..

Had a play but noticed that pixi particles doesn't really offer anything in terms of subemitters, unless I've missed it?  So really been trying to find a workaround.

I'm not so hot when it comes to the maths of any gravity, so have used gsaps 2dphysics plugin to get it working  https://greensock.com/docs/Plugins/Physics2DPlugin...
so each fireball itself is a sprite in a container, then onupdate with that animation, the x&y position of the fireball is sent to update the ownerposition of the trail emitter.

It does work pretty well appearance wise, but performance does feel like it takes a bit of a hit, which Im guessing maybe down to the plugin.  Any ideas on any more "optimal" ways in which something like this could be achieved?
 

{8E4C7319-9F27-4020-8F1C-1EC5218D428A}.png.jpg

Link to comment
Share on other sites

Have managed to get this working, but had to find some workarounds and not sure if it's a bit complex, and could be optimised further...

Involved using a timer and a loop to emit manually, then track the last added fireball particles position (if I tried accessing as soon as it was emit, it would return a blank, because it seems emission rate of 0 even for one particle is not possible), so matched the delay to the emission rate and seems to work ok.

I'll likely add the particles back into particle containers now to improve performance a bit too.

TickerTimer is just a small util class I wrote that adds a callback function to the main app ticker with a delay (so works pretty much like setTimeout, but using the app ticker)

Any further ideas greatly appreciated!

 

import TickerTimer from "../utils/TickerTimer";

class Fireballs extends PIXI.Container{

    constructor(){
        super(...arguments);

        this.balls = [];
        this.trails = [];

        // Atlas...
        this.atlas = PIXI.loader.resources["./assets/fxAtlas.json"].textures;

        this.ballContainer = new PIXI.Container();
        this.trailContainer = new PIXI.Container();

        this.addChild(this.trailContainer);
        this.addChild(this.ballContainer);

        this.emitTimer = 0;
        this.emitRate = 6;

        this.fireballCount = 0;
        this.maxFireballs = 20;

        this.timer = new PIXI.ticker.Ticker();
        this.timer.stop();

        this.fireballs = new PIXI.particles.Emitter(
            this.ballContainer,
            [this.atlas["fireball1.psd"]],
            {
                "alpha": {
                    list: [
                        {value:0, time:0},
                        {value:1, time:0.2},
                        {value:1, time:0.8},
                        {value:0, time:1}
                    ],
                },
                "scale": {
                    list: [
                        {value:0, time:0},
                        {value:0.3, time:0.2},
                        {value:0.4, time:0.8},
                        {value:0.2, time:1}
                    ],
                    "minimumScaleMultiplier": 1
                },
                "color": {
                    "start": "#ffffff",
                    "end": "#ff6105"
                },
                "speed": {
                    "start": 800,
                    "end": 1000,
                    "minimumSpeedMultiplier": 1
                },
                "acceleration": {
                    "x": 0,
                    "y": this.randomRange(1000,2000)
                },
                "maxSpeed": 1000,
                "startRotation": {
                    "min": 160,
                    "max": 380
                },
                "noRotation": false,
                "rotationSpeed": {
                    "min": 500,
                    "max": 2000
                },
                "lifetime": {
                    "min": 1,
                    "max": 1
                },
                "blendMode": "add",
                "frequency": 0.1,
                "emitterLifetime": 0.2,
                "maxParticles": 10,
                "pos": {
                    "x": 0,
                    "y": 0
                },
                "addAtBack": false,
                "spawnType": "point"
            }
        );
        
        this.timer.add(this.emitLoop,this);

        this.timer.start();
    }

    emitLoop(deltaTime){
        this.emitTimer++;
        
        if(this.fireballCount < this.maxFireballs){
            if(this.emitTimer >= this.emitRate){
                this.emitTimer = 0;
                this.emitFireball();
            }
        }

        else {
            this.timer.remove(this.emitLoop, this);
            this.emitTimer = 0;
            this.fireballCount = 0;
        }
    }

    randomRange(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
      }

    emitFireball(){
        this.fireballCount++;
        if(this.fireballCount < this.maxFireballs){
            this.fireballs.autoUpdate = true;
            this.fireballs.playOnce(this.fireballDestroyed.bind(this));
            //this.fireballs.emit = true;
            let delayMe = new TickerTimer(this.timer, 0.2, this.createTrailSmoke.bind(this));
        }
    }
    
    fireballDestroyed(ball){
        this.balls.shift();
        this.trails.shift();
    }

    createTrailSmoke(){
        let fireball = this.ballContainer.children[this.ballContainer.children.length-1];       // Get the last added fireball.
        if(fireball!=null){
            let trailSmoke = this.createTrail(fireball.x, fireball.y,1);

            this.balls.push(fireball);
            this.trails.push(trailSmoke);
            window.Game.ticker.add(this.updateTrailSmoke, this);
        }
    }

    updateTrailSmoke(){
        for(let i = 0; i < this.balls.length; i++){
            this.trails[i].updateOwnerPos(this.balls[i].x, this.balls[i].y+20);
        }
    }

    createTrail(xPos, yPos, lifeSpan){
        let trail = new PIXI.particles.Emitter(
            this.trailContainer,
            [this.atlas["smoke3.psd"]],
            {
                "alpha": {
                    list: [
                        {value:0, time:0},
                        {value:1, time:0.2},
                        {value:0, time:1}
                    ],
                },
                "scale": {
                    list: [
                        {value:0.2, time:0},
                        {value:0.1, time:0.2},
                        {value:0.4, time:1}
                    ],
                    "minimumScaleMultiplier": 1
                },
                "color": {
                    list: [
                        {value:"#ffff5e", time:0},
                        {value:"#ff0000", time:0.2},
                        {value:"#333333", time:0.3},
                        {value:"#000000", time:1}
                    ]
                },
                "speed": {
                    "start": 0,
                    "end": 0,
                    "minimumSpeedMultiplier": 1
                },
                "acceleration": {
                    "x": 0,
                    "y": 100
                },
                "maxSpeed": 0,
                "startRotation": {
                    "min": 0,
                    "max": 360
                },
                "noRotation": false,
                "rotationSpeed": {
                    "min": 0,
                    "max": 800
                },
                "lifetime": {
                    "min": 0.6,
                    "max": 0.8
                },
                "blendMode": "normal",
                "frequency": 0.008,
                "emitterLifetime": lifeSpan,
                "maxParticles": 200,
                "pos": {
                    "x": xPos,
                    "y": yPos
                },
                "addAtBack": false,
                "spawnType": "point"
            }
        );

        trail.autoUpdate = true;
        trail.playOnce();
        
        return trail;
    }
}

export default Fireballs;

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...