UNPKG

@dominicstop/utils

Version:

Yet another event emitter written in typescript.

117 lines (116 loc) 3.63 kB
import { Vector2D } from "../geometry"; export class Particle { get position() { return this._position; } ; set position(newValue) { this._position = newValue; this.shape.center = newValue.asPoint; } ; constructor(args) { this.shape = args.shape; this.id = args.id; this.position = args.position.clone(); this.previousPosition = args.position.clone(); this.mass = args.mass; this.inverseMass = (args.mass === 0 ? 0 : 1 / args.mass); this.velocity = args.initialVelocity ?? Vector2D.zero; this.acceleration = Vector2D.zero; this.isStatic = args.mass === 0; } ; clone() { const clone = new Particle({ id: this.id, position: this.position.clone(), shape: this.shape.clone(), mass: this.mass, initialVelocity: this.velocity.clone(), }); clone.previousPosition = this.previousPosition.clone(); return clone; } ; applyForce(force) { if (this.isStatic) return; const accelerationFromForce = force.multipliedByScalar(this.inverseMass); this.acceleration = this.acceleration.addedWithOther(accelerationFromForce); } ; update(deltaTime) { if (this.isStatic) return; this.previousPosition = this.position.clone(); // get change in velocity due to acceleration over the time step. const velocityDelta = this.acceleration.multipliedByScalar(deltaTime); this.velocity = this.velocity.addedWithOther(velocityDelta); // get change in position due to velocity over the time step. const positionDelta = this.velocity.multipliedByScalar(deltaTime); this.position = this.position.addedWithOther(positionDelta); } ; resetAcceleration() { this.acceleration = Vector2D.zero; } ; getSpeed() { return this.velocity.magnitude; } ; getKineticEnergy() { return 0.5 * this.mass * this.getSpeed() ** 2; } ; setPosition(newPosition) { this.previousPosition = this.position.clone(); this.position = newPosition; } ; setVelocity(newVelocity) { this.velocity = newVelocity; } ; setMass(newMass) { this.mass = newMass; this.inverseMass = ((newMass === 0) ? 0 : 1 / newMass); this.isStatic = newMass === 0; } ; isCollidingWithOther(other) { return this.shape.isCollidingWithOther(other.shape); } ; computeDistanceToOther(other) { return this.shape.computeDistanceToOther(other.shape); } ; computeOverlapVectorWith(other) { if (!this.isCollidingWithOther(other)) { return Vector2D.zero; } // Vector from other to this const direction = this.position.subtractedWithOther(other.position).normalized; // overlap depth (negative distance means overlap) const distance = this.computeDistanceToOther(other); const overlapDepth = -distance; return direction.multipliedByScalar(overlapDepth); } checkIsAtRest() { const restThreshold = 1e-5; return this.velocity.magnitude < restThreshold; } ; isEdgeToEdgeWithOther(other) { const distance = this.computeDistanceToOther(other); const epsilon = 1e-8; // Small tolerance for floating-point precision return Math.abs(distance) < epsilon && !this.isCollidingWithOther(other); } } ;