party-js
Version:
A JavaScript library to brighten up your user's site experience with visual effects!
180 lines (179 loc) • 8.38 kB
JavaScript
"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;