blaze-2d
Version:
A fast and simple WebGL 2 2D game engine written in TypeScript
229 lines • 7.28 kB
JavaScript
import { vec2 } from "gl-matrix";
import Object2D from "../object2d";
import { cross2D } from "../utils/vectors";
/**
* Represents an object in 2D world space that can experience physics.
*/
export default class PhysicsObject extends Object2D {
/**
* Creates a {@link PhysicsObject} with a mass and restitution.
*
* @param mass The mass of the object
* @param restitution The restituion (bounciness) of the object
*/
constructor(mass = 1, restitution = 0) {
super();
/**
* The gravitational froce applied to the object.
*/
this.gravity = vec2.fromValues(0, -9.8);
// PROPERTIES
/**
* Mass of object in kg.
*
* When set to 0 the object's mass is effectively infinite.
*/
this.mass = 1;
/**
* The inverse of the object's mass (1 / mass).
*/
this.inverseMass = 1;
/**
* Elasticity/bounciness
*
* This value should be between 0 and 1 for best results.
*/
this.restitution = 0;
/**
* Coefficient of static friction.
*
* This value should be between 0 and 1 for best results.
*
* @see [Static And Kinetic Friction](https://www.geeksforgeeks.org/static-and-kinetic-friction/)
*/
this.staticFriction = 0.1;
/**
* Coefficient of dynamic/kinetic friction.
*
* This value should be between 0 and 1 for best results.
*
* @see [Static And Kinetic Friction](https://www.geeksforgeeks.org/static-and-kinetic-friction/)
*/
this.dynamicFriction = 0.1;
// POSITIONAL MOMENTUM
/**
* The net force applied to the object in newtons.
*/
this.force = vec2.create();
/**
* The object's velocity in world space units (metres).
*/
this.velocity = vec2.create();
/**
* The damping applied to the object's linear velocity every physics update.
*/
this.airFriction = 0;
// ROTATIONAL MOMENTUM
/**
* The object's torque in newtons, can be thought of as rotational force.
*/
this.torque = 0;
/**
* The object's angular velocity in radians per second.
*/
this.angularVelocity = 0;
/**
* The object's moment of inertia (resistance to rotation).
*
* When set to 0 the object's inertia is effectively infinite.
*/
this.inertia = 1;
/**
* The inverse of the object's inertia (1 / inertia).
*/
this.inverseInertia = 1;
/**
* The damping applied to the object's angular velocity every physics update.
*/
this.angularDamping = 0;
// OPTIONS
/**
* Wether or not the object should take gravity from the physics world.
*/
this.takesGravity = true;
/**
* Wether or not the object's x position is locked.
*
* When true the object's x position will not be affected by collisions or dynamics.
*/
this.lockXAxis = false;
/**
* Wether or not the object's y position is locked.
*
* When true the object's y position will not be affected by collisions or dynamics.
*/
this.lockYAxis = false;
/**
* Wether or not the object can rotate.
*
* When true the object's rotation will not be affected by collisions or dynamics.
*/
this.lockRotation = false;
this.forceVec = vec2.create();
this.setMass(mass);
this.restitution = restitution;
this.setupEvents();
}
setupEvents() {
super.setupEvents();
}
/**
* Adds a force to the object's current total force vector.
*
* If no contact point is provided then the force will be applied at the
* object's centre, generating 0 torque.
*
* @param force The force vector to apply
* @param contact The local position on the body to apply the force at
*/
applyForce(force, contact) {
vec2.add(this.force, this.force, force);
if (contact) {
this.torque += contact[0] * force[1] - contact[1] * force[0];
}
}
/**
* Applies a force to the object at an angle.
*
* The direction vector is calculated from the unit y+ vector.
*
* If no contact point is provided then the force will be applied at the
* object's centre, generating 0 torque.
*
* @param force The force to apply in newtons
* @param angle The angle at which to apply the force in radians (world space)
* @param contact The local position on the body to apply the force at
*/
applyForceAtAngle(force, angle, contact) {
const dir = vec2.fromValues(0, 1);
vec2.rotate(dir, dir, vec2.create(), angle);
vec2.scale(this.forceVec, dir, force);
vec2.add(this.force, this.force, this.forceVec);
if (contact) {
this.torque += contact[0] * this.forceVec[1] - contact[1] * this.forceVec[0];
}
}
/**
* Applies an impulse to the physics object.
*
* This will apply an instantaneous change to the object's angular and linear velocity.
*
* @param impulse The impulse to apply
* @param contactVector A vector from the object's center to the contact point
*/
applyImpulse(impulse, contactVector) {
vec2.scaleAndAdd(this.velocity, this.velocity, impulse, this.inverseMass);
this.angularVelocity += this.inverseInertia * cross2D(contactVector, impulse);
}
/**
* Sets the mass of the object in kg.
*
* Also computes the inverse mass.
*
* **NOTE: Setting the mass to 0 will act as infinite mass.**
*
* @param mass The objects new mass
*/
setMass(mass) {
this.mass = mass;
this.inverseMass = mass === 0 ? 0 : 1 / mass;
if (mass === 0)
this.setInertia(0);
}
/**
* Gets the mass of the object.
*
* @returns The mass of the object
*/
getMass() {
return this.mass;
}
/**
* Gets the inverse mass of the object (1 / mass).
*
* @returns The inverse mass of the object
*/
getInverseMass() {
return this.inverseMass;
}
/**
* Sets the moment of inertia of the object.
*
* Also computes the inverse inertia.
*
* **NOTE: Setting the inertia to 0 will act as infinite inertia.**
*
* @param inertia The objects new inertia
*/
setInertia(inertia) {
this.inertia = inertia;
this.inverseInertia = inertia === 0 ? 0 : 1 / inertia;
}
/**
* Gets the moment of inertia of the object.
*
* @returns The inertia of the object
*/
getInertia() {
return this.inertia;
}
/**
* Gets the inverse moment of inertia of the object (1 / inertia).
*
* @returns The inverse inertia of the object
*/
getInverseInertia() {
return this.inverseInertia;
}
}
//# sourceMappingURL=object.js.map