Loads of little fixes all across the emitter classes.

This commit is contained in:
Richard Davey 2017-10-23 17:11:13 +01:00
parent 80a652e071
commit 816b228cc5
3 changed files with 149 additions and 253 deletions

View file

@ -1,23 +1,26 @@
var GetEaseFunction = require('../../tweens/builder/GetEaseFunction');
var GetValue = require('../../utils/object/GetValue');
var GetFastValue = require('../../utils/object/GetFastValue');
var FloatBetween = require('../../math/FloatBetween');
var GetEaseFunction = require('../../tweens/builder/GetEaseFunction');
var GetFastValue = require('../../utils/object/GetFastValue');
var Wrap = require('../../math/Wrap');
function hasOnEmit (def)
function has (object, key)
{
return (!!def.onEmit && typeof def.onEmit === 'function');
return (object.hasOwnProperty(key));
}
function hasOnUpdate (def)
function hasBoth (object, key1, key2)
{
return (!!def.onUpdate && typeof def.onUpdate === 'function');
return (object.hasOwnProperty(key1) && object.hasOwnProperty(key2));
}
function hasGetters (def)
{
return hasOnEmit(def) || hasOnUpdate(def);
return (has(def, 'onEmit')) || (has(def, 'onUpdate'));
}
var steps = 0;
var counter = 0;
var GetValueOp = function (config, key, defaultValue)
{
var propertyValue = GetFastValue(config, key, defaultValue);
@ -73,31 +76,42 @@ var GetValueOp = function (config, key, defaultValue)
particleUpdate = propertyValue;
}
else if (t === 'object' && propertyValue.hasOwnProperty('start') && propertyValue.hasOwnProperty('end'))
else if (t === 'object' && (has(propertyValue, 'random') || hasBoth(propertyValue, 'start', 'end') || hasBoth(propertyValue, 'min', 'max')))
{
var start = propertyValue.start;
var end = propertyValue.end;
var start = (propertyValue.hasOwnProperty('start')) ? propertyValue.start : propertyValue.min;
var end = (propertyValue.hasOwnProperty('end')) ? propertyValue.end : propertyValue.max;
var isRandom = false;
// A random starting value:
// x: { start: 100, end: 400, randomStart: true }
// x: { start: 100, end: 400, random: true } OR { min: 100, max: 400, random: true } OR { random: [ 100, 400 ] }
if (propertyValue.hasOwnProperty('randomStart'))
if (has(propertyValue, 'random'))
{
particleEmit = function ()
isRandom = true;
var rnd = propertyValue.random;
// x: { random: [ 100, 400 ] } = the same as doing: x: { start: 100, end: 400, random: true }
if (Array.isArray(rnd))
{
return FloatBetween(start, end);
};
}
else
{
particleEmit = function ()
start = rnd[0];
end = rnd[1];
}
particleEmit = function (particle, key)
{
return start;
var data = particle.data[key];
var value = FloatBetween(start, end);
data.min = value;
return value;
};
}
if (propertyValue.hasOwnProperty('steps'))
if (has(propertyValue, 'steps'))
{
// A stepped (per emit) range
@ -105,11 +119,18 @@ var GetValueOp = function (config, key, defaultValue)
// Increments a value stored in the emitter
particleUpdate = function (particle, key)
{
var emitter = particle.emitter;
steps = propertyValue.steps;
counter = start;
return emitter.getNext(key);
particleEmit = function ()
{
var value = counter;
var i = value + ((end - start) / steps);
counter = Wrap(i, start, end);
return counter;
};
}
else
@ -122,12 +143,25 @@ var GetValueOp = function (config, key, defaultValue)
var easeFunc = GetEaseFunction(ease);
if (!isRandom)
{
particleEmit = function (particle, key)
{
var data = particle.data[key];
data.min = start;
data.max = end;
return start;
};
}
particleUpdate = function (particle, key, t, value)
{
var data = particle.data[key];
return data.calc * easeFunc(t) + data.min;
}
return (data.max - data.min) * easeFunc(t) + data.min;
};
}
}
else if (t === 'object' && hasGetters(propertyValue))
@ -150,12 +184,12 @@ var GetValueOp = function (config, key, defaultValue)
}
*/
if (hasOnEmit(propertyValue))
if (has(propertyValue, 'onEmit'))
{
particleEmit = propertyValue.onEmit;
}
if (hasOnUpdate(propertyValue))
if (has(propertyValue, 'onUpdate'))
{
particleUpdate = propertyValue.onUpdate;
}

