200 lines
5.4 KiB
TypeScript
200 lines
5.4 KiB
TypeScript
import { lerp } from "./math/lerp.ts";
|
|
import { ComplexPath, PathSegment } from "./math/path.ts";
|
|
import { Mover } from "./physics/mover.ts";
|
|
import { Train, TrainCar } from "./train.ts";
|
|
import { fillCircle, drawCircle } from 'drawing';
|
|
import { generateSquareTrack, IControlNode, loadFromJson } from "./track.ts";
|
|
import { drawLine } from "./drawing/line.ts";
|
|
import { initializeDoodler, Vector } from 'doodler';
|
|
|
|
|
|
|
|
const engineSprites = document.createElement('img');
|
|
engineSprites.src = './sprites/EngineSprites.png';
|
|
engineSprites.style.display = 'none';
|
|
engineSprites.id = 'engine-sprites';
|
|
document.body.append(engineSprites);
|
|
|
|
initializeDoodler({
|
|
width: 400,
|
|
height: 400,
|
|
bg: '#333'
|
|
});
|
|
|
|
const path = loadFromJson();
|
|
|
|
const controls = {
|
|
ArrowUp: false,
|
|
ArrowRight: false,
|
|
ArrowDown: false,
|
|
ArrowLeft: false,
|
|
}
|
|
|
|
let t = 0;
|
|
let currentSeg = 0;
|
|
let speed = 1;
|
|
|
|
// const trainCount = 1;
|
|
// const trains = Array(trainCount).fill(null).map((_, i) => new Train(path.segments[i % path.segments.length], 5));
|
|
const car = new TrainCar(55, engineSprites, 80, 20, {at: new Vector(0, 80), height: 20, width: 80})
|
|
const train = new Train(path, [car]);
|
|
|
|
let dragEndCounter = 0
|
|
let selectedNode: IControlNode | undefined;
|
|
|
|
doodler.createLayer(() => {
|
|
for (let i = 0; i < path.evenPoints.length; i+=10) {
|
|
const p = path.evenPoints[i];
|
|
const next = path.evenPoints[(i + 1)%path.evenPoints.length];
|
|
const last = path.evenPoints.at(i - 1);
|
|
if (!last) break;
|
|
const tan = Vector.sub(last, next);
|
|
|
|
doodler.drawRotated(p, tan.heading(), () => {
|
|
doodler.line(p, p.copy().add(0,10), {color: '#291b17', weight: 4})
|
|
doodler.line(p, p.copy().add(0,-10), {color: '#291b17', weight: 4})
|
|
doodler.line(p.copy().add(-6,5), p.copy().add(6,5), {color: 'grey', weight: 2})
|
|
doodler.line(p.copy().add(-6,-5), p.copy().add(6,-5), {color: 'grey', weight: 2})
|
|
})
|
|
}
|
|
path.draw();
|
|
train.move();
|
|
|
|
selectedNode?.anchor.drawDot();
|
|
selectedNode?.controls.forEach(e => e.drawDot());
|
|
})
|
|
|
|
let editable = false;
|
|
|
|
const clickables = new Map()
|
|
|
|
let selectedPoint: Vector;
|
|
|
|
document.addEventListener('keyup', e => {
|
|
if (e.key === 'd') {
|
|
// console.log(trains)
|
|
// console.log(path.segments.reduce((a,b) => a + b.calculateApproxLength(1000), 0))
|
|
// console.log(path.evenPoints);
|
|
}
|
|
|
|
if (e.key === 'ArrowUp') {
|
|
// for (const train of trains) {
|
|
// train.speed += .1;
|
|
// }
|
|
speed += .1
|
|
}
|
|
if (e.key === 'ArrowDown') {
|
|
// for (const train of trains) {
|
|
// train.speed -= .1;
|
|
// }
|
|
speed -= .1
|
|
}
|
|
|
|
if (e.key === 'm' && selectedPoint) {
|
|
const points = path.points;
|
|
const index = points.findIndex(p => p === selectedPoint);
|
|
if (index > -1) {
|
|
const prev = points.at(index - 1)!;
|
|
const next = points[(index + 1) % points.length];
|
|
|
|
const toPrev = Vector.sub(prev, selectedPoint);
|
|
toPrev.setMag(next.dist(selectedPoint));
|
|
toPrev.rotate(Math.PI)
|
|
const toNext = Vector.add(toPrev, selectedPoint);
|
|
next.set(toNext);
|
|
|
|
path.calculateApproxLength();
|
|
path.calculateEvenlySpacedPoints(1);
|
|
}
|
|
}
|
|
|
|
if (e.key === 'e') {
|
|
editable = !editable;
|
|
for (const t of path.segments) {
|
|
t.editable = !t.editable;
|
|
for (const p of t.points) {
|
|
if (t.editable) {
|
|
doodler.registerDraggable(p, 10)
|
|
doodler.addDragEvents({
|
|
point: p,
|
|
onDragEnd: () => {
|
|
dragEndCounter++
|
|
t.length = t.calculateApproxLength(100)
|
|
path.evenPoints = path.calculateEvenlySpacedPoints(1)
|
|
},
|
|
onDrag: (movement) => {
|
|
// todo - remove ! after updating doodler
|
|
path.handleNodeEdit(p, movement!)
|
|
}
|
|
})
|
|
}
|
|
else {
|
|
doodler.unregisterDraggable(p)
|
|
}
|
|
}
|
|
}
|
|
for (const p of path.points) {
|
|
if (editable) {
|
|
const onClick = () => {
|
|
selectedPoint = p;
|
|
selectedNode = path.nodes.find(e => e.anchor === p || e.controls.includes(p));
|
|
}
|
|
|
|
clickables.set(p, onClick);
|
|
doodler.registerClickable(p.copy().sub(10, 10), p.copy().add(10, 10), onClick);
|
|
}
|
|
else {
|
|
const the = clickables.get(p);
|
|
doodler.unregisterClickable(the);
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
// document.addEventListener('keydown', e => {
|
|
// const valid = ["ArrowUp",
|
|
// "ArrowRight",
|
|
// "ArrowDown",
|
|
// "ArrowLeft",]
|
|
// if (valid.includes(e.key))
|
|
// controls[e.key as keyof typeof controls] = true;
|
|
// })
|
|
// document.addEventListener('keyup', e => {
|
|
// const valid = ["ArrowUp",
|
|
// "ArrowRight",
|
|
// "ArrowDown",
|
|
// "ArrowLeft",]
|
|
// if (valid.includes(e.key))
|
|
// controls[e.key as keyof typeof controls] = false;
|
|
// })
|
|
|
|
// function getSteeringForce(mover: Mover, dir: string) {
|
|
// const dirs = {
|
|
// ArrowUp: 0,
|
|
// ArrowRight: .1 * Math.PI,
|
|
// ArrowDown: Math.PI,
|
|
// ArrowLeft: -.1 * Math.PI,
|
|
// }
|
|
|
|
// const target = mover.velocity.copy();
|
|
// target.normalize();
|
|
// target.mult(10);
|
|
// target.rotate(dirs[dir as keyof typeof dirs]);
|
|
// const force = Vector.sub(target, mover.velocity);
|
|
// force.limit(.1)
|
|
// return force;
|
|
// }
|
|
|
|
document.addEventListener('keydown', e => {
|
|
if (e.ctrlKey && e.key === 's') {
|
|
e.preventDefault();
|
|
path.segments.forEach((s: any) => {
|
|
s.next = s.next.id
|
|
s.prev = s.prev.id
|
|
delete s.ctx
|
|
})
|
|
delete path.ctx;
|
|
const json = JSON.stringify(path);
|
|
localStorage.setItem('railPath', json);
|
|
}
|
|
}) |