proton-engine
Version:
Proton is a simple and powerful javascript particle animation engine.
122 lines (108 loc) • 3.53 kB
JavaScript
import Util from "../utils/Util";
import Vector2D from "../math/Vector2D";
import Behaviour from "./Behaviour";
export default class Collision extends Behaviour {
/**
* The callback after collision
*
* @callback Callback
*
* @param {Proton.Particle} particle
* @param {Proton.Paritcle} otherParticle
*/
/**
* @memberof! Proton#
* @augments Proton.Behaviour
* @constructor
* @alias Proton.Collision
*
* @todo add description to mass
*
* @param {Proton.Emitter} [emitter=null] the attraction point coordinates
* @param {Boolean} [mass=true]
* @param {Callback} [callback=null] the callback after the collision
* @param {Number} [life=Infinity] this behaviour's life
* @param {String} [easing=ease.easeLinear] this behaviour's easing
*
* @property {String} name The Behaviour name
*/
constructor(emitter, mass, callback, life, easing) {
super(life, easing);
this.reset(emitter, mass, callback);
this.newPool = [];
this.pool = [];
this.name = "Collision";
}
/**
* Reset this behaviour's parameters
*
* @memberof Proton#Proton.Collision
* @method reset
* @instance
*
* @todo add description to mass
*
* @param {Proton.Emitter} [emitter=null] the attraction point coordinates
* @param {Boolean} [mass=true]
* @param {Callback} [callback=null] the callback after the collision
* @param {Number} [life=Infinity] this behaviour's life
* @param {String} [easing=ease.easeLinear] this behaviour's easing
*/
reset(emitter, mass, callback, life, easing) {
this.emitter = Util.initValue(emitter, null);
this.mass = Util.initValue(mass, true);
this.callback = Util.initValue(callback, null);
this.collisionPool = [];
this.delta = new Vector2D();
life && super.reset(life, easing);
}
/**
* Apply this behaviour for all particles every time
*
* @memberof Proton#Proton.Collision
* @method applyBehaviour
* @instance
*
* @param {Proton.Particle} particle
* @param {Number} time the integrate time 1/ms
* @param {Int} index the particle index
*/
applyBehaviour(particle, time, index) {
if (this.emitter) {
Util.sliceArray(this.emitter.particles, index, this.newPool);
} else {
Util.sliceArray(this.pool, index, this.newPool);
}
const length = this.newPool.length;
let otherParticle;
let lengthSq;
let overlap;
let totalMass;
let averageMass1, averageMass2;
let i;
for (i = 0; i < length; i++) {
otherParticle = this.newPool[i];
if (otherParticle !== particle) {
this.delta.copy(otherParticle.p);
this.delta.sub(particle.p);
lengthSq = this.delta.lengthSq();
const distance = particle.radius + otherParticle.radius;
if (lengthSq <= distance * distance) {
overlap = distance - Math.sqrt(lengthSq);
overlap += 0.5;
totalMass = particle.mass + otherParticle.mass;
averageMass1 = this.mass ? otherParticle.mass / totalMass : 0.5;
averageMass2 = this.mass ? particle.mass / totalMass : 0.5;
particle.p.add(
this.delta
.clone()
.normalize()
.multiplyScalar(overlap * -averageMass1)
);
otherParticle.p.add(this.delta.normalize().multiplyScalar(overlap * averageMass2));
this.callback && this.callback(particle, otherParticle);
}
}
}
}
}