trainsim/train.ts
2023-02-13 16:38:58 -07:00

107 lines
3.1 KiB
TypeScript

import { drawLine } from "./drawing/line.ts";
import { ComplexPath, PathSegment } from "./math/path.ts";
import { Vector } from "doodler";
import { Follower } from "./physics/follower.ts";
import { Mover } from "./physics/mover.ts";
import { Spline, Track } from "./track.ts";
export class Train {
nodes: Vector[] = [];
cars: TrainCar[] = [];
path: Spline<Track>;
t: number;
engineLength = 40;
spacing = 30;
constructor(track: Spline<Track>, 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)));
this.cars.push(new TrainCar(55, document.getElementById('engine-sprites')! as HTMLImageElement, 80, 20, { at: new Vector(0, 60), width: 80, height: 20 }));
this.cars[0].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() {
this.t = (this.t + 1) % this.path.evenPoints.length;
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))
// // }
// }
// }
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 [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;
}