UNPKG

party-js

Version:

A JavaScript library to brighten up your user's site experience with visual effects!

180 lines (179 loc) 8.38 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Emitter = void 0; var vector_1 = require("../components/vector"); var settings_1 = require("../settings"); var variation_1 = require("../systems/variation"); var config_1 = require("../util/config"); var options_1 = require("./options"); var particle_1 = require("./particle"); /** * Represents an emitter that is responsible for spawning and updating particles. * * Particles themselves are just data-holders, with the system acting upon them and * modifying them. The modifications are done mainly via modules, that use the * particle's data together with some function to apply temporal transitions. * * @see Particle * @see ParticleModifierModule */ var Emitter = /** @class */ (function () { /** * Creates a new emitter, using default options. */ function Emitter(options) { /** * The particles currently contained within the system. */ this.particles = []; this.currentLoop = 0; // The current loop index. this.durationTimer = 0; // Measures the current runtime duration, to allow loops to reset. this.emissionTimer = 0; // Measures the current emission timer, to allow spawning particles in intervals. this.attemptedBurstIndices = []; // The indices of the particle bursts that were attempted this loop. this.options = config_1.overrideDefaults(options_1.getDefaultEmitterOptions(), options === null || options === void 0 ? void 0 : options.emitterOptions); this.emission = config_1.overrideDefaults(options_1.getDefaultEmissionOptions(), options === null || options === void 0 ? void 0 : options.emissionOptions); this.renderer = config_1.overrideDefaults(options_1.getDefaultRendererOptions(), options === null || options === void 0 ? void 0 : options.rendererOptions); } Object.defineProperty(Emitter.prototype, "isExpired", { /** * Checks if the emitter is already expired and can be removed. * Expired emitters do not emit new particles. */ get: function () { return (this.options.loops >= 0 && this.currentLoop >= this.options.loops); }, enumerable: false, configurable: true }); Object.defineProperty(Emitter.prototype, "canRemove", { /** * Checks if the emitter can safely be removed. * This is true if no more particles are active. */ get: function () { return this.particles.length === 0; }, enumerable: false, configurable: true }); /** * Clears all particles inside the emitter. * * @returns The number of cleared particles. */ Emitter.prototype.clearParticles = function () { return this.particles.splice(0).length; }; /** * Processes a tick of the emitter, using the elapsed time. * * @remarks * This handles a few things, namely: * - Incrementing the duration timer and potentially incrementing the loop. * - Handling particle bursts & emissions. * - Despawning particles conditionally. * * @param delta The time, in seconds, passed since the last tick. */ Emitter.prototype.tick = function (delta) { if (!this.isExpired) { this.durationTimer += delta; if (this.durationTimer >= this.options.duration) { this.currentLoop++; // To start a new loop, the duration timer and attempted bursts are reset. this.durationTimer = 0; this.attemptedBurstIndices = []; } // We need to check the expiry again, in case the added loop or duration changed something. if (!this.isExpired) { // Iterate over the bursts, attempting to execute them if the time is ready. var burstIndex = 0; for (var _i = 0, _a = this.emission.bursts; _i < _a.length; _i++) { var burst = _a[_i]; if (burst.time <= this.durationTimer) { // Has the burst already been attempted? If not ... if (!this.attemptedBurstIndices.includes(burstIndex)) { // Perform the burst, emitting a variable amount of particles. var count = variation_1.evaluateVariation(burst.count); for (var i = 0; i < count; i++) { this.emitParticle(); } // Mark the burst as attempted. this.attemptedBurstIndices.push(burstIndex); } } burstIndex++; } // Handle the 'emission over time'. By using a while-loop instead of a simple // if-condition, we take high deltas into account, and ensure that the correct // number of particles will consistently be emitted. this.emissionTimer += delta; var delay = 1 / this.emission.rate; while (this.emissionTimer > delay) { this.emissionTimer -= delay; this.emitParticle(); } } } var _loop_1 = function (i) { var particle = this_1.particles[i]; this_1.tickParticle(particle, delta); // Particles should be despawned (i.e. removed from the collection) if any of // the despawning rules apply to them. if (this_1.options.despawningRules.some(function (rule) { return rule(particle); })) { this_1.particles.splice(i, 1); } }; var this_1 = this; for (var i = this.particles.length - 1; i >= 0; i--) { _loop_1(i); } }; /** * Performs an internal tick for the particle. * * @remarks * This method controls the particle's lifetime, location and velocity, according * to the elapsed delta and the configuration. Additionally, each of the emitter's * modules is applied to the particle. * * @param particle The particle to apply the tick for. * @param delta The time, in seconds, passed since the last tick. */ Emitter.prototype.tickParticle = function (particle, delta) { particle.lifetime -= delta; if (this.options.useGravity) { // Apply gravitational acceleration to the particle. particle.velocity = particle.velocity.add(vector_1.Vector.up.scale(settings_1.settings.gravity * delta)); } // Apply the particle's velocity to its location. particle.location = particle.location.add(particle.velocity.scale(delta)); // Apply the modules to the particle. for (var _i = 0, _a = this.options.modules; _i < _a.length; _i++) { var moduleFunction = _a[_i]; moduleFunction(particle); } }; /** * Emits a particle using the registered settings. * Also may despawn a particle if the maximum number of particles is exceeded. */ Emitter.prototype.emitParticle = function () { var particle = new particle_1.Particle({ location: this.emission.sourceSampler(), lifetime: variation_1.evaluateVariation(this.emission.initialLifetime), velocity: vector_1.Vector.from2dAngle(variation_1.evaluateVariation(this.emission.angle)).scale(variation_1.evaluateVariation(this.emission.initialSpeed)), size: variation_1.evaluateVariation(this.emission.initialSize), rotation: variation_1.evaluateVariation(this.emission.initialRotation), color: variation_1.evaluateVariation(this.emission.initialColor), }); this.particles.push(particle); // Ensure that no more particles than 'maxParticles' can exist. if (this.particles.length > this.options.maxParticles) { this.particles.shift(); } return particle; }; return Emitter; }()); exports.Emitter = Emitter;