Separates game loop from doodler draw loop. Each state is in charge of registering and unregistering layers
This commit is contained in:
113
track/system.ts
113
track/system.ts
@@ -22,6 +22,13 @@ export class TrackSystem {
|
||||
return this.segments.values().toArray().pop();
|
||||
}
|
||||
|
||||
optimize(percent: number) {
|
||||
console.log("Optimizing track", percent * 100 / 4);
|
||||
for (const segment of this.segments.values()) {
|
||||
segment.recalculateRailPoints(Math.round(percent * 100 / 4));
|
||||
}
|
||||
}
|
||||
|
||||
registerSegment(segment: TrackSegment) {
|
||||
segment.setTrack(this);
|
||||
this.segments.set(segment.id, segment);
|
||||
@@ -147,9 +154,14 @@ export class TrackSystem {
|
||||
|
||||
generatePath() {
|
||||
if (!this.firstSegment) throw new Error("No first segment");
|
||||
const flags = { looping: true };
|
||||
const rightOnlyPath = [
|
||||
this.firstSegment.copy(),
|
||||
...this.findRightPath(this.firstSegment, new Set([this.firstSegment.id])),
|
||||
...this.findRightPath(
|
||||
this.firstSegment,
|
||||
new Set([this.firstSegment.id]),
|
||||
flags,
|
||||
),
|
||||
];
|
||||
|
||||
rightOnlyPath.forEach((s, i, arr) => {
|
||||
@@ -159,6 +171,14 @@ export class TrackSystem {
|
||||
s.prev = prev;
|
||||
prev.next = s;
|
||||
});
|
||||
if (flags.looping) {
|
||||
const first = rightOnlyPath[0];
|
||||
const last = rightOnlyPath[rightOnlyPath.length - 1];
|
||||
first.points[0] = last.points[3];
|
||||
last.points[3] = first.points[0];
|
||||
first.prev = last;
|
||||
last.next = first;
|
||||
}
|
||||
|
||||
return new Spline<TrackSegment>(rightOnlyPath);
|
||||
}
|
||||
@@ -166,6 +186,7 @@ export class TrackSystem {
|
||||
*findRightPath(
|
||||
start: TrackSegment,
|
||||
seen: Set<string>,
|
||||
flags: { looping: boolean },
|
||||
): Generator<TrackSegment> {
|
||||
if (start.frontNeighbours.length === 0) {
|
||||
return;
|
||||
@@ -187,14 +208,20 @@ export class TrackSystem {
|
||||
rightMost = segment;
|
||||
}
|
||||
}
|
||||
if (seen.has(rightMost.id)) return;
|
||||
if (seen.has(rightMost.id)) {
|
||||
if (seen.values().next().value === rightMost.id) {
|
||||
flags.looping = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
seen.add(rightMost.id);
|
||||
yield rightMost.copy();
|
||||
yield* this.findRightPath(rightMost, seen);
|
||||
yield* this.findRightPath(rightMost, seen, flags);
|
||||
}
|
||||
*findLeftPath(
|
||||
start: TrackSegment,
|
||||
seen: Set<string>,
|
||||
flags: { looping: boolean },
|
||||
): Generator<TrackSegment> {
|
||||
if (start.frontNeighbours.length === 0) {
|
||||
return;
|
||||
@@ -216,10 +243,15 @@ export class TrackSystem {
|
||||
leftMost = segment;
|
||||
}
|
||||
}
|
||||
if (seen.has(leftMost.id)) return;
|
||||
if (seen.has(leftMost.id)) {
|
||||
if (seen.values().next().value === leftMost.id) {
|
||||
flags.looping = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
seen.add(leftMost.id);
|
||||
yield leftMost.copy();
|
||||
yield* this.findLeftPath(leftMost, seen);
|
||||
yield* this.findLeftPath(leftMost, seen, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,11 +264,27 @@ export class TrackSegment extends PathSegment {
|
||||
track?: TrackSystem;
|
||||
|
||||
doodler: Doodler;
|
||||
normalPoints: Vector[] = [];
|
||||
antiNormalPoints: Vector[] = [];
|
||||
|
||||
constructor(p: VectorSet, id?: string) {
|
||||
super(p);
|
||||
this.doodler = getContextItem<Doodler>("doodler");
|
||||
this.id = id ?? crypto.randomUUID();
|
||||
this.recalculateRailPoints();
|
||||
}
|
||||
|
||||
recalculateRailPoints(resolution = 100) {
|
||||
this.normalPoints = [];
|
||||
this.antiNormalPoints = [];
|
||||
for (let i = 0; i <= resolution; i++) {
|
||||
const t = i / resolution;
|
||||
const normal = this.tangent(t).rotate(Math.PI / 2);
|
||||
normal.setMag(6);
|
||||
const p = this.getPointAtT(t);
|
||||
this.normalPoints.push(p.copy().add(normal));
|
||||
this.antiNormalPoints.push(p.copy().add(normal.rotate(Math.PI)));
|
||||
}
|
||||
}
|
||||
|
||||
setTrack(t: TrackSystem) {
|
||||
@@ -299,21 +347,17 @@ export class TrackSegment extends PathSegment {
|
||||
// });
|
||||
});
|
||||
}
|
||||
const lineResolution = 100;
|
||||
const normalPoints: Vector[] = [];
|
||||
const antiNormalPoints: Vector[] = [];
|
||||
for (let i = 0; i <= lineResolution; i++) {
|
||||
const t = i / lineResolution;
|
||||
const normal = this.tangent(t).rotate(Math.PI / 2);
|
||||
normal.setMag(6);
|
||||
const p = this.getPointAtT(t);
|
||||
normalPoints.push(p.copy().add(normal));
|
||||
antiNormalPoints.push(p.copy().add(normal.rotate(Math.PI)));
|
||||
}
|
||||
|
||||
this.doodler.deferDrawing(
|
||||
() => {
|
||||
this.doodler.drawLine(normalPoints, { color: "grey" });
|
||||
this.doodler.drawLine(antiNormalPoints, { color: "grey" });
|
||||
this.doodler.drawLine(this.normalPoints, {
|
||||
color: "grey",
|
||||
weight: 1.5,
|
||||
});
|
||||
this.doodler.drawLine(this.antiNormalPoints, {
|
||||
color: "grey",
|
||||
weight: 1.5,
|
||||
});
|
||||
},
|
||||
);
|
||||
// this.doodler.drawCircle(p, 2, {
|
||||
@@ -438,21 +482,24 @@ export class Spline<T extends PathSegment = PathSegment> {
|
||||
|
||||
constructor(segs: T[]) {
|
||||
this.segments = segs;
|
||||
if (this.segments.at(-1)?.next === this.segments[0]) {
|
||||
this.looped = true;
|
||||
}
|
||||
this.pointSpacing = 1;
|
||||
this.evenPoints = this.calculateEvenlySpacedPoints(1);
|
||||
this.nodes = [];
|
||||
for (let i = 0; i < this.points.length; i += 3) {
|
||||
const node: IControlNode = {
|
||||
anchor: this.points[i],
|
||||
controls: [
|
||||
this.points.at(i - 1)!,
|
||||
this.points[(i + 1) % this.points.length],
|
||||
],
|
||||
mirrored: false,
|
||||
tangent: true,
|
||||
};
|
||||
this.nodes.push(node);
|
||||
}
|
||||
// for (let i = 0; i < this.points.length; i += 3) {
|
||||
// const node: IControlNode = {
|
||||
// anchor: this.points[i],
|
||||
// controls: [
|
||||
// this.points.at(i - 1)!,
|
||||
// this.points[(i + 1) % this.points.length],
|
||||
// ],
|
||||
// mirrored: false,
|
||||
// tangent: true,
|
||||
// };
|
||||
// this.nodes.push(node);
|
||||
// }
|
||||
}
|
||||
|
||||
// setContext(ctx: CanvasRenderingContext2D) {
|
||||
@@ -464,7 +511,11 @@ export class Spline<T extends PathSegment = PathSegment> {
|
||||
|
||||
draw() {
|
||||
for (const segment of this.segments) {
|
||||
segment.draw();
|
||||
// segment.draw();
|
||||
const doodler = getContextItem<Doodler>("doodler");
|
||||
doodler.drawWithAlpha(0.5, () => {
|
||||
doodler.drawBezier(...segment.points, { color: "red" });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user