Jonny Shaw Posted January 28, 2019 Share Posted January 28, 2019 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? Quote Link to comment Share on other sites More sharing options...
Jonny Shaw Posted January 28, 2019 Author Share Posted January 28, 2019 Aha, silly me see gravity can be simulated with the acceleration, so will try that The only other issue I can see is accessing the fireball particles x,y position but hopefully children on the particle container, should give an option there Quote Link to comment Share on other sites More sharing options...
Jonny Shaw Posted January 29, 2019 Author Share Posted January 29, 2019 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; Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.