Physics
willow can attach rigid bodies to nodes. A node with a body moves where the simulation puts it, so a falling crate is just a node you never move yourself.
How it fits together
- A physics root. Call
enablePhysics(config)on a container node. Everything below it shares one isolated world. Physics roots cannot nest. - Bodies. Call
setBody(definition)on a node under the root. The body starts at the node's current position and rotation. - Stepping. In a window app the scene steps every physics root once per logic tick. You can also step a root yourself with
stepPhysics(dt).
ts
import { Node, PhysicsConfig, PhysicsBox, PhysicsDynamic, PhysicsStatic, PhysicsBody } from "willow";
class Drop {
static main(): void {
const world: Node = new Node("world");
world.enablePhysics(new PhysicsConfig(Vec2{ x: 0.0, y: 900.0 }));
const floor: Node = new Node("floor");
floor.setPosition(200, 300);
world.add(floor);
floor.setBody(new PhysicsStatic(new PhysicsBox(400, 20)));
const crate: Node = new Node("crate");
crate.setPosition(200, 100);
world.add(crate);
crate.setBody(new PhysicsDynamic(new PhysicsBox(24, 24), 1, 0.5, 0.1));
for (let i: int = 0; i < 120; i++) {
world.stepPhysics(1 / 60);
}
console.log("crate rests at y = " + Math.round(crate.y));
const body: PhysicsBody | null = crate.getBody();
if (body !== null) {
body.applyImpulse(Vec2{ x: 0.0, y: -300.0 });
console.log("velocity after a kick: " + Math.round(body.velocity().y));
}
}
}Output:
text
crate rests at y = 278
velocity after a kick: -300The floor's top is at 290 (300 minus half its 20 px height), and the crate's center rests half its 24 px height above that. Boxes are centered on the node's position.
This sample runs without a window, which makes physics easy to test. In a window app, add world to engine.root2d, give the nodes sprites, and leave the stepping to the scene.
Bodies
| Definition | Moves by | Constructor |
|---|---|---|
PhysicsDynamic | Forces, impulses, gravity and collisions. | (shape, mass, friction?, elasticity?, moment?) |
PhysicsStatic | Never moves. Floors and walls. | (shape, friction?, elasticity?) |
PhysicsKinematic | Your code, through velocity or position. Ignores forces and gravity. Moving platforms. | (shape, friction?) |
elasticity is bounciness from 0 to 1. A moment of 0 (the default) is worked out from the shape and mass.
Shapes
| Shape | Constructor |
|---|---|
PhysicsCircle | (radius, offset?) |
PhysicsBox | (width, height, cornerRadius?), centered on the node |
PhysicsSegment | (a, b, radius?), a line between two points |
PhysicsPolygon | (verts, cornerRadius?), the convex hull of the points |
Driving a body
getBody() returns the live PhysicsBody (or null). It reads position(), angle(), velocity() and angularVelocity(), and changes them with setPosition, setAngle, setVelocity, setAngularVelocity, applyImpulse (an instant kick) and applyForce (a push until the next step).
setBodyEnabled(false) takes a body out of the simulation and keeps its state; removeBody() detaches it. disablePhysics() on the root removes every body below it.
World settings
PhysicsConfig(gravity?, iterations?, sleepTime?): gravity in pixels per second squared (positive y is down), solver iterations per step (0 means the default of 10), and how long a resting body waits before it sleeps (0 never sleeps).
Next
- Performance
- Reference: Physics