clone

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

main
marbles / tests / collision_continuity_test.ts
collision_continuity_test.ts 1.6K
1import { assert, assertEquals } from "@std/assert";2import { channelProxies, segmentProxies } from "../src/gen/endless/proxies.ts";3import type { LoopPath } from "../src/shared/types.ts";45const separated: LoopPath = {6 segments: [0, 10].map((x) => ({7 placementIndex: -1,8 curve: [{9 kind: "line" as const,10 a: [x, 0, 0] as const,11 b: [x, 0, 4] as const,12 }],13 length: 4,14 })),15 totalLength: 8,16};1718function noBridge(mesh: { vertices: number[]; indices: number[] }): void {19 for (let i = 0; i < mesh.indices.length; i += 3) {20 const xs = mesh.indices.slice(i, i + 3).map((v) => mesh.vertices[v * 3]);21 assert(22 Math.max(...xs) - Math.min(...xs) < 2,23 "a triangle bridges independent lanes",24 );25 }26}2728Deno.test("disconnected lanes emit separate ribbons with no invisible bridge", () => {29 const meshes = channelProxies(separated).filter((p) => p.kind === "mesh");30 assertEquals(meshes.length, 2);31 meshes.forEach(noBridge);32});3334Deno.test("connected windows retain a continuous ribbon", () => {35 const path: LoopPath = {36 ...separated,37 segments: [0, 4].map((z) => ({38 placementIndex: -1,39 curve: [{ kind: "line", a: [0, 0, z], b: [0, 0, z + 4] }],40 length: 4,41 })),42 };43 assertEquals(channelProxies(path).filter((p) => p.kind === "mesh").length, 1);44});4546Deno.test("packed segment meshes retain disconnected topology", () => {47 const meshes = segmentProxies({48 path: separated,49 pieceFamilies: ["straight", "straight"],50 windowMods: [null, null],51 }).filter((p) => p.kind === "mesh");52 assertEquals(meshes.length, 1);53 noBridge(meshes[0]);54});