View file

@ -1,6 +1,5 @@
var Class = require('../../utils/Class');
var DegToRad = require('../../math/DegToRad');
var FloatBetween = require('../../math/FloatBetween');
var Particle = new Class({
@ -44,10 +43,10 @@ var Particle = new Class({
// ease data
this.data = {
tint: { min: 0xffffff, max: 0xffffff, current: 0xffffff },
alpha: { min: 1, max: 1, calc: 0 },
angle: { min: 0, max: 0, calc: 0 },
scaleX: { min: 1, max: 1, calc: 0 },
scaleY: { min: 1, max: 1, calc: 0 }
alpha: { min: 1, max: 1 },
angle: { min: 0, max: 0 },
scaleX: { min: 1, max: 1 },
scaleY: { min: 1, max: 1 }
};
},
@ -67,15 +66,15 @@ var Particle = new Class({
emitter.zone.getRandomPoint(this);
}
this.x += emitter.x.getNext();
this.y += emitter.y.getNext();
this.x += emitter.x.onEmit(this, 'x');
this.y += emitter.y.onEmit(this, 'y');
var sx = emitter.speedX.getNext();
var sy = emitter.speedY.getNext();
var sx = emitter.speedX.onEmit(this, 'speedX');
var sy = (emitter.speedY) ? emitter.speedY.onEmit(this, 'speedY') : sx;
if (emitter.radial)
{
var rad = DegToRad(emitter.emitterAngle.getNext());
var rad = DegToRad(emitter.emitterAngle.onEmit(this, 'angle'));
this.velocityX = Math.cos(rad) * Math.abs(sx);
this.velocityY = Math.sin(rad) * Math.abs(sy);
@ -86,104 +85,17 @@ var Particle = new Class({
this.velocityY = sy;
}
this.life = emitter.lifespan.getNext();
this.life = emitter.lifespan.onEmit(this, 'lifespan');
this.lifeCurrent = this.life;
// eased values
this.scaleX = emitter.scaleX.onEmit(this, 'scaleX');
this.scaleY = (emitter.scaleY) ? emitter.scaleY.onEmit(this, 'scaleY') : this.scaleX;
var dataScaleX = this.data.scaleX;
var dataScaleY = this.data.scaleY;
var dataAngle = this.data.angle;
var dataAlpha = this.data.alpha;
this.angle = emitter.particleAngle.onEmit(this, 'angle');
this.rotation = DegToRad(this.angle);
emitter.scaleX.copyToMinMax(dataScaleX);
emitter.scaleY.copyToMinMax(dataScaleY);
emitter.particleAngle.copyToMinMax(dataAngle);
emitter.alpha.copyToMinMax(dataAlpha);
this.alpha = emitter.alpha.onEmit(this, 'alpha');
// Random overrides
if (emitter.randomScaleX)
{
var randomScaleX = FloatBetween(emitter.randomScaleX[0], emitter.randomScaleX[1]);
// If there is no current ease value set we override them both
if (dataScaleX.min === dataScaleX.max)
{
dataScaleX.min = randomScaleX;
dataScaleX.max = randomScaleX;
}
else
{
// Otherwise we just reset the start value, so it still eases to the end value
dataScaleX.min = randomScaleX;
}
}
if (emitter.randomScaleY)
{
var randomScaleY = FloatBetween(emitter.randomScaleY[0], emitter.randomScaleY[1]);
// If there is no current ease value set we override them both
if (dataScaleY.min === dataScaleY.max)
{
dataScaleY.min = randomScaleY;
dataScaleY.max = randomScaleY;
}
else
{
// Otherwise we just reset the start value, so it still eases to the end value
dataScaleY.min = randomScaleY;
}
}
if (emitter.randomAngle)
{
var randomAngle = FloatBetween(emitter.randomAngle[0], emitter.randomAngle[1]);
// If there is no current ease value set we override them both
if (dataAngle.min === dataAngle.max)
{
dataAngle.min = randomAngle;
dataAngle.max = randomAngle;
}
else
{
// Otherwise we just reset the start value, so it still eases to the end value
dataAngle.min = randomAngle;
}
}
if (emitter.randomAlpha)
{
var randomAlpha = FloatBetween(emitter.randomAlpha[0], emitter.randomAlpha[1]);
// If there is no current ease value set we override them both
if (dataAlpha.min === dataAlpha.max)
{
dataAlpha.min = randomAlpha;
dataAlpha.max = randomAlpha;
}
else
{
// Otherwise we just reset the start value, so it still eases to the end value
dataAlpha.min = randomAlpha;
}
}
// Pre-calc ease values
dataScaleX.calc = dataScaleX.max - dataScaleX.min;
dataScaleY.calc = dataScaleY.max - dataScaleY.min;
dataAngle.calc = dataAngle.max - dataAngle.min;
dataAlpha.calc = dataAlpha.max - dataAlpha.min;
// Set initial values
this.scaleX = dataScaleX.min;
this.scaleY = dataScaleY.min;
this.angle = dataAngle.min;
this.rotation = DegToRad(dataAngle.min);
this.alpha = dataAlpha.min;
this.color = (this.color & 0x00FFFFFF) | (((this.alpha * 0xFF) | 0) << 24);
this.index = emitter.alive.length;
@ -197,21 +109,27 @@ var Particle = new Class({
// How far along in life is this particle? (t = 0 to 1)
var t = 1 - (this.lifeCurrent / this.life);
this.velocityX += (emitter.gravity.x * step);
this.velocityY += (emitter.gravity.y * step);
this.velocityX += (emitter.gravityX * step);
this.velocityY += (emitter.gravityY * step);
this.x += this.velocityX * step;
this.y += this.velocityY * step;
var data = this.data;
this.scaleX = emitter.scaleX.onUpdate(this, 'scaleX', t, this.scaleX);
this.scaleX = data.scaleX.calc * emitter.easingFunctionScale(t) + data.scaleX.min;
this.scaleY = data.scaleY.calc * emitter.easingFunctionScale(t) + data.scaleY.min;
if (emitter.scaleY)
{
this.scaleY = emitter.scaleY.onUpdate(this, 'scaleY', t, this.scaleY);
}
else
{
this.scaleY = this.scaleX;
}
this.angle = data.angle.calc * emitter.easingFunctionRotation(t) + data.angle.min;
this.angle = emitter.particleAngle.onUpdate(this, 'angle', t, this.angle);
this.rotation = DegToRad(this.angle);
this.alpha = data.alpha.calc * emitter.easingFunctionAlpha(t) + data.alpha.min;
this.alpha = emitter.alpha.onUpdate(this, 'alpha', t, this.alpha);
this.color = (this.color & 0x00FFFFFF) | (((this.alpha * 0xFF) | 0) << 24);

View file

@ -1,12 +1,9 @@
var BlendModes = require('../../renderer/BlendModes');
var Class = require('../../utils/Class');
var Components = require('../components');
var GetEaseFunction = require('../../tweens/builder/GetEaseFunction');
var GetRandomElement = require('../../utils/array/GetRandomElement');
var GetValue = require('../../utils/object/GetValue');
var GetFastValue = require('../../utils/object/GetFastValue');
var MinMax2 = require('../../math/MinMax2');
var MinMax4 = require('../../math/MinMax4');
var Particle = require('./Particle');
var StableSort = require('../../utils/array/StableSort');
var Vector2 = require('../../math/Vector2');
@ -45,82 +42,48 @@ var ParticleEmitter = new Class({
// A point emitter will emit particles only in the direction derived from the speed values
this.radial = GetFastValue(config, 'radial', true);
// Not a value operation because you should be able to constantly alter this and effect all
// alive particles in real-time, instantly
this.gravityX = GetValue(config, 'gravityX', 0);
this.gravityY = GetValue(config, 'gravityY', 0);
// Value ops
this.speedX = GetValueOp(config, 'speedX', 0);
this.speedY = GetValueOp(config, 'speedY', 0);
if (config.hasOwnProperty('speed'))
{
this.speedX = GetValueOp(config, 'speed', 0);
this.speedY = null;
}
this.scaleX = GetValueOp(config, 'scaleX', 1);
this.scaleY = GetValueOp(config, 'scaleY', 1);
this.gravityX = GetValueOp(config, 'gravityX', 0);
this.gravityY = GetValueOp(config, 'gravityY', 0);
if (config.hasOwnProperty('scale'))
{
this.scaleX = GetValueOp(config, 'scale', 1);
this.scaleY = null;
}
this.alpha = GetValueOp(config, 'alpha', 1);
/*
this.x = new MinMax2(GetValue(config, 'x', 0));
this.y = new MinMax2(GetValue(config, 'y', 0));
this.lifespan = GetValueOp(config, 'lifespan', 1000);
this.radial = GetValue(config, 'radial', true);
this.emitterAngle = GetValueOp(config, 'angle', { min: 0, max: 360, random: true });
this.speedX = new MinMax2(GetValue(config, 'speedX', 0));
this.speedY = new MinMax2(GetValue(config, 'speedY', 0));
var speedConfig = GetValue(config, 'speed', null);
if (speedConfig)
{
this.speedX.set(speedConfig);
this.speedY.set(speedConfig);
}
this.scaleX = new MinMax2(GetValue(config, 'scaleX', 1));
this.scaleY = new MinMax2(GetValue(config, 'scaleY', 1));
var scaleConfig = GetValue(config, 'scale', null);
if (scaleConfig)
{
this.scaleX.set(scaleConfig);
this.scaleY.set(scaleConfig);
}
this.gravity = new MinMax2(GetValue(config, 'gravity', 0));
this.alpha = new MinMax2(GetValue(config, 'alpha', 1));
*/
this.emitterAngle = new MinMax2(GetValue(config, 'angle', [ 0, 360 ]));
this.particleAngle = new MinMax2(GetValue(config, 'particleAngle', 0));
// The lifespan of the particles (in ms)
this.lifespan = new MinMax2(GetValue(config, 'lifespan', 1000));
// Random overrides
this.randomScaleX = GetValue(config, 'randomScaleX', null);
this.randomScaleY = GetValue(config, 'randomScaleY', null);
this.randomScale = GetValue(config, 'randomScale', null);
if (this.randomScale)
{
this.randomScaleX = this.randomScale;
this.randomScaleY = this.randomScale;
}
this.randomAlpha = GetValue(config, 'randomAlpha', null);
this.randomAngle = GetValue(config, 'randomAngle', null);
this.particleAngle = GetValueOp(config, 'particleAngle', 0);
// Callbacks
this.emitCallback = GetValue(config, 'emitCallback', null);
this.emitCallbackScope = GetValue(config, 'emitCallbackScope', null);
this.emitCallback = GetFastValue(config, 'emitCallback', null);
this.emitCallbackScope = GetFastValue(config, 'emitCallbackScope', null);
this.deathCallback = GetValue(config, 'deathCallback', null);
this.deathCallbackScope = GetValue(config, 'deathCallbackScope', null);
this.deathCallback = GetFastValue(config, 'deathCallback', null);
this.deathCallbackScope = GetFastValue(config, 'deathCallbackScope', null);
var callbackScope = GetValue(config, 'callbackScope', null)
var callbackScope = GetFastValue(config, 'callbackScope', null);
if (callbackScope)
{
@ -129,46 +92,43 @@ var ParticleEmitter = new Class({
}
// Set to hard limit the amount of particle objects this emitter is allowed to create
this.maxParticles = GetValue(config, 'maxParticles', 0);
this.maxParticles = GetFastValue(config, 'maxParticles', 1);
// How many particles are emitted each time the emitter updates
this.quantity = GetValue(config, 'quantity', 1);
this.quantity = GetFastValue(config, 'quantity', 1);
// How often a particle is emitted in ms (if emitter is a constant / flow emitter)
// If emitter is an explosion emitter this value will be -1.
// Anything > -1 sets this to be a flow emitter
this.frequency = GetValue(config, 'frequency', 0);
this.frequency = GetFastValue(config, 'frequency', 0);
// Controls if the emitter is currently emitting particles. Already alive particles will continue to update until they expire.
this.on = GetValue(config, 'on', true);
this.on = GetFastValue(config, 'on', 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.
this.particleBringToTop = GetValue(config, 'particleBringToTop', true);
this.particleBringToTop = GetFastValue(config, 'particleBringToTop', true);
this.timeScale = GetValue(config, 'timeScale', 1);
this.timeScale = GetFastValue(config, 'timeScale', 1);
// private
this.dead = [];
this.alive = [];
this._counter = 0;
// Optional Particle emission zone - must be an object that supports a `getRandomPoint` function, such as a Rectangle, Circle, Path, etc.
this.zone = GetValue(config, 'zone', null);
this.zone = GetFastValue(config, 'zone', null);
this.active = GetValue(config, 'active', true);
this.visible = GetValue(config, 'visible', true);
this.active = GetFastValue(config, 'active', true);
this.visible = GetFastValue(config, 'visible', true);
this.blendMode = GetValue(config, 'blendMode', BlendModes.NORMAL);
this.blendMode = GetFastValue(config, 'blendMode', BlendModes.NORMAL);
this.easingFunctionAlpha = GetEaseFunction(GetValue(config, 'alphaEase', 'Linear'));
this.easingFunctionScale = GetEaseFunction(GetValue(config, 'scaleEase', 'Linear'));
this.easingFunctionRotation = GetEaseFunction(GetValue(config, 'rotationEase', 'Linear'));
this.follow = GetFastValue(config, 'follow', null);
this.followOffset = new Vector2(GetFastValue(config, 'followOffset', 0));
this.trackVisible = GetFastValue(config, 'trackVisible', false);
this.follow = GetValue(config, 'follow', null);
this.followOffset = new Vector2(GetValue(config, 'followOffset', 0));
this.trackVisible = GetValue(config, 'trackVisible', false);
var frame = GetValue(config, 'frame', null);
var frame = GetFastValue(config, 'frame', null);
if (frame)
{
@ -176,6 +136,16 @@ var ParticleEmitter = new Class({
}
},
fromJSON: function (config)
{
},
toJSON: function ()
{
},
startFollow: function (target, offsetX, offsetY, trackVisible)
{
if (offsetX === undefined) { offsetX = 0; }
@ -227,6 +197,7 @@ var ParticleEmitter = new Class({
return this;
},
/*
setPosition: function (x, y)
{
this.x = x;
@ -235,38 +206,6 @@ var ParticleEmitter = new Class({
return this;
},
setEase: function (easeName, easeParam)
{
var ease = GetEaseFunction(easeName, easeParam);
this.easingFunctionAlpha = ease;
this.easingFunctionScale = ease;
this.easingFunctionRotation = ease;
return this;
},
setAlphaEase: function (easeName, easeParam)
{
this.easingFunctionAlpha = GetEaseFunction(easeName, easeParam);
return this;
},
setScaleEase: function (easeName, easeParam)
{
this.easingFunctionScale = GetEaseFunction(easeName, easeParam);
return this;
},
setRotationEase: function (easeName, easeParam)
{
this.easingFunctionRotation = GetEaseFunction(easeName, easeParam);
return this;
},
// Particle Emission
setSpeed: function (xMin, xMax, yMin, yMax)
@ -317,6 +256,7 @@ var ParticleEmitter = new Class({
return this;
},
*/
setQuantity: function (quantity)
{
@ -536,6 +476,7 @@ var ParticleEmitter = new Class({
// Store emitter coordinates in-case this was a placement explode, or emitAt
/*
var oldX = this.x;
var oldY = this.y;
@ -548,6 +489,7 @@ var ParticleEmitter = new Class({
{
this.y = y;
}
*/
var dead = this.dead;
@ -586,8 +528,10 @@ var ParticleEmitter = new Class({
}
}
/*
this.x = oldX;
this.y = oldY;
*/
return particle;
},