107 lines
3.1 KiB
TypeScript
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;
|
|
}
|