Simulate Torpedo and Hydrofoil Physics in Matter.js
Simulating an underwater torpedo with hydrofoil steering in Matter.js requires modeling three core physical phenomena: constant axial thrust (propulsion), anisotropic fluid drag (water resistance that permits forward motion while resisting sideways slippage), and dynamic hydrodynamic lift generated by steering hydrofoils. Because Matter.js is fundamentally a rigid-body physics engine built for dry environments, this guide details how to implement a custom update loop that calculates and applies these fluid forces to a body in real time.
1. Environment and Body Configuration
Water cancels out most or all of an object's weight through buoyancy. In Matter.js, set the world's vertical gravity to zero, or calculate an upward buoyant force equal to gravity for a neutrally buoyant vessel.
Initialize the torpedo as a rectangular or chamfered rigid body with realistic physical properties:
const { Engine, Render, Runner, Bodies, Composite, Body, Vector } = Matter;
// Create engine and disable global gravity to mimic neutral buoyancy
const engine = Engine.create({
gravity: { x: 0, y: 0, scale: 0 }
});
// Create the torpedo body
const torpedo = Bodies.rectangle(400, 300, 120, 24, {
density: 0.002,
frictionAir: 0, // Disable default uniform air resistance
friction: 0.1,
restitution: 0.1
});
Composite.add(engine.world, torpedo);2. Forward Propulsion (Thrust)
A torpedo's propeller provides continuous thrust along its longitudinal axis. To compute this, extract the forward directional vector from the torpedo's current rotation angle and scale it by the desired engine power.
function applyThrust(body, thrustPower) {
// Vector pointing along the torpedo's forward axis
const forwardVector = {
x: Math.cos(body.angle),
y: Math.sin(body.angle)
};
const force = Vector.mult(forwardVector, thrustPower);
Body.applyForce(body, body.position, force);
}3. Hydrodynamic Drag (Water Resistance)
Uniform linear damping (such as the default frictionAir)
makes a torpedo feel like it is floating in air rather than slicing
through water. Torpedoes encounter low drag along their streamlined
longitudinal axis and massive drag perpendicular to their hull (lateral
drag).
Deconstruct the body's velocity into forward and lateral components, apply separate drag coefficients to each, and damp the angular velocity:
function applyHydrodynamicDrag(body) {
const forwardVector = { x: Math.cos(body.angle), y: Math.sin(body.angle) };
const lateralVector = { x: -Math.sin(body.angle), y: Math.cos(body.angle) };
// Project current velocity onto forward and lateral axes
const forwardSpeed = Vector.dot(body.velocity, forwardVector);
const lateralSpeed = Vector.dot(body.velocity, lateralVector);
// Drag coefficients (drag increases quadratically or linearly with speed)
const forwardDragCoeff = 0.001;
const lateralDragCoeff = 0.05; // High resistance to sideways motion
const angularDragCoeff = 0.08; // High resistance to spinning
// Compute opposing drag forces
const forwardDragForce = Vector.mult(forwardVector, -forwardSpeed * forwardDragCoeff * Math.abs(forwardSpeed));
const lateralDragForce = Vector.mult(lateralVector, -lateralSpeed * lateralDragCoeff * Math.abs(lateralSpeed));
const totalDragForce = Vector.add(forwardDragForce, lateralDragForce);
// Apply translational and rotational damping
Body.applyForce(body, body.position, totalDragForce);
body.torque -= body.angularVelocity * angularDragCoeff * body.inertia;
}4. Hydrofoil Steering (Lift Mechanics)
Hydrofoils (fins or rudders) steer a vessel by redirecting water flow, which generates a lift force perpendicular to the relative flow direction. Because Matter.js calculates rotation through torque:
- Calculate the effective flow speed: Steering foils only work when water is moving over them (forward velocity).
- Compute the angle of attack: The angle between the incoming flow and the hydrofoil surface.
- Apply steering torque: The torque must be proportional to the deflection of the rudder and the forward speed.
let rudderAngle = 0; // Negative for left, positive for right (in radians)
function applyHydrofoilSteering(body, rudderAngle) {
const forwardVector = { x: Math.cos(body.angle), y: Math.sin(body.angle) };
const forwardSpeed = Vector.dot(body.velocity, forwardVector);
// Hydrofoils generate lift proportional to forward speed and fin deflection
const liftCoefficient = 0.0005;
const steeringTorque = rudderAngle * forwardSpeed * liftCoefficient * body.inertia;
// Apply torque to change the heading
body.torque += steeringTorque;
}5. Running the Physics Loop
Hook the force calculations into Matter.js's
beforeUpdate event. This ensures all fluid forces,
propulsion vectors, and hydrofoil adjustments are resolved directly
before collision detection and integration occur in each frame:
Matter.Events.on(engine, 'beforeUpdate', () => {
const thrustMagnitude = 0.004;
// 1. Push forward
applyThrust(torpedo, thrustMagnitude);
// 2. Dissipate lateral energy and spin
applyHydrodynamicDrag(torpedo);
// 3. Apply foil-induced turning based on user control
applyHydrofoilSteering(torpedo, rudderAngle);
});By balancing lateral drag and forward speed-dependent torque, the torpedo naturally follows curved trajectories without sliding sideways, accurately mirroring underwater fluid dynamics.