UNPKG

proton-engine

Version:

Proton is a simple and powerful javascript particle animation engine.

337 lines (286 loc) 8.13 kB
import Util from "../utils/Util"; import Puid from "../utils/Puid"; import Particle from "../core/Particle"; import EventDispatcher from "../events/EventDispatcher"; import Rate from "../initialize/Rate"; import InitializeUtil from "../initialize/InitializeUtil"; export default class Emitter extends Particle { /** * You can use this emit particles. * * It will dispatch follow events: * PARTICLE_CREATED * PARTICLE_UPDATA * PARTICLE_DEAD * * @class Emitter * @constructor * @param {Object} conf the parameters object; * for example {damping:0.01,bindEmitter:false} */ constructor(conf = {}) { super(conf); this.particles = []; this.behaviours = []; this.initializes = []; this.emitTime = 0; this.emitSpeed = 0; this.totalTime = -1; /** * The friction coefficient for all particle emit by This; * @property damping * @type {Number} * @default 0.006 */ this.damping = 0.006; /** * If bindEmitter the particles can bind this emitter's property; * @property bindEmitter * @type {Boolean} * @default true */ this.bindEmitter = true; /** * The number of particles per second emit (a [particle]/b [s]); * @property rate * @type {Rate} * @default Rate(1, .1) */ this.rate = new Rate(1, 0.1); this.name = "Emitter"; this.id = Puid.id(this.name); } /** * start emit particle * @method emit * @param {Number | String} [totalTime] begin emit time; * @param {String | boolean} [life] the life of this emitter */ emit(totalTime, life) { this.stoped = false; this.emitTime = 0; this.totalTime = Util.initValue(totalTime, Infinity); if (life === true || life === "life" || life === "destroy") { this.life = totalTime === "once" ? 1 : this.totalTime; } else if (!isNaN(life)) { this.life = life; } this.rate.init(); } /** * stop emiting * @method stop */ stop() { this.totalTime = -1; this.emitTime = 0; this.stoped = true; } preEmit(time) { let oldStoped = this.stoped; let oldEmitTime = this.emitTime; let oldTotalTime = this.totalTime; this.stoped = false; this.emitTime = 0; this.totalTime = time; this.rate.init(); const step = 0.0167; while (time > step) { time -= step; this.update(step); } this.stoped = oldStoped; this.emitTime = oldEmitTime + Math.max(time, 0); this.totalTime = oldTotalTime; } /** * remove current all particles * @method removeAllParticles */ removeAllParticles() { let i = this.particles.length; while (i--) this.particles[i].dead = true; } /** * add initialize to this emitter * @method addSelfInitialize */ addSelfInitialize(initialize) { if (initialize["init"]) { initialize.init(this); } else { // this.initAll(); } } /** * add the Initialize to particles; * * you can use initializes array:for example emitter.addInitialize(initialize1,initialize2,initialize3); * @method addInitialize * @param {Initialize} initialize like this new Radius(1, 12) */ addInitialize(...rest) { let i = rest.length; while (i--) this.initializes.push(rest[i]); } /** * remove the Initialize * @method removeInitialize * @param {Initialize} initialize a initialize */ removeInitialize(initializer) { const index = this.initializes.indexOf(initializer); if (index > -1) this.initializes.splice(index, 1); } /** * remove all Initializes * @method removeInitializers */ removeAllInitializers() { Util.emptyArray(this.initializes); } /** * add the Behaviour to particles; * * you can use Behaviours array:emitter.addBehaviour(Behaviour1,Behaviour2,Behaviour3); * @method addBehaviour * @param {Behaviour} behaviour like this new Color('random') */ addBehaviour(...rest) { let i = arguments.length; while (i--) { let behaviour = rest[i]; this.behaviours.push(behaviour); if (behaviour.parents) behaviour.parents.push(this); } } /** * remove the Behaviour * @method removeBehaviour * @param {Behaviour} behaviour a behaviour */ removeBehaviour(behaviour) { let index = this.behaviours.indexOf(behaviour); this.behaviours.splice(index, 1); if (behaviour.parents) { index = behaviour.parents.indexOf(behaviour); behaviour.parents.splice(index, 1); } return index; } /** * remove all behaviours * @method removeAllBehaviours */ removeAllBehaviours() { Util.emptyArray(this.behaviours); } // emitter update update(time) { this.age += time; if (this.age >= this.life || this.dead) this.destroy(); this.emitting(time); this.integrate(time); } integrate(time) { if (!this.parent) return; const damping = 1 - this.damping; this.parent.integrator.calculate(this, time, damping); const length = this.particles.length; let i, particle; for (i = length - 1; i >= 0; i--) { particle = this.particles[i]; // particle update particle.update(time, i); this.parent.integrator.calculate(particle, time, damping); this.dispatch("PARTICLE_UPDATE", particle); // check dead if (particle.dead) { this.dispatch("PARTICLE_DEAD", particle); this.parent.pool.expire(particle); this.particles.splice(i, 1); } } } dispatch(event, target) { this.parent && this.parent.dispatchEvent(event, target); this.bindEvent && this.dispatchEvent(event, target); } emitting(time) { if (this.stoped) return; if (this.totalTime === "none") { this.emitTime += time; } else if (this.totalTime === "once") { let i; const length = this.rate.getValue(99999); if (length > 0) this.emitSpeed = length; for (i = 0; i < length; i++) this.createParticle(); this.totalTime = "none"; } else { this.emitTime += time; if (this.emitTime < this.totalTime) { const length = this.rate.getValue(time); let i; if (length > 0) this.emitSpeed = length; for (i = 0; i < length; i++) this.createParticle(); } } } /** * Creates a single particle. * * @param {Object|Array} [initialize] - Initialization parameters or array of initialization objects. * @param {Object|Array} [behaviour] - Behavior object or array of behavior objects. * @returns {Particle} The created particle. * */ createParticle(initialize, behaviour) { const particle = this.parent.pool.get(Particle); this.setupParticle(particle, initialize, behaviour); this.dispatch("PARTICLE_CREATED", particle); return particle; } /** * Sets up a particle with initialization and behavior. * * @param {Particle} particle - The particle to set up. * @param {Object|Array} [initialize] - Initialization parameters or array of initialization objects. * @param {Object|Array} [behaviour] - Behavior object or array of behavior objects. */ setupParticle(particle, initialize, behaviour) { let initializes = this.initializes; let behaviours = this.behaviours; if (initialize) initializes = Util.toArray(initialize); if (behaviour) behaviours = Util.toArray(behaviour); particle.reset(); InitializeUtil.initialize(this, particle, initializes); particle.addBehaviours(behaviours); particle.parent = this; this.particles.push(particle); } /** * Removes all particles and stops the emitter. */ remove() { this.stop(); Util.destroyAll(this.particles); } /** * Destory this Emitter * @method destroy */ destroy() { this.dead = true; this.remove(); this.removeAllInitializers(); this.removeAllBehaviours(); this.parent && this.parent.removeEmitter(this); this.rate = null; this.old = null; this.rgb = null; this.v = null; this.a = null; this.p = null; } } EventDispatcher.bind(Emitter);