Preparing new frames getter.

This commit is contained in:
Richard Davey 2017-10-18 15:18:42 +01:00
parent f40459553d
commit c65c247393
3 changed files with 258 additions and 196 deletions

View file

@ -6,15 +6,15 @@ var Particle = new Class({
initialize: initialize:
function Particle (x, y, frame) function Particle ()
{ {
// Phaser.Texture.Frame // Phaser.Texture.Frame
this.frame = frame; this.frame = null;
this.index = 0; this.index = 0;
this.x = x; this.x = 0;
this.y = y; this.y = 0;
// Add Acceleration (and Bounce?) // Add Acceleration (and Bounce?)
@ -66,14 +66,14 @@ var Particle = new Class({
*/ */
}, },
reset: function (x, y, frame) reset: function ()
{ {
this.index = 0; this.index = 0;
this.frame = frame; // this.frame = frame;
this.x = x; this.x = 0;
this.y = y; this.y = 0;
this.velocityX = 0; this.velocityX = 0;
this.velocityY = 0; this.velocityY = 0;
@ -148,20 +148,30 @@ var Particle = new Class({
emit: function (emitter) emit: function (emitter)
{ {
// var rad = DegToRad(emitter.angle.getRandom()); this.frame = emitter.getFrame();
// this.velocityX = Math.cos(rad) * emitter.velocity.getRandomX(); if (emitter.zone)
// this.velocityY = Math.sin(rad) * emitter.velocity.getRandomY(); {
emitter.zone.getRandomPoint(this);
}
this.velocityX = emitter.velocity.getRandomX(); this.x += emitter.x;
this.velocityY = emitter.velocity.getRandomY(); this.y += emitter.y;
var sx = emitter.speed.getRandomX();
var sy = emitter.speed.getRandomY();
if (emitter.radial)
{
var rad = DegToRad(emitter.angle.getRandom()); var rad = DegToRad(emitter.angle.getRandom());
if (rad !== 0) this.velocityX = Math.cos(rad) * Math.abs(sx);
this.velocityY = Math.sin(rad) * Math.abs(sy);
}
else
{ {
this.velocityX *= Math.cos(rad); this.velocityX = sx;
this.velocityY *= Math.sin(rad); this.velocityY = sy;
} }
this.life = emitter.lifespan.getRandom(); this.life = emitter.lifespan.getRandom();
@ -176,8 +186,6 @@ var Particle = new Class({
// emitter.alpha.copyToMinMax(this.data.alpha); // emitter.alpha.copyToMinMax(this.data.alpha);
// this.scaleX = emitter.scale.xMin; // this.scaleX = emitter.scale.xMin;
// this.scaleY = emitter.scale.yMin; // this.scaleY = emitter.scale.yMin;

View file

@ -1,14 +1,12 @@
var Between = require('../../math/Between');
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
var Components = require('../components'); var Components = require('../components');
var DegToRad = require('../../math/DegToRad');
var Easing = require('../../math/easing'); var Easing = require('../../math/easing');
var GameObject = require('../GameObject');
var GetEaseFunction = require('../../tweens/builder/GetEaseFunction'); var GetEaseFunction = require('../../tweens/builder/GetEaseFunction');
var MinMax2 = require('../../math/MinMax2'); var MinMax2 = require('../../math/MinMax2');
var MinMax4 = require('../../math/MinMax4'); var MinMax4 = require('../../math/MinMax4');
var Particle = require('./Particle'); var Particle = require('./Particle');
var StableSort = require('../../utils/array/StableSort'); var StableSort = require('../../utils/array/StableSort');
var GetRandomElement = require('../../utils/array/GetRandomElement');
var ParticleEmitter = new Class({ var ParticleEmitter = new Class({
@ -29,19 +27,23 @@ var ParticleEmitter = new Class({
this.key = ''; this.key = '';
this.frame = manager.frame;
this.particleClass = Particle; this.particleClass = Particle;
this.frames = [];
this.dead = []; this.dead = [];
this.alive = []; this.alive = [];
this.x = 0; this.x = 0;
this.y = 0; this.y = 0;
// Implement ease into the MinMax component? // How can the emitter pick from a random frame OR a fixed frame?
this.velocity = new MinMax4(); // A radial emitter will emit particles in all directions between angle min and max
// A point emitter will emit particles only in the direction set by the speed values
this.radial = true;
this.speed = new MinMax4();
this.scale = new MinMax4(1); this.scale = new MinMax4(1);
@ -49,7 +51,7 @@ var ParticleEmitter = new Class({
this.alpha = new MinMax2(1); this.alpha = new MinMax2(1);
this.angle = new MinMax2(); this.angle = new MinMax2(0, 360);
this.particleAngle = new MinMax2(); this.particleAngle = new MinMax2();
@ -59,50 +61,55 @@ var ParticleEmitter = new Class({
this.deathCallback = null; this.deathCallback = null;
this.deathCallbackScope = null; this.deathCallbackScope = null;
// Set to hard limit the amount of particle objects this emitter is allowed to create
this.maxParticles = 0;
// How many particles are emitted each time the emitter updates
this.emitCount = 1; this.emitCount = 1;
/** // How often a particle is emitted in ms (if emitter is a constant / flow emitter)
* @property {number} frequency - How often a particle is emitted in ms (if emitter is started with Explode === false). // If emitter is an explosion emitter this value will be -1.
*/ // Anything > -1 sets this to be a flow emitter
this.frequency = 100; this.frequency = 0;
/** // Controls if the emitter is currently emitting particles. Already alive particles will continue to update until they expire.
* @property {boolean} on - Determines whether the emitter is currently emitting particles. It is totally safe to directly toggle this. this.on = true;
* @default
*/
this.on = false;
// this.enabled = true;
/** // Newly emitted particles are added to the top of the particle list, i.e. rendered above those already alive. Set to false to send them to the back.
* @property {boolean} particleBringToTop - If this is `true` then when the Particle is emitted it will be bought to the top of the Emitters display list. this.particleBringToTop = true;
* @default
*/
this.particleBringToTop = false;
/**
* @property {boolean} particleSendToBack - If this is `true` then when the Particle is emitted it will be sent to the back of the Emitters display list.
* @default
*/
this.particleSendToBack = false;
this.timeScale = 1; this.timeScale = 1;
// this.delay = 0; this._counter = 0;
// this.delayCounter = 0;
// this.allowCreation = true;
this.emitShape = null; // Optional Particle emission zone - must be an object that supports a `getRandomPoint` function, such as a Rectangle, Circle, Path, etc.
this.zone = null;
this.easingFunctionAlpha = Easing.Linear; // this.easingFunctionAlpha = Easing.Linear;
this.easingFunctionScale = Easing.Linear; // this.easingFunctionScale = Easing.Linear;
this.easingFunctionRotation = Easing.Linear; // this.easingFunctionRotation = Easing.Linear;
this.active = true; this.active = true;
}, },
getFrame: function ()
{
return GetRandomElement(this.frames);
},
// Either a single frame (numeric / string based), or an array of frames to randomly pick from
setFrame: function (frame) setFrame: function (frame)
{ {
this.frame = this.manager.texture.get(frame); this.manager.setEmitterFrames(frame, this);
return this;
},
setRadial: function (value)
{
if (value === undefined) { value = true; }
this.radial = value;
return this; return this;
}, },
@ -151,9 +158,9 @@ var ParticleEmitter = new Class({
// Particle Emission // Particle Emission
setVelocity: function (xMin, xMax, yMin, yMax) setSpeed: function (xMin, xMax, yMin, yMax)
{ {
this.velocity.set(xMin, xMax, yMin, yMax); this.speed.set(xMin, xMax, yMin, yMax);
return this; return this;
}, },
@ -200,17 +207,26 @@ var ParticleEmitter = new Class({
return this; return this;
}, },
setDelay: function (delay) setFrequency: function (frequency)
{ {
this.delay = delay; this.frequency = frequency;
this.delayCounter = delay / 1000; this._counter = 0;
return this; return this;
}, },
setShape: function (shape) // The zone must have a function called `getRandomPoint` that takes an object and sets
// its x and y properties accordingly then returns that object
setZone: function (zone)
{ {
this.emitShape = shape; if (zone === undefined)
{
this.zone = null;
}
else if (typeof zone.getRandomPoint === 'function')
{
this.zone = zone;
}
return this; return this;
}, },
@ -221,9 +237,9 @@ var ParticleEmitter = new Class({
{ {
var dead = this.dead; var dead = this.dead;
for (var count = 0; count < particleCount; ++count) for (var i = 0; i < particleCount; i++)
{ {
dead.push(new this.particleClass(this.x, this.y, this.frame)); dead.push(new this.particleClass());
} }
return this; return this;
@ -244,6 +260,11 @@ var ParticleEmitter = new Class({
return this.getAliveParticleCount() + this.getDeadParticleCount(); return this.getAliveParticleCount() + this.getDeadParticleCount();
}, },
atLimit: function ()
{
return (this.maxParticles > 0 && this.getParticleCount() === this.maxParticles);
},
onParticleDeath: function (callback, context) onParticleDeath: function (callback, context)
{ {
if (callback === undefined) if (callback === undefined)
@ -285,7 +306,8 @@ var ParticleEmitter = new Class({
for (var index = 0; index < length; ++index) for (var index = 0; index < length; ++index)
{ {
callback.call(thisArg, alive[index]); // Sends the Particle and the Emitter
callback.call(thisArg, alive[index], this);
} }
return this; return this;
@ -298,12 +320,22 @@ var ParticleEmitter = new Class({
for (var index = 0; index < length; ++index) for (var index = 0; index < length; ++index)
{ {
callback.call(thisArg, dead[index]); // Sends the Particle and the Emitter
callback.call(thisArg, dead[index], this);
} }
return this; return this;
}, },
start: function ()
{
this.on = true;
this._counter = 0;
return this;
},
pause: function () pause: function ()
{ {
this.active = false; this.active = false;
@ -318,93 +350,95 @@ var ParticleEmitter = new Class({
return this; return this;
}, },
flow: function (frequency, count)
explode: function (count)
{ {
this.emit(count); if (count === undefined) { count = 1; }
return this; this.frequency = frequency;
this.emitCount = count;
return this.start();
},
explode: function (count, x, y)
{
this.frequency = -1;
return this.emit(count, x, y);
}, },
emitAt: function (x, y, count) emitAt: function (x, y, count)
{ {
return this.emit(count, x, y);
},
emit: function (count, x, y)
{
if (count === undefined) { count = 1; }
var output = [];
if (this.atLimit())
{
return output;
}
// Store emitter coordinates in-case this was a placement explode, or emitAt
var oldX = this.x; var oldX = this.x;
var oldY = this.y; var oldY = this.y;
if (x !== undefined)
{
this.x = x; this.x = x;
this.y = y; }
var particle = this.emit(count); if (y !== undefined)
{
this.y = y;
}
var dead = this.dead;
for (var i = 0; i < count; i++)
{
var particle;
if (dead.length > 0)
{
particle = dead.pop();
particle.reset();
}
else
{
particle = new this.particleClass();
}
particle.emit(this);
if (this.particleBringToTop)
{
this.alive.push(particle);
}
else
{
this.alive.unshift(particle);
}
output.push(particle);
if (this.atLimit())
{
break;
}
}
this.x = oldX; this.x = oldX;
this.y = oldY; this.y = oldY;
return particle; return output;
},
emit: function (count)
{
if (count === undefined) { count = 1; }
var particle = null;
var x = this.x;
var y = this.y;
// var shape = this.emitShape;
var dead = this.dead;
var allowCreation = true;
for (var index = 0; index < count; index++)
{
if (dead.length > 0)
{
particle = dead.pop();
particle.reset(x, y, this.frame);
}
else if (allowCreation)
{
particle = new this.particleClass(x, y, this.frame);
}
else
{
return null;
}
// if (shape)
// {
// shape.getRandomPoint(particle);
// particle.x += x;
// particle.y += y;
// }
particle.emit(this);
// particle.velocityX = vx;
// particle.velocityY = vy;
// particle.life = Math.max(this.life, Number.MIN_VALUE);
// particle.lifeStep = particle.life;
// particle.start.scale = this.startScale;
// particle.end.scale = this.endScale;
// particle.scaleX = this.startScale;
// particle.scaleY = this.startScale;
// particle.start.alpha = this.startAlpha;
// particle.end.alpha = this.endAlpha;
// particle.start.rotation = DegToRad(this.startAngle);
// particle.end.rotation = DegToRad(this.endAngle);
// particle.color = (particle.color & 0x00FFFFFF) | (((this.startAlpha * 0xFF)|0) << 24);
// particle.index = this.alive.length;
this.alive.push(particle);
}
return particle;
}, },
preUpdate: function (time, delta) preUpdate: function (time, delta)
@ -412,17 +446,10 @@ var ParticleEmitter = new Class({
// Scale the delta // Scale the delta
delta *= this.timeScale; delta *= this.timeScale;
var dead = this.dead; var step = (delta / 1000);
var particles = this.alive; var particles = this.alive;
var length = particles.length; var length = particles.length;
var step = (delta / 1000);
var deathCallback = this.deathCallback;
var deathCallbackScope = this.deathCallbackScope;
/* Simulation */
for (var index = 0; index < length; index++) for (var index = 0; index < length; index++)
{ {
var particle = particles[index]; var particle = particles[index];
@ -432,67 +459,49 @@ var ParticleEmitter = new Class({
{ {
// Moves the dead particle to the end of the particles array (ready for splicing out later) // Moves the dead particle to the end of the particles array (ready for splicing out later)
var last = particles[length - 1]; var last = particles[length - 1];
particles[length - 1] = particle; particles[length - 1] = particle;
particles[index] = last; particles[index] = last;
index -= 1; index -= 1;
length -= 1; length -= 1;
} }
/*
particle.velocityX += gravityX;
particle.velocityY += gravityY;
particle.x += particle.velocityX * emitterStep;
particle.y += particle.velocityY * emitterStep;
particle.normLifeStep = particle.lifeStep / particle.life;
var norm = 1 - particle.normLifeStep;
var alphaEase = this.easingFunctionAlpha(norm);
var scaleEase = this.easingFunctionScale(norm);
var rotationEase = this.easingFunctionRotation(norm);
var alphaf = (particle.end.alpha - particle.start.alpha) * alphaEase + particle.start.alpha;
var scale = (particle.end.scale - particle.start.scale) * scaleEase + particle.start.scale;
var rotation = (particle.end.rotation - particle.start.rotation) * rotationEase + particle.start.rotation;
particle.scaleX = particle.scaleY = scale;
particle.color = (particle.color & 0x00FFFFFF) | (((alphaf * 0xFF)|0) << 24);
particle.rotation = rotation;
if (particle.lifeStep <= 0)
{
var last = particles[length - 1];
particles[length - 1] = particle;
particles[index] = last;
index -= 1;
length -= 1;
if (deathCallback)
{
deathCallback.call(deathCallbackScope, particle);
}
}
particle.lifeStep -= emitterStep;
*/
} }
// Move dead particles to the dead array // Move dead particles to the dead array
// We can skip this for 'emitCount' number of particles if 'this.enabled'
var deadLength = particles.length - length; var deadLength = particles.length - length;
if (deadLength > 0) if (deadLength > 0)
{ {
dead.push.apply(dead, particles.splice(particles.length - deadLength, deadLength)); var rip = particles.splice(particles.length - deadLength, deadLength);
var deathCallback = this.deathCallback;
var deathCallbackScope = this.deathCallbackScope;
if (deathCallback)
{
for (var i = 0; i < rip.length; i++)
{
deathCallback.call(deathCallbackScope, rip[i]);
}
}
this.dead.concat(rip);
StableSort(particles, this.indexSort); StableSort(particles, this.indexSort);
} }
// this.delayCounter -= emitterStep; if (this.frequency > -1 && this.on)
{
this._counter -= delta;
// if (this.delayCounter <= 0 && this.enabled) if (this._counter <= 0)
// { {
this.emit(this.emitCount); this.emit(this.emitCount);
// this.delayCounter = this.delay / 1000;
// } this._counter = this.frequency;
}
}
}, },
indexSort: function (a, b) indexSort: function (a, b)

View file

@ -9,7 +9,6 @@ var ParticleEmitterManager = new Class({
Extends: GameObject, Extends: GameObject,
Mixins: [ Mixins: [
Components.Texture,
Components.Visible, Components.Visible,
Render Render
], ],
@ -25,8 +24,14 @@ var ParticleEmitterManager = new Class({
this.timeScale = 1; this.timeScale = 1;
this.texture = null;
this.frame = null;
this.frameNames = [];
this.setTexture(texture, frame); this.setTexture(texture, frame);
// Array of frame names the emitters are allowed to use
this.emitters = []; this.emitters = [];
if (emitters !== undefined) if (emitters !== undefined)
@ -44,6 +49,46 @@ var ParticleEmitterManager = new Class({
} }
}, },
setTexture: function (key, frame)
{
this.texture = this.scene.sys.textures.get(key);
return this.setFrame(frame);
},
setFrame: function (frame)
{
this.frame = this.texture.get(frame);
this.frameNames = this.texture.getFramesFromTextureSource(this.frame.sourceIndex);
return this;
},
setEmitterFrames: function (frames, emitter)
{
if (!Array.isArray(frames))
{
frames = [ frames ];
}
var out = emitter.frames;
out.length = 0;
for (var i = 0; i < frames.length; i++)
{
var frame = frames[i];
if (this.frameNames.indexOf(frame) !== -1)
{
out.push(this.texture.get(frame));
}
}
return this;
},
addEmitter: function (emitter) addEmitter: function (emitter)
{ {
this.emitters.push(emitter); this.emitters.push(emitter);