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; // } // }