312 lines
8.4 KiB
TypeScript
312 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.follower?.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;
|
|
// }
|
|
// }
|