trainsim/train.ts
2023-02-07 22:44:24 -07:00

311 lines
8.4 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 { Track } from "./track.ts";
export class Train extends Follower {
nodes?: Vector[];
currentTrack: Track;
speed: number;
follower?: TrainCar;
followers?: TrainCar[];
constructor(track: Track, length: number) {
super(track.points[0].copy());
this.maxSpeed = 2;
this.speed = 1;
this.currentTrack = track;
this.velocity = this.currentTrack.tangent(0).normalize().mult(this.maxSpeed);
this.addCar(length);
this.maxForce = .2;
}
init(): void {
this.boundingBox.size.set(30, 10);
this._trailingPoint = 30;
}
move(): void {
this.follow();
super.move();
this.follower?.move()
// this.draw();
}
follow(): void {
const [_, t] = this.currentTrack.followTrack(this);
// this.position = this.currentTrack.getPointAtT(t);
this.velocity = this.currentTrack.tangent(t);
this.velocity.normalize().mult(this.speed || this.maxSpeed);
// if (nearest.dist(this.position) > 10)
// this.seek(nearest);
}
// draw(): void {
// if (!this.ctx) return;
// const ctx = this.ctx;
// // const [a, b] = this.nodes;
// ctx.strokeStyle = 'blue'
// ctx.lineWidth = 10;
// // drawLine(ctx, a.x, a.y, b.x, b.y);
// super.draw()
// }
setContext(ctx: CanvasRenderingContext2D): void {
super.setContext(ctx);
this.follower?.setContext(ctx);
}
addCar(length: number,) {
console.log(length);
if (length)
this.follower = new TrainCar(this.currentTrack, length - 1);
this.follower?.setTarget(this);
this.follower?.position.set(this.trailingPoint);
this._trailingPoint -= 2;
}
}
class TrainCar extends Train {
// constructor(n: [Vector, Vector], track: Track) {
// super(track);
// this.nodes = n;
// }
target?: Train;
setTarget(t: Train) {
this.target = t;
}
init(): void {
this.boundingBox.size.set(20, 10)
this._trailingPoint = 25;
this.maxSpeed = this.maxSpeed * 2;
this.maxForce = this.maxForce * 2;
// this.speed = 0;
}
// follow(): void {
// if (!this.target) return;
// const points = this.currentTrack.getAllPointsInRange(this.target.position, this.target._trailingPoint);
// let closest = this.target.position;
// let closestTan = this.target.velocity;
// for (const [t, path] of points) {
// const point = path.getPointAtT(t);
// if (point.dist(this.target.trailingPoint) < this.target.trailingPoint.dist(closest)) {
// closest = point;
// closestTan = path.tangent(t);
// }
// }
// // this.position.set(closest);
// this.seek(closest);
// this.velocity.set(closestTan.normalize().mult(this.target.speed));
// }
move(): void {
// if (!this.target) return;
// const r = 30;
// const points = this.currentTrack.getAllPointsInRange(this.target.position, this.target._trailingPoint);
// let closest = this.target.position;
// let closestTan = this.target.velocity;
// for (const [t, path] of points) {
// const point = path.getPointAtT(t);
// if (point.dist(this.target.trailingPoint) < this.target.trailingPoint.dist(closest)) {
// closest = point;
// closestTan = path.tangent(t);
// }
// }
// // this.position.set(closest);
// // this.seek(closest);
// this.velocity.set(closestTan.normalize().mult(this.target.speed));
// super.move();
// if (this.target && this.position.dist(this.target.trailingPoint) < 2) {
// this.velocity.setMag(0);
// } else if (this.target) {
// this.velocity.setMag(this.target.velocity.mag());
// }
// if (this.target) {
// this.position.set(this.target.trailingPoint);
// this.speed = this.target.speed;
// }
// const [pos,t] = this.currentTrack.followTrack(this);
// this.position = pos.copy()
// if (this.target) {
// const points = this.currentTrack.getPointWithinRadius(this.target.position, 30);
// let closest = this.target.position;
// for (const [i,point] of points.entries()) {
// if (typeof point !== "number") break;
// const tracks = [this.currentTrack, this.currentTrack.next, this.currentTrack.prev];
// const a = tracks[i].getPointAtT(point);
// if (a.dist(this.target.trailingPoint) < closest.dist(this.target.trailingPoint)) {
// closest = a;
// }
// }
// this.position = closest;
// }
// this.draw();
if (this.target) {
if (this.position.dist(this.target.position) > this.target.position.dist(this.target.trailingPoint)) {
// this.velocity = this.currentTrack.tangent(t);
// this.velocity.normalize().mult(this.speed);
this.arrive(this.currentTrack.getNearestPoint(this.target.trailingPoint));
// if (this.position.dist())
// this.move()
this.speed = this.target.speed;
super.move();
} else {
this.draw()
}
}
// this.draw()
// this.follower?.move()
}
// draw(): void {
// if (!this.ctx) return;
// super.draw()
// this.ctx.fillStyle = 'red';
// this.position.drawDot(this.ctx);
// this.ctx.fillStyle = 'green';
// this.target?.trailingPoint.drawDot(this.ctx);
// }
edges(): void {
}
}
// export class Train extends Follower {
// currentSegment: Track;
// cars: TrainCar[] = [];
// id: string;
// constructor(path: Track);
// constructor(x: number, y: number, segment: Track);
// constructor(x: number | Track, y?: number, segment?: Track) {
// super(x instanceof Track ? x.points[0].copy() : new Vector(x, y))
// if (x instanceof Track) {
// this.currentSegment = x;
// } else if (segment) {
// this.currentSegment = segment;
// } else {
// throw new Error('Path not provided for train construction')
// }
// // super(new Vector(Math.floor(Math.random() * 200),Math.floor(Math.random() * 200)), Vector.random2D());
// this.id = crypto.randomUUID()
// this.boundingBox.size.set(40, 10)
// this.maxSpeed = 3;
// this.maxForce = .3;
// this.addCar();
// this._trailingPoint = 40;
// this._leadingPoint = 15;
// }
// move(): void {
// for (const car of this.cars) {
// car.move();
// }
// this.follow(this.currentSegment)
// super.move();
// }
// draw(): void {
// if (!this.ctx) return;
// // this.ctx.save();
// this.ctx.fillStyle = 'white';
// this.ctx.strokeStyle = 'red';
// super.draw();
// // this.ctx.restore();
// }
// addCar() {
// const last = this.cars[this.cars.length - 1];
// this.cars.push(new TrainCar(this, (last || this).velocity.copy().normalize().mult(-30), last));
// }
// setContext(ctx: CanvasRenderingContext2D): void {
// super.setContext(ctx);
// for (const car of this.cars) {
// car.setContext(ctx);
// }
// }
// follow(toFollow: Track): void {
// // const predict = this.velocity.copy();
// // predict.normalize();
// // predict.mult(25);
// // const predictpos = Vector.add(this.position, predict)
// const nearest = toFollow.getMostValidTrack(this);
// this.seek(nearest);
// }
// }
// export class TrainCar extends Follower {
// train?: Train;
// prevCar?: Mover;
// constructor(train: Train, pos: Vector, prevCar: Mover) {
// super(pos);
// this.train = train;
// this.boundingBox.size.set(20, 15);
// this.prevCar = prevCar || train;
// this.maxSpeed = 2;
// this.maxForce = .3;
// this._trailingPoint = 25;
// this._leadingPoint = 25;
// }
// move(): void {
// if (this.train && this.prevCar) {
// this.link(this.prevCar);
// // super.move();
// this.edges();
// this.ctx && (this.ctx.fillStyle = 'orange')
// this.draw();
// }
// else super.move();
// }
// edges(): void {
// if (!this.ctx || !this.train) return;
// if (this.train.position.x > this.ctx.canvas.width) this.position.x -= this.ctx.canvas.width;
// if (this.train.position.y > this.ctx.canvas.height) this.position.y -= this.ctx.canvas.height;
// if (this.train.position.x < 0) this.position.x += this.ctx.canvas.width;
// if (this.train.position.y < 0) this.position.y += this.ctx.canvas.height;
// }
// }