blaze-2d
Version:
A fast and simple WebGL 2 2D game engine written in TypeScript
132 lines • 4.46 kB
JavaScript
import { vec2 } from "gl-matrix";
import CircleCollider from "../collider/circle";
import RigidBody from "../rigidbody";
import solveForces from "../solvers/dynamics/forces";
const diff = vec2.create();
const dir = vec2.create();
const negDir = vec2.create();
export default class Particle extends RigidBody {
/**
* Creates a {@link Particle}.
*
* @param radius The radius of the particle
* @param mass The mass of the particle
*/
constructor(radius, mass) {
const collider = new CircleCollider(radius);
super(collider, mass);
this.dx = vec2.create();
this.posPrev = vec2.create();
this.radius = radius;
this.lockRotation = true;
this.density = 0;
this.densityNear = 0;
this.pressure = 0;
this.pressureNear = 0;
this.neighbours = [];
}
/**
* Finds particles which are closer to this particle than the fluid's smoothing radius.
*
* Particles which are closer than this distance are added to this particle's neighbours array.
*
* @param kdTree The {@link kdTree} of the fluid
* @param smoothingRadius The fluid's smoothing radius
* @param smoothingRadiusSqr The fluid's smoothing radius squared
*/
findNeighbours(kdTree, smoothingRadius, smoothingRadiusSqr) {
this.neighbours = kdTree.findNeighbours(this, smoothingRadius, smoothingRadiusSqr);
}
/**
* Computes the density and density near of the particle based on it's neighbours.
*
* @param smoothingRadius The smoothing radius of the fluid
*/
computeDoubleDensityRelaxation(smoothingRadius) {
let diffLen = 0;
let q = 0;
let qFlip = 0;
let qFlipSqr = 0;
this.density = 0;
this.densityNear = 0;
for (const n of this.neighbours) {
vec2.sub(diff, n.getPosition(), this.getPosition());
diffLen = vec2.len(diff);
q = diffLen / smoothingRadius;
if (q < 1) {
qFlip = 1 - q;
qFlipSqr = Math.pow(qFlip, 2);
this.density += qFlipSqr;
this.densityNear += qFlipSqr * qFlip;
}
}
}
/**
* Calculate the pressure the particle based on it's neighbours.
*
* @param restDensity The rest density of the fluid
*/
computePressure(stiffness, stiffnessNear, restDensity) {
this.pressure = stiffness * (this.density - restDensity);
this.pressureNear = stiffnessNear * this.densityNear;
}
/**
* Advanced the particle's position.
*
* @param delta The time since the last update
* @param smoothingRadius The smoothing radius of the fluid
*/
advancePosition(delta, smoothingRadius) {
let diffLen = 0;
let q = 0;
let qFlip = 0;
let qFlipSqr = 0;
vec2.zero(this.dx);
for (const n of this.neighbours) {
vec2.sub(diff, n.getPosition(), this.getPosition());
diffLen = vec2.len(diff);
q = diffLen / smoothingRadius;
if (q < 1) {
qFlip = 1 - q;
qFlipSqr = Math.pow(qFlip, 2);
vec2.normalize(dir, diff);
vec2.scale(dir, dir, delta * delta * (this.pressure * qFlip + this.pressureNear * qFlipSqr) * 0.5);
this.translate(vec2.negate(negDir, dir));
n.translate(dir);
vec2.sub(this.dx, this.dx, dir);
}
}
this.translate(this.dx);
}
/**
* Comptues the particle's new velocity and performs the second force solving pass.
*
* @param delta The time since the last update
* @param gravity The physics world's gravity vector
*/
computeNewVelocity(delta, gravity) {
// compute new velocity
vec2.sub(this.velocity, this.getPosition(), this.posPrev);
vec2.scale(this.velocity, this.velocity, 1 / delta);
// integrate forces
solveForces(this, delta, gravity);
}
/**
* Sets the particle's radius.
*
* @param radius The particle's new radius
*/
setRadius(radius) {
this.radius = radius;
this.collider.setRadius(radius);
}
/**
* Gets the radius of the particle.
*
* @returns The particle's radius
*/
getRadius() {
return this.radius;
}
}
//# sourceMappingURL=particle.js.map