blaze-2d
Version:
A fast and simple WebGL 2 2D game engine written in TypeScript
84 lines • 3.91 kB
JavaScript
import { vec2 } from "gl-matrix";
import { cross2DWithScalar } from "../../../utils/vectors";
import Physics from "../../physics";
// initialise needed vectors
const impulse = vec2.create();
const negImpulse = vec2.create();
const tangentImpulse = vec2.create();
const reverseTangentImpulse = vec2.create();
/**
* Solves the impulse for a collision described by a {@link Manifold}.
*
* @param m {@link Manifold} describing the collision to solve the impulse for
*/
export default function solveImpulse(m) {
// don't resolve impulse if both objects have infinite mass
if (m.a.getInverseMass() === 0 && m.b.getInverseMass() === 0)
return;
for (const contact of m.contactPoints) {
// calculate contact vectors
const contactA = contact.contactA;
const contactB = contact.contactB;
let relativeVelocity = calculateRelativeVelocity(m, contactA, contactB);
// calculate relative velocity in terms of normal direction
const contactVelocity = vec2.dot(relativeVelocity, contact.normal);
// do not resolve if velocities are seperating
// if (contactVelocity > 0) return;
let deltaImpulseNormal = contact.massNormal * (-contactVelocity + contact.bias);
if (Physics.G_CONF.ACUMMULATE_IMPULSE) {
// clamp the accumulated impulse
const old = contact.impulseNormal;
contact.impulseNormal = Math.max(old + deltaImpulseNormal, 0);
deltaImpulseNormal = contact.impulseNormal - old;
}
else {
deltaImpulseNormal = Math.max(deltaImpulseNormal, 0);
}
// apply impulse
vec2.scale(impulse, contact.normal, deltaImpulseNormal);
m.a.applyImpulse(vec2.negate(negImpulse, impulse), contactA);
m.b.applyImpulse(impulse, contactB);
// friction impulse
relativeVelocity = calculateRelativeVelocity(m, contactA, contactB);
const velTangent = vec2.dot(relativeVelocity, contact.tangent);
let deltaImpulseTangent = contact.massTangent * -velTangent;
if (Physics.G_CONF.ACUMMULATE_IMPULSE) {
// compute friction impulse
const maxImpulseTangent = m.df * contact.impulseNormal;
// clamp friction
const old = contact.impulseTangent;
contact.impulseTangent = Math.max(-maxImpulseTangent, Math.min(maxImpulseTangent, old + deltaImpulseTangent));
deltaImpulseTangent = contact.impulseTangent - old;
}
else {
const maxImpulseTangent = m.df * deltaImpulseNormal;
deltaImpulseTangent = Math.max(-maxImpulseTangent, Math.min(maxImpulseTangent, deltaImpulseTangent));
}
// apply friction impulse
vec2.scale(tangentImpulse, contact.tangent, deltaImpulseTangent);
vec2.negate(reverseTangentImpulse, tangentImpulse);
m.a.applyImpulse(reverseTangentImpulse, contactA);
m.b.applyImpulse(tangentImpulse, contactB);
}
}
// initialise vectors
const angularCrossContactA = vec2.create();
const angularCrossContactB = vec2.create();
const rVelA = vec2.create();
const rVelB = vec2.create();
const relativeVelocity = vec2.create();
/**
* Calculates the relative velocity for the impulse resolution of a collision between 2 {@link CollisionObject}s.
*
* @param m The manifold of the collision between **a** and **b**
* @param contactA The contact point on **a**
* @param contactB The contact point on **b**
*/
export function calculateRelativeVelocity(m, contactA, contactB) {
cross2DWithScalar(angularCrossContactA, contactA, m.a.angularVelocity);
cross2DWithScalar(angularCrossContactB, contactB, -m.b.angularVelocity);
vec2.sub(rVelA, m.a.velocity, angularCrossContactA);
vec2.add(rVelB, m.b.velocity, angularCrossContactB);
return vec2.sub(relativeVelocity, rVelB, rVelA);
}
//# sourceMappingURL=impulse.js.map