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