From 9587ce5ae6d21c00c35c169a24899556bcd2e318 Mon Sep 17 00:00:00 2001 From: Emma Date: Sun, 16 Feb 2025 13:06:52 -0700 Subject: [PATCH] Train movement rewrite --- src/train/cars.ts | 85 ++++++++++++++++++++--------- src/train/engines.ts | 85 ++++++++++++++++++++--------- src/train/train.ts | 127 +++++++++++++++++++++++++++++++------------ 3 files changed, 213 insertions(+), 84 deletions(-) diff --git a/src/train/cars.ts b/src/train/cars.ts index ec503c7..d280b8b 100644 --- a/src/train/cars.ts +++ b/src/train/cars.ts @@ -6,50 +6,85 @@ import { getContextItem } from "../lib/context.ts"; export class Tender extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(25, resources.get("snr:sprite/engine")!, 40, 20, { - at: new Vector(80, 0), - width: 40, - height: 20, - }); + super( + 25, + 10, + resources.get("snr:sprite/engine")!, + 40, + 20, + { + at: new Vector(80, 0), + width: 40, + height: 20, + }, + ); } } export class Tank extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(50, resources.get("snr:sprite/engine")!, 70, 20, { - at: new Vector(80, 20), - width: 70, - height: 20, - }); + super( + 50, + 10, + resources.get("snr:sprite/engine")!, + 70, + 20, + { + at: new Vector(80, 20), + width: 70, + height: 20, + }, + ); } } export class YellowDumpCar extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(50, resources.get("snr:sprite/engine")!, 70, 20, { - at: new Vector(80, 40), - width: 70, - height: 20, - }); + super( + 50, + 10, + resources.get("snr:sprite/engine")!, + 70, + 20, + { + at: new Vector(80, 40), + width: 70, + height: 20, + }, + ); } } export class GrayDumpCar extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(50, resources.get("snr:sprite/engine")!, 70, 20, { - at: new Vector(80, 60), - width: 70, - height: 20, - }); + super( + 50, + 10, + resources.get("snr:sprite/engine")!, + 70, + 20, + { + at: new Vector(80, 60), + width: 70, + height: 20, + }, + ); } } export class NullCar extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(50, resources.get("snr:sprite/engine")!, 70, 20, { - at: new Vector(80, 80), - width: 70, - height: 20, - }); + super( + 50, + 10, + resources.get("snr:sprite/engine")!, + 70, + 20, + { + at: new Vector(80, 80), + width: 70, + height: 20, + }, + ); } } diff --git a/src/train/engines.ts b/src/train/engines.ts index e409419..4cfe6b9 100644 --- a/src/train/engines.ts +++ b/src/train/engines.ts @@ -6,50 +6,85 @@ import { ResourceManager } from "../lib/resources.ts"; export class RedEngine extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(55, resources.get("snr:sprite/engine")!, 80, 20, { - at: new Vector(0, 60), - width: 80, - height: 20, - }); + super( + 55, + 10, + resources.get("snr:sprite/engine")!, + 80, + 20, + { + at: new Vector(0, 60), + width: 80, + height: 20, + }, + ); } } export class PurpleEngine extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(55, resources.get("snr:sprite/engine")!, 80, 20, { - at: new Vector(0, 60), - width: 80, - height: 20, - }); + super( + 55, + 10, + resources.get("snr:sprite/engine")!, + 80, + 20, + { + at: new Vector(0, 60), + width: 80, + height: 20, + }, + ); } } export class GreenEngine extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(55, resources.get("snr:sprite/engine")!, 80, 20, { - at: new Vector(0, 40), - width: 80, - height: 20, - }); + super( + 55, + 10, + resources.get("snr:sprite/engine")!, + 80, + 20, + { + at: new Vector(0, 40), + width: 80, + height: 20, + }, + ); } } export class GrayEngine extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(55, resources.get("snr:sprite/engine")!, 80, 20, { - at: new Vector(0, 20), - width: 80, - height: 20, - }); + super( + 55, + 10, + resources.get("snr:sprite/engine")!, + 80, + 20, + { + at: new Vector(0, 20), + width: 80, + height: 20, + }, + ); } } export class BlueEngine extends TrainCar { constructor() { const resources = getContextItem("resources"); - super(55, resources.get("snr:sprite/engine")!, 80, 20, { - at: new Vector(0, 0), - width: 80, - height: 20, - }); + super( + 55, + 10, + resources.get("snr:sprite/engine")!, + 80, + 20, + { + at: new Vector(0, 0), + width: 80, + height: 20, + }, + ); } } diff --git a/src/train/train.ts b/src/train/train.ts index 343dcd0..77c258c 100644 --- a/src/train/train.ts +++ b/src/train/train.ts @@ -3,6 +3,7 @@ import { Doodler, Vector } from "@bearmetal/doodler"; import { Spline, TrackSegment, TrackSystem } from "../track/system.ts"; import { Debuggable } from "../lib/debuggable.ts"; import { map } from "../math/lerp.ts"; +import { off } from "node:process"; export class Train extends Debuggable { nodes: Vector[] = []; @@ -14,10 +15,12 @@ export class Train extends Debuggable { spacing = 20; - speed = 10; + speed = 0; get segments() { - return Array.from(new Set(this.cars.flatMap((c) => c.segments))); + return Array.from( + new Set(this.cars.flatMap((c) => c.segments.values().toArray())), + ); } constructor(track: Spline, cars: TrainCar[]) { @@ -29,24 +32,22 @@ export class Train extends Debuggable { let currentOffset = 0; try { for (const car of this.cars) { - currentOffset += this.spacing; - const a = this.path.followEvenPoints(this.t - currentOffset); - currentOffset += car.length; - const b = this.path.followEvenPoints(this.t - currentOffset); - car.points = [a.p, b.p]; - this.nodes.push(a.p, b.p); - car.segments = [a.segmentId, b.segmentId]; + car.train = this; + currentOffset += car.moveAlongPath(this.t - currentOffset) + + this.spacing; } + console.log("forward"); } catch { currentOffset = 0; + console.log("Reversed"); for (const car of this.cars.toReversed()) { - currentOffset += this.spacing; - const a = this.path.followEvenPoints(this.t - currentOffset); - currentOffset += car.length; - const b = this.path.followEvenPoints(this.t - currentOffset); - car.points = [a.p, b.p]; - this.nodes.push(a.p, b.p); - car.segments = [a.segmentId, b.segmentId]; + for (const [i, bogie] of car.bogies.entries().toArray().reverse()) { + currentOffset += bogie.length; + const a = this.path.followEvenPoints(this.t - currentOffset); + car.setBogiePosition(a.p, i); + this.nodes.push(a.p); + car.segments.add(a.segmentId); + } } } } @@ -58,16 +59,18 @@ export class Train extends Debuggable { 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; - const nA = this.path.followEvenPoints(this.t - currentOffset); - a.set(nA.p); - currentOffset += car.length; - const nB = this.path.followEvenPoints(this.t - currentOffset); - b.set(nB.p); - currentOffset += this.spacing; - car.segments = [nA.segmentId, nB.segmentId]; + // if (!car.points) return; + // const [a, b] = car.points; + // const nA = this.path.followEvenPoints(this.t - currentOffset); + // a.set(nA.p); + // currentOffset += car.length; + // const nB = this.path.followEvenPoints(this.t - currentOffset); + // b.set(nB.p); + // currentOffset += this.spacing; + // car.segments = [nA.segmentId, nB.segmentId]; // car.draw(); + + currentOffset += car.moveAlongPath(this.t - currentOffset) + this.spacing; } // this.draw(); } @@ -118,7 +121,7 @@ export class Train extends Debuggable { colors.push(colors.shift()!); colors.push(colors.shift()!); colors.push(colors.shift()!); - for (const [i, segmentId] of this.segments.entries()) { + for (const [i, segmentId] of this.segments.entries().toArray()) { const segment = track.getSegment(segmentId); segment && doodler.drawBezier(...segment.points, { @@ -134,6 +137,12 @@ export class Train extends Debuggable { } } +interface Bogie { + pos: Vector; + angle: number; + length: number; +} + export class TrainCar extends Debuggable { img: HTMLImageElement; imgWidth: number; @@ -143,10 +152,15 @@ export class TrainCar extends Debuggable { points?: [Vector, Vector, ...Vector[]]; length: number; - segments: string[] = []; + bogies: Bogie[] = []; + + segments: Set = new Set(); + + train?: Train; constructor( length: number, + trailing: number, img: HTMLImageElement, w: number, h: number, @@ -158,14 +172,51 @@ export class TrainCar extends Debuggable { this.imgWidth = w; this.imgHeight = h; this.length = length; + + this.bogies = [ + { + pos: new Vector(0, 0), + angle: 0, + length: length, + }, + { + pos: new Vector(0, 0), + angle: 0, + length: trailing, + }, + ]; + } + + setBogiePosition(pos: Vector, idx: number) { + this.bogies[idx].pos.set(pos); + } + + update(dTime: number, t: number) { + if (this.train) { + for (const [i, bogie] of this.bogies.entries()) { + const a = this.train.path.followEvenPoints(t - this.length * i); + } + } + } + + moveAlongPath(t: number): number { + if (!this.train) return 0; + let offset = 0; + this.segments.clear(); + for (const [i, bogie] of this.bogies.entries()) { + const a = this.train.path.followEvenPoints(t - offset); + offset += bogie.length; + this.setBogiePosition(a.p, i); + this.segments.add(a.segmentId); + } + return offset; } draw() { - if (!this.points) return; const doodler = getContextItem("doodler"); - const [a, b] = this.points; - const origin = Vector.add(Vector.sub(a, b).div(2), b); - const angle = Vector.sub(b, a).heading(); + const [a, b] = this.bogies; + const origin = Vector.add(Vector.sub(a.pos, b.pos).div(2), b.pos); + const angle = Vector.sub(b.pos, a.pos).heading(); doodler.drawCircle(origin, 4, { color: "blue" }); @@ -187,11 +238,19 @@ export class TrainCar extends Debuggable { }); } override debugDraw(...args: unknown[]): void { - if (!this.points) return; const doodler = getContextItem("doodler"); - doodler.drawLine(this.points, { + doodler.drawLine(this.bogies.map((b) => b.pos), { color: "blue", - weight: 3, + weight: 2, + }); + doodler.deferDrawing(() => { + const colors = getContextItem("colors"); + for (const [i, b] of this.bogies.entries()) { + doodler.drawCircle(b.pos, 5, { color: colors[i % colors.length] }); + doodler.fillText(b.length.toString(), b.pos.copy().add(10, 0), 100, { + color: "white", + }); + } }); } }