283 lines
7.2 KiB
TypeScript
283 lines
7.2 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/train.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);
|
|
}
|
|
});
|