game_actor_particle_particle_emitter.js
import Vec2 from "../../vector/vec2.js";
import Vec2Gradient from "../../../util/gradient/vec2_gradient.js";
import Actor from "../actor.js";
import Particle from "./particle.js";
import NumberGradient from "../../../util/gradient/number_gradient.js";
/**
* @module ParticleEmitter
* @fileoverview Contains ParticleEmitter class.
*/
/**
* @class
* @extends Actor
* Emits particles.
*/
class ParticleEmitter extends Actor {
/**
* Create a new particle emitter.
* @param {Vec2} pos Position of emitter
* @param {number} rate Seconds between spawning particles, or number to spawn (if continuous is false)
* @param {boolean} continuous Whether particles should be spawned repeatedly every [rate] seconds, or all at once
* @param {number} lifespan Lifespan of particles
* @param {string|Sprite} sprite Sprite or identifier of sprite to use for particles
* @param {"random"|number} rotation Rotation of particles
* @param {number} spin Angular velocity of particles
* @param {number|Vec2|Vec2Gradient} scale Scale of particles
* @param {number|NumberGradient} opacity Opacity of particles
* @param {number|Vec2} range Range of spawning particles
* @param {number|Vec2|Vec2Gradient} velocity Velocity of particles (if a number is given, it will be outward from
* the source)
* @param {Object} events Events to add to emitter
* @constructor
*/
constructor({
pos = new Vec2(),
rate = 0.5,
continuous = true,
lifespan = 1,
sprite = null,
rotation = "random",
spin = 0,
scale = 1,
opacity = 1,
range = 0,
velocity = new Vec2(),
events = {}
} = {}) {
super({
pos: pos,
events: events
});
this.rate = rate;
this.continuous = continuous;
this.lifespan = lifespan;
this.sprite = sprite;
this.pRot = rotation;
this.spin = spin;
this.pScale = new Vec2Gradient({0: new Vec2(1, 1)});
if (typeof scale === "number" || scale instanceof Vec2)
this.pScale = new Vec2Gradient({0: scale});
else if (scale instanceof Vec2Gradient)
this.pScale = scale;
this.opacity = new NumberGradient({0: 1});
if (typeof opacity === "number")
this.opacity = new NumberGradient({0: opacity});
else if (opacity instanceof NumberGradient)
this.opacity = opacity;
this.range = 0;
if (typeof range === "number")
this.range = new Vec2(range, range);
else if (range instanceof Vec2)
this.range = range.copy();
this.velocity = new Vec2Gradient();
if (typeof velocity === "number")
this.velocity = velocity;
else if (velocity instanceof Vec2)
this.velocity = new Vec2Gradient({0: velocity});
else if (velocity instanceof Vec2Gradient)
this.velocity = velocity;
// Timer
this._timer = 0;
}
init() {
super.init();
if (this.continuous)
return;
this._spawnParticles(this.rate);
this.delete();
}
update(elapsed) {
super.update(elapsed);
if (!this.continuous)
return;
this._timer += elapsed;
if (this._timer >= this.rate) {
this._spawnParticle();
this._timer = 0;
}
}
//
// Spawning Particles
//
/**
* Spawn a new particle.
* @private
*/
_spawnParticle() {
const diff = new Vec2(
this.range.x * (Math.random() * 2 - 1),
this.range.y * (Math.random() * 2 - 1)
);
let vel = this.velocity;
if (typeof vel === "number")
vel = new Vec2Gradient({
0: diff.norm().mulv(this.velocity)
});
const particle = this.space.addActor(new Particle({
pos: this.globalPos.add(diff),
lifespan: this.lifespan,
sprite: this.sprite,
rotation: this.pRot,
spin: this.spin,
scale: this.pScale,
opacity: this.opacity,
velocity: vel
}));
this.doEvent("spawnParticle", particle);
}
/**
* Spawn multiple new particles.
* @param {number} amount Number of new particles to spawn
* @private
*/
_spawnParticles(amount) {
for (let i = 0; i < amount; i++)
this._spawnParticle();
}
}
export default ParticleEmitter;