threeplay threeplay

Examples / physics-sandbox

Physics sandbox

Rapier does the heavy lifting; threeplay gives every object a rigid body with one component. Clicks are raycast against the scene, so onClick works on 3D objects like it does on sprites in kaplay.

physics-sandbox/main.js

Source

examples/physics-sandbox/main.js
// Physics sandbox: knock over a tower, spawn shapes, flick things around.
// Shows dynamic bodies, impulses, onClick on 3D objects and orbitCamera.
import threeplay from "threeplay";

threeplay({
  width: 960,
  height: 540,
  background: "#f1faee",
});

const PALETTE = ["#e63946", "#457b9d", "#f4a261", "#2a9d8f", "#8338ec"];

function spawnShape(at) {
  const shape = choose([box(1, 1, 1), sphere(0.55), cylinder(0.5, 1), capsule(0.4, 1.4)]);
  add([
    shape,
    pos(at),
    rotate(rand(360), rand(360), 0),
    color(choose(PALETTE)),
    area({ restitution: 0.3 }),
    body(),
    lifespan(30, { fade: 1 }),
    opacity(1),
    "prop",
  ]);
}

scene("sandbox", () => {
  setGravity(9.81);
  add([box(30, 1, 30), pos(0, -0.5, 0), color("#a8dadc"), area(), body({ isStatic: true })]);

  // A tower of crates.
  for (let y = 0; y < 6; y++) {
    for (let x = -1; x <= 1; x++) {
      add([
        box(1, 1, 1),
        pos(x * 1.05, 0.5 + y * 1.02, 0),
        color(PALETTE[(x + y + 3) % 5]),
        area(),
        body({ mass: 1 }),
        "prop",
      ]);
    }
  }
  const ball = add([
    sphere(0.7),
    pos(0, 0.7, 8),
    color("#1d3557"),
    area({ restitution: 0.5 }),
    body({ mass: 6 }),
    "prop",
    "ball",
  ]);

  orbitCamera({ target: vec3(0, 2, 0), distance: 16 });
  add([
    text("Click a shape to flick it · space: spawn · B: bowl the ball · R: reset · drag to orbit", {
      size: 15,
    }),
    pos(20, 16),
    fixed(),
  ]);
  const counter = add([text("", { size: 15 }), pos(20, 40), fixed()]);
  onUpdate(() => {
    counter.text = `${get("prop").length} bodies`;
  });

  onClick("prop", (obj) => {
    const push = camForward().multiplyScalar(6 * (obj.is("ball") ? 6 : 1));
    obj.applyImpulse(push.add(vec3(0, 3, 0)));
  });
  onKeyPress("space", () => spawnShape(vec3(rand(-3, 3), 10, rand(-3, 3))));
  onKeyPress("b", () => {
    ball.teleport(vec3(0, 0.7, 8));
    ball.applyImpulse(vec3(0, 0, -150));
  });
  onKeyPress("r", () => go("sandbox"));
});

go("sandbox");