2017-10-20 02:20:39 +00:00
|
|
|
var BlendModes = require('../../renderer/BlendModes');
|
2017-10-17 03:16:52 +00:00
|
|
|
var Class = require('../../utils/Class');
|
|
|
|
var Components = require('../components');
|
2017-10-20 02:20:39 +00:00
|
|
|
var GetRandomElement = require('../../utils/array/GetRandomElement');
|
|
|
|
var GetValue = require('../../utils/object/GetValue');
|
2017-10-21 04:05:51 +00:00
|
|
|
var GetFastValue = require('../../utils/object/GetFastValue');
|
2017-10-17 03:16:52 +00:00
|
|
|
var Particle = require('./Particle');
|
|
|
|
var StableSort = require('../../utils/array/StableSort');
|
2017-10-20 13:13:48 +00:00
|
|
|
var Vector2 = require('../../math/Vector2');
|
2017-10-24 02:02:03 +00:00
|
|
|
var EmitterOp = require('./EmitterOp');
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
var ParticleEmitter = new Class({
|
|
|
|
|
|
|
|
Mixins: [
|
|
|
|
Components.BlendMode,
|
|
|
|
Components.ScrollFactor,
|
|
|
|
Components.Visible
|
|
|
|
],
|
|
|
|
|
|
|
|
initialize:
|
|
|
|
|
|
|
|
function ParticleEmitter (manager, config)
|
|
|
|
{
|
|
|
|
if (config === undefined) { config = {}; }
|
|
|
|
|
|
|
|
this.manager = manager;
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.name = GetFastValue(config, 'name', '');
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.particleClass = GetFastValue(config, 'particleClass', Particle);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-19 23:54:47 +00:00
|
|
|
this.texture = manager.texture;
|
|
|
|
|
|
|
|
this.frames = [ manager.defaultFrame ];
|
2017-10-18 14:18:42 +00:00
|
|
|
|
2017-10-20 02:20:39 +00:00
|
|
|
this.defaultFrame = manager.defaultFrame;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.x = new EmitterOp(config, 'x', 0);
|
|
|
|
this.y = new EmitterOp(config, 'y', 0);
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-24 02:31:54 +00:00
|
|
|
// A radial emitter will emit particles in all directions between angle min and max, using speed as the value
|
2017-10-24 02:02:03 +00:00
|
|
|
// A point emitter will emit particles only in the direction derived from the speedX and speedY values
|
2017-10-21 04:05:51 +00:00
|
|
|
this.radial = GetFastValue(config, 'radial', true);
|
2017-10-18 14:18:42 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
// 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);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
// Value ops
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.speedX = new EmitterOp(config, 'speedX', 0);
|
|
|
|
this.speedY = new EmitterOp(config, 'speedY', 0);
|
|
|
|
|
|
|
|
// If you specify speedX and Y then it changes the emitter from radial to a point emitter
|
|
|
|
if (config.hasOwnProperty('speedX') || config.hasOwnProperty('speedY'))
|
|
|
|
{
|
|
|
|
this.radial = false;
|
|
|
|
}
|
2017-10-21 04:05:51 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
if (config.hasOwnProperty('speed'))
|
2017-10-20 17:49:45 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.speedX = new EmitterOp(config, 'speed', 0);
|
2017-10-23 16:11:13 +00:00
|
|
|
this.speedY = null;
|
2017-10-20 17:49:45 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.scaleX = new EmitterOp(config, 'scaleX', 1);
|
|
|
|
this.scaleY = new EmitterOp(config, 'scaleY', 1);
|
2017-10-21 04:05:51 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
if (config.hasOwnProperty('scale'))
|
2017-10-21 04:05:51 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.scaleX = new EmitterOp(config, 'scale', 1);
|
2017-10-23 16:11:13 +00:00
|
|
|
this.scaleY = null;
|
2017-10-21 04:05:51 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.alpha = new EmitterOp(config, 'alpha', 1);
|
2017-10-20 17:49:45 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
this.lifespan = new EmitterOp(config, 'lifespan', 1000);
|
2017-10-20 17:49:45 +00:00
|
|
|
|
2017-10-24 02:31:54 +00:00
|
|
|
this.angle = new EmitterOp(config, 'angle', { min: 0, max: 360 });
|
2017-10-20 17:49:45 +00:00
|
|
|
|
2017-10-24 02:31:54 +00:00
|
|
|
this.rotate = new EmitterOp(config, 'rotate', 0);
|
2017-10-20 17:49:45 +00:00
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
// Callbacks
|
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
this.emitCallback = GetFastValue(config, 'emitCallback', null);
|
|
|
|
this.emitCallbackScope = GetFastValue(config, 'emitCallbackScope', null);
|
2017-10-21 04:05:51 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
this.deathCallback = GetFastValue(config, 'deathCallback', null);
|
|
|
|
this.deathCallbackScope = GetFastValue(config, 'deathCallbackScope', null);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
var callbackScope = GetFastValue(config, 'callbackScope', null);
|
2017-10-21 04:05:51 +00:00
|
|
|
|
|
|
|
if (callbackScope)
|
|
|
|
{
|
|
|
|
this.emitCallbackScope = callbackScope;
|
|
|
|
this.deathCallbackScope = callbackScope;
|
|
|
|
}
|
|
|
|
|
2017-10-24 02:31:54 +00:00
|
|
|
// Set to hard limit the amount of particle objects this emitter is allowed to create. 0 means unlimited.
|
2017-10-24 02:02:03 +00:00
|
|
|
this.maxParticles = GetFastValue(config, 'maxParticles', 0);
|
2017-10-18 14:18:42 +00:00
|
|
|
|
|
|
|
// How many particles are emitted each time the emitter updates
|
2017-10-24 02:31:54 +00:00
|
|
|
this.quantity = new EmitterOp(config, 'quantity', 1);
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
// 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
|
2017-10-23 16:11:13 +00:00
|
|
|
this.frequency = GetFastValue(config, 'frequency', 0);
|
2017-10-18 14:18:42 +00:00
|
|
|
|
|
|
|
// Controls if the emitter is currently emitting particles. Already alive particles will continue to update until they expire.
|
2017-10-23 16:11:13 +00:00
|
|
|
this.on = GetFastValue(config, 'on', true);
|
2017-10-18 14:18:42 +00:00
|
|
|
|
|
|
|
// 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.
|
2017-10-23 16:11:13 +00:00
|
|
|
this.particleBringToTop = GetFastValue(config, 'particleBringToTop', true);
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
this.timeScale = GetFastValue(config, 'timeScale', 1);
|
2017-10-20 02:20:39 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
// private
|
2017-10-20 02:20:39 +00:00
|
|
|
this.dead = [];
|
|
|
|
this.alive = [];
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
this._counter = 0;
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
// Optional Particle emission zone - must be an object that supports a `getRandomPoint` function, such as a Rectangle, Circle, Path, etc.
|
2017-10-23 16:11:13 +00:00
|
|
|
this.zone = GetFastValue(config, 'zone', null);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
this.active = GetFastValue(config, 'active', true);
|
|
|
|
this.visible = GetFastValue(config, 'visible', true);
|
2017-10-20 02:20:39 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
this.blendMode = GetFastValue(config, 'blendMode', BlendModes.NORMAL);
|
2017-10-20 02:20:39 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
this.follow = GetFastValue(config, 'follow', null);
|
|
|
|
this.followOffset = new Vector2(GetFastValue(config, 'followOffset', 0));
|
|
|
|
this.trackVisible = GetFastValue(config, 'trackVisible', false);
|
2017-10-20 02:48:42 +00:00
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
var frame = GetFastValue(config, 'frame', null);
|
2017-10-20 02:20:39 +00:00
|
|
|
|
|
|
|
if (frame)
|
|
|
|
{
|
|
|
|
this.setFrame(frame);
|
|
|
|
}
|
2017-10-17 03:16:52 +00:00
|
|
|
},
|
|
|
|
|
2017-10-23 16:11:13 +00:00
|
|
|
fromJSON: function (config)
|
|
|
|
{
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
toJSON: function ()
|
|
|
|
{
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2017-10-20 13:13:48 +00:00
|
|
|
startFollow: function (target, offsetX, offsetY, trackVisible)
|
2017-10-20 02:48:42 +00:00
|
|
|
{
|
2017-10-20 13:13:48 +00:00
|
|
|
if (offsetX === undefined) { offsetX = 0; }
|
|
|
|
if (offsetY === undefined) { offsetY = 0; }
|
|
|
|
if (trackVisible === undefined) { trackVisible = false; }
|
|
|
|
|
|
|
|
this.follow = target;
|
|
|
|
this.followOffset.set(offsetX, offsetY);
|
|
|
|
this.trackVisible = trackVisible;
|
2017-10-20 02:48:42 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
stopFollow: function ()
|
|
|
|
{
|
2017-10-20 13:13:48 +00:00
|
|
|
this.follow = null;
|
|
|
|
this.followOffset.set(0, 0);
|
|
|
|
this.trackVisible = false;
|
2017-10-20 02:48:42 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
getFrame: function ()
|
|
|
|
{
|
2017-10-19 23:54:47 +00:00
|
|
|
if (this.frames.length === 1)
|
|
|
|
{
|
|
|
|
return this.defaultFrame;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return GetRandomElement(this.frames);
|
|
|
|
}
|
2017-10-18 14:18:42 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// Either a single frame (numeric / string based), or an array of frames to randomly pick from
|
2017-10-19 23:54:47 +00:00
|
|
|
setFrame: function (frames)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-19 23:54:47 +00:00
|
|
|
this.manager.setEmitterFrames(frames, this);
|
2017-10-18 14:18:42 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setRadial: function (value)
|
|
|
|
{
|
|
|
|
if (value === undefined) { value = true; }
|
|
|
|
|
|
|
|
this.radial = value;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setPosition: function (x, y)
|
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.x.onChange(x);
|
|
|
|
this.y.onChange(y);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-17 20:32:45 +00:00
|
|
|
// Particle Emission
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
setSpeedX: function (value)
|
|
|
|
{
|
|
|
|
this.speedX.onChange(value);
|
|
|
|
|
|
|
|
// If you specify speedX and Y then it changes the emitter from radial to a point emitter
|
|
|
|
this.radial = false;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setSpeedY: function (value)
|
|
|
|
{
|
|
|
|
this.speedY.onChange(value);
|
|
|
|
|
|
|
|
// If you specify speedX and Y then it changes the emitter from radial to a point emitter
|
|
|
|
this.radial = false;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setSpeed: function (value)
|
|
|
|
{
|
|
|
|
this.speedX.onChange(value);
|
|
|
|
this.speedY = null;
|
|
|
|
|
|
|
|
// If you specify speedX and Y then it changes the emitter from radial to a point emitter
|
|
|
|
this.radial = false;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setScaleX: function (value)
|
|
|
|
{
|
|
|
|
this.scaleX.onChange(value);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setScaleY: function (value)
|
|
|
|
{
|
|
|
|
this.scaleY.onChange(value);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setScale: function (value)
|
|
|
|
{
|
|
|
|
this.scaleX.onChange(value);
|
|
|
|
this.scaleY = null;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setGravityX: function (value)
|
2017-10-17 20:32:45 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.gravityX = value;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
setGravityY: function (value)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.gravityY = value;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-18 01:26:15 +00:00
|
|
|
setGravity: function (x, y)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.gravityX = x;
|
|
|
|
this.gravityY = y;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
setAlpha: function (value)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.alpha.onChange(value);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
setEmitterAngle: function (value)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-24 02:31:54 +00:00
|
|
|
this.angle.onChange(value);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
setAngle: function (value)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.angle.onChange(value);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-17 20:32:45 +00:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
setLifespan: function (value)
|
2017-10-17 20:32:45 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.lifespan.onChange(value);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-19 23:54:47 +00:00
|
|
|
setQuantity: function (quantity)
|
|
|
|
{
|
2017-10-24 02:31:54 +00:00
|
|
|
this.quantity.onChange(quantity);
|
2017-10-19 23:54:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setFrequency: function (frequency, quantity)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
this.frequency = frequency;
|
2017-10-19 23:54:47 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
this._counter = 0;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-19 23:54:47 +00:00
|
|
|
if (quantity)
|
|
|
|
{
|
2017-10-24 02:31:54 +00:00
|
|
|
this.quantity.onChange(quantity);
|
2017-10-19 23:54:47 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
// 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)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
if (zone === undefined)
|
|
|
|
{
|
|
|
|
this.zone = null;
|
|
|
|
}
|
|
|
|
else if (typeof zone.getRandomPoint === 'function')
|
|
|
|
{
|
|
|
|
this.zone = zone;
|
|
|
|
}
|
2017-10-17 03:16:52 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-17 20:32:45 +00:00
|
|
|
// Particle Management
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
reserve: function (particleCount)
|
|
|
|
{
|
|
|
|
var dead = this.dead;
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
for (var i = 0; i < particleCount; i++)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-21 04:05:51 +00:00
|
|
|
dead.push(new this.particleClass(this));
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
getAliveParticleCount: function ()
|
|
|
|
{
|
|
|
|
return this.alive.length;
|
|
|
|
},
|
|
|
|
|
|
|
|
getDeadParticleCount: function ()
|
|
|
|
{
|
|
|
|
return this.dead.length;
|
|
|
|
},
|
|
|
|
|
|
|
|
getParticleCount: function ()
|
|
|
|
{
|
|
|
|
return this.getAliveParticleCount() + this.getDeadParticleCount();
|
|
|
|
},
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
atLimit: function ()
|
|
|
|
{
|
|
|
|
return (this.maxParticles > 0 && this.getParticleCount() === this.maxParticles);
|
|
|
|
},
|
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
onParticleEmit: function (callback, context)
|
|
|
|
{
|
|
|
|
if (callback === undefined)
|
|
|
|
{
|
|
|
|
// Clear any previously set callback
|
|
|
|
this.emitCallback = null;
|
|
|
|
this.emitCallbackScope = null;
|
|
|
|
}
|
|
|
|
else if (typeof callback === 'function')
|
|
|
|
{
|
|
|
|
this.emitCallback = callback;
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
this.emitCallbackScope = context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
onParticleDeath: function (callback, context)
|
|
|
|
{
|
|
|
|
if (callback === undefined)
|
|
|
|
{
|
|
|
|
// Clear any previously set callback
|
|
|
|
this.deathCallback = null;
|
|
|
|
this.deathCallbackScope = null;
|
|
|
|
}
|
|
|
|
else if (typeof callback === 'function')
|
|
|
|
{
|
|
|
|
this.deathCallback = callback;
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
this.deathCallbackScope = context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
killAll: function ()
|
|
|
|
{
|
|
|
|
var dead = this.dead;
|
|
|
|
var alive = this.alive;
|
|
|
|
|
|
|
|
while (alive.length > 0)
|
|
|
|
{
|
|
|
|
dead.push(alive.pop());
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
forEachAlive: function (callback, thisArg)
|
|
|
|
{
|
|
|
|
var alive = this.alive;
|
|
|
|
var length = alive.length;
|
|
|
|
|
|
|
|
for (var index = 0; index < length; ++index)
|
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
// Sends the Particle and the Emitter
|
|
|
|
callback.call(thisArg, alive[index], this);
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
forEachDead: function (callback, thisArg)
|
|
|
|
{
|
|
|
|
var dead = this.dead;
|
|
|
|
var length = dead.length;
|
|
|
|
|
|
|
|
for (var index = 0; index < length; ++index)
|
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
// Sends the Particle and the Emitter
|
|
|
|
callback.call(thisArg, dead[index], this);
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
start: function ()
|
|
|
|
{
|
|
|
|
this.on = true;
|
|
|
|
|
|
|
|
this._counter = 0;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
pause: function ()
|
|
|
|
{
|
|
|
|
this.active = false;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
resume: function ()
|
|
|
|
{
|
|
|
|
this.active = true;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
depthSort: function ()
|
|
|
|
{
|
|
|
|
StableSort.inplace(this.alive, this.depthSortCallback);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
flow: function (frequency, count)
|
|
|
|
{
|
|
|
|
if (count === undefined) { count = 1; }
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
this.frequency = frequency;
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-24 02:31:54 +00:00
|
|
|
this.quantity.onChange(count);
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
return this.start();
|
|
|
|
},
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
explode: function (count, x, y)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
this.frequency = -1;
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
return this.emit(count, x, y);
|
2017-10-17 03:16:52 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
emitAt: function (x, y, count)
|
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
return this.emit(count, x, y);
|
|
|
|
},
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
emit: function (count, x, y)
|
|
|
|
{
|
|
|
|
if (this.atLimit())
|
|
|
|
{
|
2017-10-21 04:05:51 +00:00
|
|
|
return;
|
2017-10-18 14:18:42 +00:00
|
|
|
}
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-24 02:31:54 +00:00
|
|
|
if (count === undefined)
|
|
|
|
{
|
|
|
|
count = this.quantity.onEmit();
|
|
|
|
}
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
var dead = this.dead;
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
for (var i = 0; i < count; i++)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
var particle;
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
if (dead.length > 0)
|
|
|
|
{
|
|
|
|
particle = dead.pop();
|
2017-10-18 14:18:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-21 04:05:51 +00:00
|
|
|
particle = new this.particleClass(this);
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
2017-10-18 14:18:42 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
particle.emit(x, y);
|
2017-10-18 14:18:42 +00:00
|
|
|
|
|
|
|
if (this.particleBringToTop)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
this.alive.push(particle);
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
this.alive.unshift(particle);
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
if (this.emitCallback)
|
|
|
|
{
|
|
|
|
this.emitCallback.call(this.emitCallbackScope, particle, this);
|
|
|
|
}
|
2017-10-17 20:32:45 +00:00
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
if (this.atLimit())
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
return particle;
|
2017-10-17 03:16:52 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
preUpdate: function (time, delta)
|
|
|
|
{
|
2017-10-17 20:32:45 +00:00
|
|
|
// Scale the delta
|
|
|
|
delta *= this.timeScale;
|
|
|
|
|
2017-10-18 14:18:42 +00:00
|
|
|
var step = (delta / 1000);
|
2017-10-20 02:48:42 +00:00
|
|
|
|
2017-10-24 02:02:03 +00:00
|
|
|
if (this.trackVisible)
|
2017-10-20 02:48:42 +00:00
|
|
|
{
|
2017-10-24 02:02:03 +00:00
|
|
|
this.visible = this.follow.visible;
|
2017-10-20 02:48:42 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
var particles = this.alive;
|
|
|
|
var length = particles.length;
|
2017-10-17 20:32:45 +00:00
|
|
|
|
|
|
|
for (var index = 0; index < length; index++)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
|
|
|
var particle = particles[index];
|
|
|
|
|
2017-10-17 20:32:45 +00:00
|
|
|
// update returns `true` if the particle is now dead (lifeStep < 0)
|
2017-10-21 04:05:51 +00:00
|
|
|
if (particle.update(delta, step))
|
2017-10-17 20:32:45 +00:00
|
|
|
{
|
|
|
|
// Moves the dead particle to the end of the particles array (ready for splicing out later)
|
|
|
|
var last = particles[length - 1];
|
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
particles[length - 1] = particle;
|
|
|
|
particles[index] = last;
|
2017-10-18 14:18:42 +00:00
|
|
|
|
2017-10-17 03:16:52 +00:00
|
|
|
index -= 1;
|
|
|
|
length -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move dead particles to the dead array
|
|
|
|
var deadLength = particles.length - length;
|
|
|
|
|
|
|
|
if (deadLength > 0)
|
|
|
|
{
|
2017-10-18 14:18:42 +00:00
|
|
|
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);
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
StableSort.inplace(particles, this.indexSortCallback);
|
2017-10-17 03:16:52 +00:00
|
|
|
}
|
2017-10-21 04:05:51 +00:00
|
|
|
|
2017-10-19 23:54:47 +00:00
|
|
|
if (!this.on)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.frequency === 0)
|
|
|
|
{
|
2017-10-20 13:13:48 +00:00
|
|
|
this.emit();
|
2017-10-19 23:54:47 +00:00
|
|
|
}
|
|
|
|
else if (this.frequency > 0)
|
2017-10-18 14:18:42 +00:00
|
|
|
{
|
|
|
|
this._counter -= delta;
|
|
|
|
|
|
|
|
if (this._counter <= 0)
|
|
|
|
{
|
2017-10-20 13:13:48 +00:00
|
|
|
this.emit();
|
2017-10-17 03:16:52 +00:00
|
|
|
|
2017-10-19 23:54:47 +00:00
|
|
|
// counter = frequency - remained from previous delta
|
|
|
|
this._counter = (this.frequency - Math.abs(this._counter));
|
2017-10-18 14:18:42 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-17 03:16:52 +00:00
|
|
|
},
|
|
|
|
|
2017-10-21 04:05:51 +00:00
|
|
|
depthSortCallback: function (a, b)
|
|
|
|
{
|
|
|
|
return a.y - b.y;
|
|
|
|
},
|
|
|
|
|
|
|
|
indexSortCallback: function (a, b)
|
2017-10-17 03:16:52 +00:00
|
|
|
{
|
|
|
|
return a.index - b.index;
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = ParticleEmitter;
|