From ffa2ef97e092b4088f3934c25691e950604b5447 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 15 Feb 2025 16:04:30 -0700 Subject: [PATCH] train car occupied segment tracking --- .temp/deno.lock | 10 +++--- .temp/temp.json | 1 + src/main.ts | 3 +- src/state/states/RunningState.ts | 5 ++- src/track/system.ts | 57 +++++++++++++++++++++++--------- src/train/train.ts | 35 +++++++++++++++----- 6 files changed, 80 insertions(+), 31 deletions(-) create mode 100644 .temp/temp.json diff --git a/.temp/deno.lock b/.temp/deno.lock index a0975ed..9aa9b88 100644 --- a/.temp/deno.lock +++ b/.temp/deno.lock @@ -1,7 +1,6 @@ { "version": "4", "specifiers": { - "jsr:@bearmetal/doodler@0.0.5-b": "0.0.5-b", "jsr:@luca/esbuild-deno-loader@*": "0.11.0", "jsr:@luca/esbuild-deno-loader@0.11.1": "0.11.1", "jsr:@std/assert@*": "1.0.10", @@ -25,9 +24,6 @@ "@bearmetal/doodler@0.0.4": { "integrity": "b631083cff84994c513f70d1f09e6a9256edabcb224112c93a9ca6a87c88a389" }, - "@bearmetal/doodler@0.0.5-b": { - "integrity": "94f265ea21162f943291526800de7f3f6560634a4fe762a38cd73892685b6742" - }, "@luca/esbuild-deno-loader@0.11.0": { "integrity": "c05a989aa7c4ee6992a27be5f15cfc5be12834cab7ff84cabb47313737c51a2c", "dependencies": [ @@ -208,7 +204,11 @@ ] } }, + "redirects": { + "https://deno.land/x/clipboard/mod.ts": "https://deno.land/x/clipboard@v0.0.3/mod.ts" + }, "remote": { + "https://deno.land/x/clipboard@v0.0.3/mod.ts": "5b68fe3b710b852de5273c135fc3c11b2b4050577401ee994161380bd8cab219", "https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/canvas.ts": "aadfb4b2e9acce34d4a5da3f9027be642c93229bbfc2641cb55301542cbb87bf", "https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/geometry/constants.ts": "4f4cf7bf49ac871d984e9b43896783b0cc8ab0ea60d0fc4c8c582f7e00c3df5a", "https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/geometry/vector.ts": "a08ecff64c5436a28c6451a31c68fc912d25f941aabafb79418fa0a1aeffa9d2", @@ -232,7 +232,7 @@ }, "workspace": { "dependencies": [ - "jsr:@bearmetal/doodler@0.0.5-b" + "jsr:@bearmetal/doodler@0.0.5" ] } } diff --git a/.temp/temp.json b/.temp/temp.json new file mode 100644 index 0000000..dd14ceb --- /dev/null +++ b/.temp/temp.json @@ -0,0 +1 @@ +[{"p":[[200,24,0],[233,24,0],[264.87555226753926,32.541028488383176,0],[293.45439059242574,49.041028488383176,0]],"id":"11d7561a-3172-4ad7-9d53-6f65f49ce8c3","bNeighbors":["93e4d69d-10f2-4ecc-a4d0-560ee71708e8"],"fNeighbors":["e44c3a93-01f0-42f1-aee9-939cbde5903b"]},{"p":[[293.45439059242574,49.041028488383176,0],[322.0332289173122,65.54102848838318,0],[345.3677526964683,88.87555226753923,0],[361.8677526964683,117.45439059242571,0]],"id":"e44c3a93-01f0-42f1-aee9-939cbde5903b","bNeighbors":["11d7561a-3172-4ad7-9d53-6f65f49ce8c3"],"fNeighbors":["bf9833f2-fd66-45fb-924d-f40b7c863c26"]},{"p":[[361.8677526964683,117.45439059242571,0],[378.3677526964683,146.0332289173122,0],[386.9087811848515,177.90878118485145,0],[386.9087811848515,210.90878118485148,0]],"id":"bf9833f2-fd66-45fb-924d-f40b7c863c26","bNeighbors":["e44c3a93-01f0-42f1-aee9-939cbde5903b"],"fNeighbors":["081c81f3-8fe7-4c71-babd-1d02d52c3385"]},{"p":[[386.9087811848515,210.90878118485148,0],[386.9087811848515,243.90878118485148,0],[378.3677526964683,275.78433345239074,0],[361.8677526964683,304.3631717772772,0]],"id":"081c81f3-8fe7-4c71-babd-1d02d52c3385","bNeighbors":["bf9833f2-fd66-45fb-924d-f40b7c863c26"],"fNeighbors":["d1380635-1dba-4180-8038-931289a56d17"]},{"p":[[361.8677526964683,304.3631717772772,0],[345.3677526964683,332.9420101021637,0],[322.0332289173122,356.2765338813198,0],[293.45439059242574,372.7765338813198,0]],"id":"d1380635-1dba-4180-8038-931289a56d17","bNeighbors":["081c81f3-8fe7-4c71-babd-1d02d52c3385"],"fNeighbors":["8fe94c53-c0be-4f0d-986b-f37e143e62d7"]},{"p":[[293.45439059242574,372.7765338813198,0],[264.87555226753926,389.2765338813198,0],[233,397.81756236970296,0],[200,397.81756236970296,0]],"id":"8fe94c53-c0be-4f0d-986b-f37e143e62d7","bNeighbors":["d1380635-1dba-4180-8038-931289a56d17"],"fNeighbors":["1542c063-b548-4d27-9fd8-c7a8344b05cb"]},{"p":[[200,397.81756236970296,0],[167,397.81756236970296,0],[135.12444773246074,389.2765338813198,0],[106.54560940757426,372.7765338813198,0]],"id":"1542c063-b548-4d27-9fd8-c7a8344b05cb","bNeighbors":["8fe94c53-c0be-4f0d-986b-f37e143e62d7"],"fNeighbors":["9be20051-651f-4cca-b6f1-ca80d5db7635"]},{"p":[[106.54560940757426,372.7765338813198,0],[77.96677108268779,356.2765338813198,0],[54.6322473035317,332.94201010216375,0],[38.1322473035317,304.3631717772772,0]],"id":"9be20051-651f-4cca-b6f1-ca80d5db7635","bNeighbors":["1542c063-b548-4d27-9fd8-c7a8344b05cb"],"fNeighbors":["4b7ff960-9fe7-48b3-b64e-9e32f60b0d2f"]},{"p":[[38.1322473035317,304.3631717772772,0],[21.632247303531692,275.7843334523908,0],[13.091218815148487,243.9087811848515,0],[13.09121881514848,210.90878118485153,0]],"id":"4b7ff960-9fe7-48b3-b64e-9e32f60b0d2f","bNeighbors":["9be20051-651f-4cca-b6f1-ca80d5db7635"],"fNeighbors":["0c481aa2-92de-4517-8e76-6c3f163f3dde"]},{"p":[[13.09121881514848,210.90878118485153,0],[13.091218815148467,177.90878118485153,0],[21.632247303531646,146.03322891731227,0],[38.132247303531635,117.45439059242577,0]],"id":"0c481aa2-92de-4517-8e76-6c3f163f3dde","bNeighbors":["4b7ff960-9fe7-48b3-b64e-9e32f60b0d2f"],"fNeighbors":["c62384ad-3fec-4479-9596-1173a6e651bb"]},{"p":[[38.132247303531635,117.45439059242577,0],[54.63224730353162,88.87555226753928,0],[77.96677108268767,65.54102848838318,0],[106.54560940757415,49.041028488383176,0]],"id":"c62384ad-3fec-4479-9596-1173a6e651bb","bNeighbors":["0c481aa2-92de-4517-8e76-6c3f163f3dde"],"fNeighbors":["93e4d69d-10f2-4ecc-a4d0-560ee71708e8"]},{"p":[[106.54560940757415,49.041028488383176,0],[135.12444773246062,32.541028488383176,0],[166.9999999999999,23.99999999999997,0],[199.9999999999999,23.99999999999997,0]],"id":"93e4d69d-10f2-4ecc-a4d0-560ee71708e8","bNeighbors":["c62384ad-3fec-4479-9596-1173a6e651bb"],"fNeighbors":["11d7561a-3172-4ad7-9d53-6f65f49ce8c3"]}] \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index a9840d8..dd33d00 100644 --- a/src/main.ts +++ b/src/main.ts @@ -41,8 +41,7 @@ setDefaultContext({ inputManager, doodler, resources, - debug: true, - showEnds: true, + debug: false, colors, }); diff --git a/src/state/states/RunningState.ts b/src/state/states/RunningState.ts index 1bf14c0..353ba67 100644 --- a/src/state/states/RunningState.ts +++ b/src/state/states/RunningState.ts @@ -61,7 +61,7 @@ export class RunningState extends State { const train = new Train(track.path, [new RedEngine(), new Tender()]); ctx.trains.push(train); }); - // const trainCount = 2000; + // const trainCount = 1000; // for (let i = 0; i < trainCount; i++) { // const train = new Train(track.path, [new RedEngine(), new Tender()]); // ctx.trains.push(train); @@ -72,6 +72,9 @@ export class RunningState extends State { for (const train of trains) { train.speed += 1; } + // for (const [i, train] of trains.entries()) { + // train.speed += .01 * i; + // } }); inputManager.onKey("ArrowDown", () => { const trains = getContextItem("trains"); diff --git a/src/track/system.ts b/src/track/system.ts index 5829e9a..e49fc97 100644 --- a/src/track/system.ts +++ b/src/track/system.ts @@ -164,7 +164,7 @@ export class TrackSystem { generatePath() { if (!this.firstSegment) throw new Error("No first segment"); - const flags = { looping: true }; + const flags = { looping: false }; const rightOnlyPath = [ this.firstSegment.copy(), ...this.findRightPath( @@ -276,15 +276,19 @@ export class TrackSegment extends PathSegment { doodler: Doodler; normalPoints: Vector[] = []; antiNormalPoints: Vector[] = []; + evenPoints: [Vector, number][] = []; constructor(p: VectorSet, id?: string) { super(p); this.doodler = getContextItem("doodler"); this.id = id ?? crypto.randomUUID(); this.recalculateRailPoints(); + + const spacing = Math.ceil(this.length / 10); + this.evenPoints = this.calculateEvenlySpacedPoints(this.length / spacing); } - recalculateRailPoints(resolution = 100) { + recalculateRailPoints(resolution = 60) { this.normalPoints = []; this.antiNormalPoints = []; for (let i = 0; i <= resolution; i++) { @@ -330,12 +334,12 @@ export class TrackSegment extends PathSegment { }); } - const spacing = Math.ceil(this.length / 10); - const points = this.calculateEvenlySpacedPoints(this.length / spacing); - for (let i = 0; i < points.length - 1; i++) { + // const spacing = Math.ceil(this.length / 10); + // const points = this.calculateEvenlySpacedPoints(this.length / spacing); + for (let i = 0; i < this.evenPoints.length - 1; i++) { // const t = i / ties; // const p = this.getPointAtT(t); - const [p, t] = points[i]; + const [p, t] = this.evenPoints[i]; // this.doodler.drawCircle(p, 2, { // color: "red", // weight: 3, @@ -480,11 +484,17 @@ export class TrackSegment extends PathSegment { } } +interface PathPoint { + p: Vector; + segmentId: string; + tangent: Vector; +} + export class Spline { segments: T[] = []; ctx?: CanvasRenderingContext2D; - evenPoints: Vector[]; + evenPoints: PathPoint[]; pointSpacing: number; get points() { @@ -534,13 +544,17 @@ export class Spline { } } - calculateEvenlySpacedPoints(spacing: number, resolution = 1) { + calculateEvenlySpacedPoints(spacing: number, resolution = 1): PathPoint[] { this.pointSpacing = 1; // return this.segments.flatMap(s => s.calculateEvenlySpacedPoints(spacing, resolution)); - const points: Vector[] = []; + const points: PathPoint[] = []; - points.push(this.segments[0].points[0]); - let prev = points[0]; + points.push({ + p: this.segments[0].points[0], + segmentId: this.segments[0].id, + tangent: this.segments[0].tangent(0), + }); + let prev = points[0].p; let distSinceLastEvenPoint = 0; for (const seg of this.segments) { let t = 0; @@ -558,8 +572,13 @@ export class Spline { Vector.sub(point, prev).normalize().mult(overshoot), ); distSinceLastEvenPoint = overshoot; - points.push(evenPoint); + points.push({ + p: evenPoint, + segmentId: seg.id, + tangent: seg.tangent(t), + }); prev = evenPoint; + continue; } prev = point; @@ -571,13 +590,17 @@ export class Spline { return points; } - followEvenPoints(t: number) { + followEvenPoints(t: number): PathPoint { if (this.looped) { if (t < 0) t += this.evenPoints.length; const i = Math.floor(t) % this.evenPoints.length; const a = this.evenPoints[i]; const b = this.evenPoints[(i + 1) % this.evenPoints.length]; - return Vector.lerp(a, b, t % 1); + return { + p: Vector.lerp(a.p, b.p, t % 1), + segmentId: b.segmentId, + tangent: b.tangent, + }; } t = clamp(t, 0, this.evenPoints.length - 1); const i = clamp(Math.floor(t), 0, this.evenPoints.length - 1); @@ -586,7 +609,11 @@ export class Spline { .evenPoints[ clamp((i + 1) % this.evenPoints.length, 0, this.evenPoints.length - 1) ]; - return Vector.lerp(a, b, t % 1); + return { + p: Vector.lerp(a.p, b.p, t % 1), + segmentId: b.segmentId, + tangent: b.tangent, + }; } calculateApproxLength() { diff --git a/src/train/train.ts b/src/train/train.ts index 133414b..4b50384 100644 --- a/src/train/train.ts +++ b/src/train/train.ts @@ -5,6 +5,7 @@ import { getContext, getContextItem } from "../lib/context.ts"; import { Doodler, Vector } from "@bearmetal/doodler"; import { Spline, TrackSegment } from "../track/system.ts"; import { ResourceManager } from "../lib/resources.ts"; +import { map } from "../math/lerp.ts"; export class Train { nodes: Vector[] = []; @@ -19,6 +20,10 @@ export class Train { speed = 10; + get segments() { + return Array.from(new Set(this.cars.flatMap((c) => c.segments))); + } + constructor(track: Spline, cars: TrainCar[]) { this.path = track; this.t = 0; @@ -47,8 +52,9 @@ export class Train { const a = this.path.followEvenPoints(this.t - currentOffset); currentOffset += car.length; const b = this.path.followEvenPoints(this.t - currentOffset); - car.points = [a, b]; - this.nodes.push(a, b); + car.points = [a.p, b.p]; + this.nodes.push(a.p, b.p); + car.segments = [a.segmentId, b.segmentId]; } } catch { currentOffset = 0; @@ -57,8 +63,9 @@ export class Train { const a = this.path.followEvenPoints(this.t - currentOffset); currentOffset += car.length; const b = this.path.followEvenPoints(this.t - currentOffset); - car.points = [a, b]; - this.nodes.push(a, b); + car.points = [a.p, b.p]; + this.nodes.push(a.p, b.p); + car.segments = [a.segmentId, b.segmentId]; } } } @@ -69,12 +76,16 @@ export class Train { // console.log(this.t); let currentOffset = 0; for (const car of this.cars) { + // This needs to be moved to the car itself if (!car.points) return; const [a, b] = car.points; - a.set(this.path.followEvenPoints(this.t - currentOffset)); + const nA = this.path.followEvenPoints(this.t - currentOffset); + a.set(nA.p); currentOffset += car.length; - b.set(this.path.followEvenPoints(this.t - currentOffset)); + const nB = this.path.followEvenPoints(this.t - currentOffset); + b.set(nB.p); currentOffset += this.spacing; + car.segments = [nA.segmentId, nB.segmentId]; // car.draw(); } // this.draw(); @@ -103,8 +114,14 @@ export class Train { // color: "red", // weight: 3, // }); - for (const p of this.path.evenPoints) { - doodler.drawCircle(p, 2, { color: "red", weight: .5 }); + const colors = getContextItem("colors"); + for (const [i, p] of this.path.evenPoints.entries()) { + const color = colors[ + Math.floor( + map(i, 0, this.path.evenPoints.length, 0, colors.length), + ) + ]; + doodler.drawCircle(p.p, 2, { color, weight: .5 }); } } for (const car of this.cars) { @@ -126,6 +143,8 @@ export class TrainCar { points?: [Vector, Vector, ...Vector[]]; length: number; + segments: string[] = []; + constructor( length: number, img: HTMLImageElement,