clone

an endless marble-race generator in the browser; the url is the seed, so every track can be shared

main
marbles / tools / physics-debug / phys-contact.ts
phys-contact.ts 2.6K
1import { EndlessWorld } from "/Users/dami/Developer/marbles/src/gen/endless/world.ts";2import {3 channelProxies,4 islandProxies,5} from "/Users/dami/Developer/marbles/src/gen/endless/proxies.ts";6const catalog = {7 packs: [{8 slug: "nature-kit",9 ids: JSON.parse(10 Deno.readTextFileSync(11 "/Users/dami/Developer/marbles/assets/nature-kit.manifest.json",12 ),13 ).pieces.map((p: { id: string }) => p.id),14 }],15};16const seed = Deno.args[0];17const M = Deno.args.slice(1, 4).map(Number);18const R = 0.21;19const w = new EndlessWorld(seed, catalog);20for (let i = 0; i < 8; i++) {21 const seg = w.get(i);22 const all = [23 ...channelProxies(seg.path),24 ...seg.islands.flatMap((x) => islandProxies(x.placements)),25 ];26 for (const p of all) {27 if (p.kind === "mesh" || p.kind === "bumper") continue;28 // Transform marble into slab local frame (yaw then pitch inverse).29 const dx = M[0] - p.center[0],30 dy = M[1] - p.center[1],31 dz = M[2] - p.center[2];32 const yaw = p.kind === "slab" ? p.yaw : 0;33 const pitch = p.kind === "slab" ? p.pitch : 0;34 // inverse yaw35 let lx = Math.cos(-yaw) * dx + Math.sin(-yaw) * dz * -1;36 let lz = -Math.sin(yaw) * dx * -1 + Math.cos(yaw) * dz;37 // careful: rotation about y by yaw maps local→world: wx = cos? use standard: world = Ry(yaw)·local where Ry: x' = x cos + z sin, z' = -x sin + z cos... our convention: local z → (sin yaw, cos yaw). So world = [x cos yaw + z sin yaw, y, -x sin yaw + z cos yaw]. Inverse: local = [wx cos yaw - wz sin yaw, y, wx sin yaw + wz cos yaw].38 lx = dx * Math.cos(yaw) - dz * Math.sin(yaw);39 lz = dx * Math.sin(yaw) + dz * Math.cos(yaw);40 let ly = dy;41 // inverse pitch about x: local = [x, y cos p - z ... ] Rx(pitch): y' = y cos - z sin, z' = y sin + z cos. Inverse: y = ly cos + lz2 sin...42 const cy2 = ly * Math.cos(pitch) + lz * Math.sin(pitch) * -1 * -1;43 const cz2 = -ly * Math.sin(pitch) * -1 * -1 + lz * Math.cos(pitch);44 ly = ly * Math.cos(pitch) + lz * Math.sin(pitch);45 lz = cz2 === lz46 ? lz47 : (-(M[1] - p.center[1]) * Math.sin(pitch) + lz * Math.cos(pitch));48 void cy2;49 const ex = Math.max(Math.abs(lx) - p.half[0], 0);50 const ey = Math.max(Math.abs(ly) - p.half[1], 0);51 const ez = Math.max(Math.abs(lz) - p.half[2], 0);52 const d = Math.hypot(ex, ey, ez);53 if (d < R) {54 console.log(55 `${p.kind} CONTACT d=${d.toFixed(3)} c=(${56 p.center.map((v) => v.toFixed(2))57 }) h=(${p.half.map((v) => v.toFixed(2))}) yaw=${58 (p.kind === "slab" ? p.yaw : 0).toFixed(2)59 } pitch=${(p.kind === "slab" ? p.pitch : 0).toFixed(2)}`,60 );61 }62 }63}