import { ComplexPath, PathSegment } from "../math/path.ts"; import { Follower } from "../physics/follower.ts"; import { Mover } from "../physics/mover.ts"; import { Spline, Track } from "../track.ts"; import { getContextItem } from "../lib/context.ts"; import { Doodler, Vector } from "@bearmetal/doodler"; export class Train { nodes: Vector[] = []; cars: TrainCar[] = []; path: Spline; t: number; engineLength = 40; spacing = 30; speed = 0; constructor(track: Spline, cars: TrainCar[] = []) { this.path = track; this.t = 0; this.nodes.push(this.path.followEvenPoints(this.t)); this.nodes.push(this.path.followEvenPoints(this.t - this.real2Track(40))); const engineSprites = document.getElementById( "engine-sprites", )! as HTMLImageElement; this.cars.push( new TrainCar( 55, engineSprites, 80, 20, { at: new Vector(0, 60), width: 80, height: 20 }, ), new TrainCar( 25, engineSprites, 40, 20, { at: new Vector(80, 0), width: 40, height: 20 }, ), ); this.cars[0].points = this.nodes.map((n) => n) as [Vector, Vector]; this.cars[1].points = this.nodes.map((n) => n) as [Vector, Vector]; let currentOffset = 40; for (const car of 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, b]; this.cars.push(car); } } move(dTime: number) { this.t = (this.t + this.speed * dTime * 10) % this.path.evenPoints.length; // console.log(this.t); let currentOffset = 0; for (const car of this.cars) { if (!car.points) return; const [a, b] = car.points; a.set(this.path.followEvenPoints(this.t - currentOffset)); currentOffset += car.length; b.set(this.path.followEvenPoints(this.t - currentOffset)); currentOffset += this.spacing; car.draw(); } // this.draw(); } // draw() { // for (const [i, node] of this.nodes.entries()) { // doodler.drawCircle(node.point, 10, { color: 'purple', weight: 3 }) // // const next = this.nodes[i + 1]; // // if (next) { // // const to = Vector.sub(node.point, next.point); // // to.setMag(40); // // doodler.line(next.point, Vector.add(to, next.point)) // // } // } // } draw() { for (const car of this.cars) { car.draw(); } } real2Track(length: number) { return length / this.path.pointSpacing; } } export class TrainCar { img: HTMLImageElement; imgWidth: number; imgHeight: number; sprite?: ISprite; points?: [Vector, Vector]; length: number; constructor( length: number, img: HTMLImageElement, w: number, h: number, sprite?: ISprite, ) { this.img = img; this.sprite = sprite; this.imgWidth = w; this.imgHeight = h; this.length = length; } 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(); doodler.drawCircle(origin, 4, { color: "blue" }); doodler.drawRotated(origin, angle, () => { this.sprite ? doodler.drawSprite( this.img, this.sprite.at, this.sprite.width, this.sprite.height, origin.copy().sub(this.imgWidth / 2, this.imgHeight / 2), this.imgWidth, this.imgHeight, ) : doodler.drawImage( this.img, origin.copy().sub(this.imgWidth / 2, this.imgHeight / 2), ); }); } } interface ISprite { at: Vector; width: number; height: number; }