From 246453a25e6a80799a093d6b79ecd25f4c388890 Mon Sep 17 00:00:00 2001 From: Nathan Kunicki Date: Sat, 13 Feb 2016 23:22:21 +0000 Subject: [PATCH] Particles now emit at a specified rate and correctly obey parent positions --- examples/particles/particles.js | 17 +++++---- src/classes/emitter.js | 64 +++++++++++++++++++++++++++------ src/classes/entity.js | 8 +++++ 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/examples/particles/particles.js b/examples/particles/particles.js index fcc3592..385e1da 100644 --- a/examples/particles/particles.js +++ b/examples/particles/particles.js @@ -4,6 +4,7 @@ import MomentumEngine from "../../src/es6"; let white = new MomentumEngine.Classes.Color(255, 255, 255); + class BlueParticle extends MomentumEngine.Classes.Rect { constructor (x, y) { @@ -15,11 +16,11 @@ class BlueParticle extends MomentumEngine.Classes.Rect { window.onload = function () { - var width = 640, + let width = 640, height = 360, baseSize = width / 64; - var particles = new MomentumEngine.Classes.Game({ + let particles = new MomentumEngine.Classes.Game({ canvas: document.getElementById("canvas"), width: width, height: height, @@ -27,19 +28,23 @@ window.onload = function () { desiredFps: 60 }); - var black = new MomentumEngine.Classes.Color(0, 0, 0), + let black = new MomentumEngine.Classes.Color(0, 0, 0), red = new MomentumEngine.Classes.Color(255, 0, 0); - var mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black); + let mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black); particles.addChildEntity(mainScene); - var rect = new MomentumEngine.Classes.Rect(width / 2 - baseSize, height / 2 - baseSize, baseSize * 2, baseSize * 2, red), - emitter = new MomentumEngine.Classes.Emitter(0, 0, new MomentumEngine.Classes.Vector2D(1, 1), BlueParticle); + let rect = new MomentumEngine.Classes.Rect(width / 10 - baseSize, height - (baseSize * 10), baseSize * 2, baseSize * 2, red), + emitter = new MomentumEngine.Classes.Emitter(baseSize, baseSize, 2, new MomentumEngine.Classes.Vector2D(1, 1), BlueParticle); mainScene.addChildEntity(rect); rect.addChildEntity(emitter); + rect.setVelocity(0.01, 0); + rect.setAcceleration(0.01, 0); + emitter.setParticleParent(mainScene); emitter.emitting = true; + particles.start(); }; \ No newline at end of file diff --git a/src/classes/emitter.js b/src/classes/emitter.js index 1755403..e1c6ad3 100644 --- a/src/classes/emitter.js +++ b/src/classes/emitter.js @@ -7,46 +7,88 @@ import Vector2D from "./vector2d.js"; class Emitter extends Entity { - constructor (x, y, velocity, particle) { + constructor (x, y, rate, velocity, particle) { super(x, y); this.particleVelocity = velocity; this.particleClass = particle; + + this.emitRate = rate; this.emitting = false; + this._lastEmitTime = this._creationTime; + this._wasEmitting = false; this.particles = []; this.spread = function () { - return Math.PI / 32; + return Math.PI / 1; } } + setParticleParent (entity) { + this._particleParent = entity; + } + + _emit () { + let ParticleClass = this.particleClass, + parent = this._particleParent || this._parent; + + let angle = this.particleVelocity.angle() + this.spread() - (Math.random() * this.spread() * 2), + magnitude = this.particleVelocity.length(), + velocity = Vector2D.fromAngle(angle, magnitude); + + let particle = new ParticleClass(this._calculatedPos.x, this._calculatedPos.y); + particle.velocity = velocity; + + this.particles.push(particle); + parent.addChildEntity(particle); + + } + + + _triggerEmissions () { + + // We prematurely call preprocess so that child particles can spawn from the emitters permission but be children of a different parent + // NK: This might cause a bug where child renders have an incorrect position because preprocess should normally be called after the update function but before the render, here it is before update. We'll see. + this._preprocess(); + if (this.emitting) { - let ParticleClass = this.particleClass; + let currentTime = +(new Date()); - let angle = this.particleVelocity.angle() + this.spread() - (Math.random() * this.spread() * 2), - magnitude = this.particleVelocity.length(), - velocity = Vector2D.fromAngle(angle, magnitude); + if (!this._wasEmitting) { + this._wasEmitting = true; + this._lastEmitTime = currentTime; + } - let particle = new ParticleClass(this.pos.x, this.pos.y); - particle.velocity = velocity; + // In honour the code of Alex Evans + let emitDelta = currentTime - this._lastEmitTime; + if (emitDelta > this.emitRate) { - this.particles.push(particle); - this._parent.addChildEntity(particle); + let emissions = ~~(emitDelta / this.emitRate); + this._lastEmitTime = currentTime + (emitDelta - (this.emitRate * emissions)); + + for (let i = 0; i < emissions; i++) { + this._emit(); + } + + } + + } else { + this._wasEmitting = false; } } update () { - this._emit(); + this._triggerEmissions(); } diff --git a/src/classes/entity.js b/src/classes/entity.js index 705b028..b21cce1 100644 --- a/src/classes/entity.js +++ b/src/classes/entity.js @@ -19,6 +19,8 @@ class Entity { this._game = null; this._parent = null; + this._creationTime = +(new Date()); + } @@ -130,6 +132,12 @@ class Entity { _updateEntity (delta) { + if (this.timeToLive) { + if (+(new Date()) - this._creationTime > this.timeToLive) { + this._parent.detachChildEntity(this); + } + } + // Calculate new position based on velocity and acceleration if there's one set if (this.velocity) {