import { lerp } from "./math/lerp.ts"; import { ComplexPath, PathSegment } from "./math/path.ts"; import { Mover } from "./physics/mover.ts"; import { Train, TrainCar } from "./train/train.old.ts"; 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({ fillScreen: true, bg: "#333", }, true); let path; try { path = loadFromJson(); } catch { path = generateSquareTrack(); } 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 length = Math.floor(Math.random() * 7); const cars = Array.from( { length }, () => new TrainCar(40, engineSprites, 61, 20, { at: new Vector(80, 20 * Math.ceil(Math.random() * 3)), width: 61, height: 20, }), ); const train = new Train(path, cars); let dragEndCounter = 0; let selectedNode: IControlNode | undefined; doodler.createLayer((_1, _2, _3) => { // console.log(_1, _2, _3); _1.imageSmoothingEnabled = false; const dTime = (_3 < 0 ? 1 : _3) / 1000; // console.log(dTime); 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(dTime); 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; train.speed += 1; } if (e.key === "ArrowDown") { // for (const train of trains) { // train.speed -= .1; // } speed -= .1; train.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); } } let translate: boolean = false; if (e.key === "e" && !translate) { 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); } } } let x = 0; let y = 0; const onDrag = (e: MouseEvent) => { x += e.movementX; y += e.movementY; console.log("draggin"); }; const dragEnd = () => { x = 0; y = 0; for (const t of path.points) { t.add(x, y); } }; if (e.key === "t" && editable) { // translate = !translate; // console.log(translate); for (const t of path.points) { t.add(100, 100); } path.calculateEvenlySpacedPoints(1); // switch (translate) { // case true: // console.log("adding"); // ((doodler as any)._canvas as HTMLCanvasElement).addEventListener( // "drag", // onDrag, // ); // ((doodler as any)._canvas as HTMLCanvasElement).addEventListener( // "dragend", // dragEnd, // ); // break; // case false: // ((doodler as any)._canvas as HTMLCanvasElement).removeEventListener( // "drag", // onDrag, // ); // ((doodler as any)._canvas as HTMLCanvasElement).removeEventListener( // "dragend", // dragEnd, // ); // break; // } } }); // 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.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); } });