Train movement rewrite

This commit is contained in:
Emmaline Autumn 2025-02-16 13:06:52 -07:00
parent 01081706b1
commit 9587ce5ae6
3 changed files with 213 additions and 84 deletions

View File

@ -6,50 +6,85 @@ import { getContextItem } from "../lib/context.ts";
export class Tender extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(25, resources.get<HTMLImageElement>("snr:sprite/engine")!, 40, 20, {
super(
25,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
40,
20,
{
at: new Vector(80, 0),
width: 40,
height: 20,
});
},
);
}
}
export class Tank extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
super(
50,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
70,
20,
{
at: new Vector(80, 20),
width: 70,
height: 20,
});
},
);
}
}
export class YellowDumpCar extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
super(
50,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
70,
20,
{
at: new Vector(80, 40),
width: 70,
height: 20,
});
},
);
}
}
export class GrayDumpCar extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
super(
50,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
70,
20,
{
at: new Vector(80, 60),
width: 70,
height: 20,
});
},
);
}
}
export class NullCar extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(50, resources.get<HTMLImageElement>("snr:sprite/engine")!, 70, 20, {
super(
50,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
70,
20,
{
at: new Vector(80, 80),
width: 70,
height: 20,
});
},
);
}
}

View File

@ -6,50 +6,85 @@ import { ResourceManager } from "../lib/resources.ts";
export class RedEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
super(
55,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
80,
20,
{
at: new Vector(0, 60),
width: 80,
height: 20,
});
},
);
}
}
export class PurpleEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
super(
55,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
80,
20,
{
at: new Vector(0, 60),
width: 80,
height: 20,
});
},
);
}
}
export class GreenEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
super(
55,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
80,
20,
{
at: new Vector(0, 40),
width: 80,
height: 20,
});
},
);
}
}
export class GrayEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
super(
55,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
80,
20,
{
at: new Vector(0, 20),
width: 80,
height: 20,
});
},
);
}
}
export class BlueEngine extends TrainCar {
constructor() {
const resources = getContextItem<ResourceManager>("resources");
super(55, resources.get<HTMLImageElement>("snr:sprite/engine")!, 80, 20, {
super(
55,
10,
resources.get<HTMLImageElement>("snr:sprite/engine")!,
80,
20,
{
at: new Vector(0, 0),
width: 80,
height: 20,
});
},
);
}
}

View File

@ -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<TrackSegment>, 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;
for (const [i, bogie] of car.bogies.entries().toArray().reverse()) {
currentOffset += bogie.length;
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.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<string> = 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>("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");
doodler.drawLine(this.points, {
doodler.drawLine(this.bogies.map((b) => b.pos), {
color: "blue",
weight: 3,
weight: 2,
});
doodler.deferDrawing(() => {
const colors = getContextItem<string[]>("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",
});
}
});
}
}