Compare commits
5 Commits
8d379461c3
...
b30a241d09
Author | SHA1 | Date | |
---|---|---|---|
b30a241d09 | |||
7914eb444a | |||
6009818d93 | |||
8bd2c30108 | |||
ffa2ef97e0 |
10
.temp/deno.lock
generated
10
.temp/deno.lock
generated
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "4",
|
"version": "4",
|
||||||
"specifiers": {
|
"specifiers": {
|
||||||
"jsr:@bearmetal/doodler@0.0.5-b": "0.0.5-b",
|
|
||||||
"jsr:@luca/esbuild-deno-loader@*": "0.11.0",
|
"jsr:@luca/esbuild-deno-loader@*": "0.11.0",
|
||||||
"jsr:@luca/esbuild-deno-loader@0.11.1": "0.11.1",
|
"jsr:@luca/esbuild-deno-loader@0.11.1": "0.11.1",
|
||||||
"jsr:@std/assert@*": "1.0.10",
|
"jsr:@std/assert@*": "1.0.10",
|
||||||
@ -25,9 +24,6 @@
|
|||||||
"@bearmetal/doodler@0.0.4": {
|
"@bearmetal/doodler@0.0.4": {
|
||||||
"integrity": "b631083cff84994c513f70d1f09e6a9256edabcb224112c93a9ca6a87c88a389"
|
"integrity": "b631083cff84994c513f70d1f09e6a9256edabcb224112c93a9ca6a87c88a389"
|
||||||
},
|
},
|
||||||
"@bearmetal/doodler@0.0.5-b": {
|
|
||||||
"integrity": "94f265ea21162f943291526800de7f3f6560634a4fe762a38cd73892685b6742"
|
|
||||||
},
|
|
||||||
"@luca/esbuild-deno-loader@0.11.0": {
|
"@luca/esbuild-deno-loader@0.11.0": {
|
||||||
"integrity": "c05a989aa7c4ee6992a27be5f15cfc5be12834cab7ff84cabb47313737c51a2c",
|
"integrity": "c05a989aa7c4ee6992a27be5f15cfc5be12834cab7ff84cabb47313737c51a2c",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
@ -208,7 +204,11 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"redirects": {
|
||||||
|
"https://deno.land/x/clipboard/mod.ts": "https://deno.land/x/clipboard@v0.0.3/mod.ts"
|
||||||
|
},
|
||||||
"remote": {
|
"remote": {
|
||||||
|
"https://deno.land/x/clipboard@v0.0.3/mod.ts": "5b68fe3b710b852de5273c135fc3c11b2b4050577401ee994161380bd8cab219",
|
||||||
"https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/canvas.ts": "aadfb4b2e9acce34d4a5da3f9027be642c93229bbfc2641cb55301542cbb87bf",
|
"https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/canvas.ts": "aadfb4b2e9acce34d4a5da3f9027be642c93229bbfc2641cb55301542cbb87bf",
|
||||||
"https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/geometry/constants.ts": "4f4cf7bf49ac871d984e9b43896783b0cc8ab0ea60d0fc4c8c582f7e00c3df5a",
|
"https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/geometry/constants.ts": "4f4cf7bf49ac871d984e9b43896783b0cc8ab0ea60d0fc4c8c582f7e00c3df5a",
|
||||||
"https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/geometry/vector.ts": "a08ecff64c5436a28c6451a31c68fc912d25f941aabafb79418fa0a1aeffa9d2",
|
"https://git.cyborggrizzly.com/emma/doodler/raw/tag/0.0.7a/geometry/vector.ts": "a08ecff64c5436a28c6451a31c68fc912d25f941aabafb79418fa0a1aeffa9d2",
|
||||||
@ -232,7 +232,7 @@
|
|||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"jsr:@bearmetal/doodler@0.0.5-b"
|
"jsr:@bearmetal/doodler@0.0.5"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
.temp/temp.json
Normal file
1
.temp/temp.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"p":[[200,24,0],[233,24,0],[264.87555226753926,32.541028488383176,0],[293.45439059242574,49.041028488383176,0]],"id":"11d7561a-3172-4ad7-9d53-6f65f49ce8c3","bNeighbors":["93e4d69d-10f2-4ecc-a4d0-560ee71708e8"],"fNeighbors":["e44c3a93-01f0-42f1-aee9-939cbde5903b"]},{"p":[[293.45439059242574,49.041028488383176,0],[322.0332289173122,65.54102848838318,0],[345.3677526964683,88.87555226753923,0],[361.8677526964683,117.45439059242571,0]],"id":"e44c3a93-01f0-42f1-aee9-939cbde5903b","bNeighbors":["11d7561a-3172-4ad7-9d53-6f65f49ce8c3"],"fNeighbors":["bf9833f2-fd66-45fb-924d-f40b7c863c26"]},{"p":[[361.8677526964683,117.45439059242571,0],[378.3677526964683,146.0332289173122,0],[386.9087811848515,177.90878118485145,0],[386.9087811848515,210.90878118485148,0]],"id":"bf9833f2-fd66-45fb-924d-f40b7c863c26","bNeighbors":["e44c3a93-01f0-42f1-aee9-939cbde5903b"],"fNeighbors":["081c81f3-8fe7-4c71-babd-1d02d52c3385"]},{"p":[[386.9087811848515,210.90878118485148,0],[386.9087811848515,243.90878118485148,0],[378.3677526964683,275.78433345239074,0],[361.8677526964683,304.3631717772772,0]],"id":"081c81f3-8fe7-4c71-babd-1d02d52c3385","bNeighbors":["bf9833f2-fd66-45fb-924d-f40b7c863c26"],"fNeighbors":["d1380635-1dba-4180-8038-931289a56d17"]},{"p":[[361.8677526964683,304.3631717772772,0],[345.3677526964683,332.9420101021637,0],[322.0332289173122,356.2765338813198,0],[293.45439059242574,372.7765338813198,0]],"id":"d1380635-1dba-4180-8038-931289a56d17","bNeighbors":["081c81f3-8fe7-4c71-babd-1d02d52c3385"],"fNeighbors":["8fe94c53-c0be-4f0d-986b-f37e143e62d7"]},{"p":[[293.45439059242574,372.7765338813198,0],[264.87555226753926,389.2765338813198,0],[233,397.81756236970296,0],[200,397.81756236970296,0]],"id":"8fe94c53-c0be-4f0d-986b-f37e143e62d7","bNeighbors":["d1380635-1dba-4180-8038-931289a56d17"],"fNeighbors":["1542c063-b548-4d27-9fd8-c7a8344b05cb"]},{"p":[[200,397.81756236970296,0],[167,397.81756236970296,0],[135.12444773246074,389.2765338813198,0],[106.54560940757426,372.7765338813198,0]],"id":"1542c063-b548-4d27-9fd8-c7a8344b05cb","bNeighbors":["8fe94c53-c0be-4f0d-986b-f37e143e62d7"],"fNeighbors":["9be20051-651f-4cca-b6f1-ca80d5db7635"]},{"p":[[106.54560940757426,372.7765338813198,0],[77.96677108268779,356.2765338813198,0],[54.6322473035317,332.94201010216375,0],[38.1322473035317,304.3631717772772,0]],"id":"9be20051-651f-4cca-b6f1-ca80d5db7635","bNeighbors":["1542c063-b548-4d27-9fd8-c7a8344b05cb"],"fNeighbors":["4b7ff960-9fe7-48b3-b64e-9e32f60b0d2f"]},{"p":[[38.1322473035317,304.3631717772772,0],[21.632247303531692,275.7843334523908,0],[13.091218815148487,243.9087811848515,0],[13.09121881514848,210.90878118485153,0]],"id":"4b7ff960-9fe7-48b3-b64e-9e32f60b0d2f","bNeighbors":["9be20051-651f-4cca-b6f1-ca80d5db7635"],"fNeighbors":["0c481aa2-92de-4517-8e76-6c3f163f3dde"]},{"p":[[13.09121881514848,210.90878118485153,0],[13.091218815148467,177.90878118485153,0],[21.632247303531646,146.03322891731227,0],[38.132247303531635,117.45439059242577,0]],"id":"0c481aa2-92de-4517-8e76-6c3f163f3dde","bNeighbors":["4b7ff960-9fe7-48b3-b64e-9e32f60b0d2f"],"fNeighbors":["c62384ad-3fec-4479-9596-1173a6e651bb"]},{"p":[[38.132247303531635,117.45439059242577,0],[54.63224730353162,88.87555226753928,0],[77.96677108268767,65.54102848838318,0],[106.54560940757415,49.041028488383176,0]],"id":"c62384ad-3fec-4479-9596-1173a6e651bb","bNeighbors":["0c481aa2-92de-4517-8e76-6c3f163f3dde"],"fNeighbors":["93e4d69d-10f2-4ecc-a4d0-560ee71708e8"]},{"p":[[106.54560940757415,49.041028488383176,0],[135.12444773246062,32.541028488383176,0],[166.9999999999999,23.99999999999997,0],[199.9999999999999,23.99999999999997,0]],"id":"93e4d69d-10f2-4ecc-a4d0-560ee71708e8","bNeighbors":["c62384ad-3fec-4479-9596-1173a6e651bb"],"fNeighbors":["11d7561a-3172-4ad7-9d53-6f65f49ce8c3"]}]
|
@ -1,6 +1,6 @@
|
|||||||
// Create a new devtools panel named "Context Stack"
|
// Create a new devtools panel named "Context Stack"
|
||||||
browser.devtools.panels.create(
|
browser.devtools.panels.create(
|
||||||
"Context Stack", // Tab title
|
"Smoke and Rails", // Tab title
|
||||||
"train icon.png", // Icon for your panel (optional)
|
"train icon.png", // Icon for your panel (optional)
|
||||||
"panel.html", // HTML page for your panel content
|
"panel.html", // HTML page for your panel content
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Context Stack</title>
|
<title>Smoke and Rails</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
@ -40,9 +40,9 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h1>Context Stack</h1>
|
<h2>Smoke and Rails Debugger</h2>
|
||||||
<div id="contextContainer"></div>
|
|
||||||
<button id="refresh">Refresh</button>
|
<button id="refresh">Refresh</button>
|
||||||
|
<div id="contextContainer"></div>
|
||||||
<script src="panel.js"></script>
|
<script src="panel.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { TrackSegment } from "../track/system.ts";
|
import { TrackSegment } from "../track/system.ts";
|
||||||
|
import { Train, TrainCar } from "../train/train.ts";
|
||||||
|
import { InputManager } from "./input.ts";
|
||||||
|
|
||||||
type ContextStore = Record<string, any>;
|
type ContextStore = Record<string, any>;
|
||||||
|
|
||||||
@ -52,66 +54,62 @@ export function setContextItem<T>(prop: string, value: T) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
setInterval(() => {
|
|
||||||
let ctxEl = document.getElementById("context");
|
|
||||||
if (!ctxEl) {
|
|
||||||
ctxEl = document.createElement("div");
|
|
||||||
ctxEl.id = "context";
|
|
||||||
document.body.append(ctxEl);
|
|
||||||
}
|
|
||||||
ctxEl.innerHTML = "";
|
|
||||||
const div = document.createElement("div");
|
|
||||||
const pre = document.createElement("pre");
|
|
||||||
const h3 = document.createElement("h3");
|
|
||||||
h3.textContent = "Default";
|
|
||||||
div.append(h3);
|
|
||||||
pre.textContent = safeStringify(defaultContext);
|
|
||||||
div.append(pre);
|
|
||||||
ctxEl.append(div);
|
|
||||||
for (const [idx, ctx] of contextStack.entries()) {
|
|
||||||
const div = document.createElement("div");
|
|
||||||
const pre = document.createElement("pre");
|
|
||||||
const h3 = document.createElement("h3");
|
|
||||||
h3.textContent = "CTX " + idx;
|
|
||||||
div.append(h3);
|
|
||||||
pre.textContent = safeStringify(ctx);
|
|
||||||
div.append(pre);
|
|
||||||
ctxEl.append(div);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function safeStringify(obj: any) {
|
function safeStringify(obj: any) {
|
||||||
const seen = new WeakSet();
|
const seen = new WeakSet();
|
||||||
return JSON.stringify(obj, (key, value) => {
|
return JSON.stringify(obj, (key, value) => {
|
||||||
if (value instanceof Map) {
|
|
||||||
const val: Record<string, unknown> = {};
|
|
||||||
for (const [k, v] of value) {
|
|
||||||
if (typeof k !== "string") continue;
|
|
||||||
val[k] = v;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof Set) {
|
|
||||||
return Array.from(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof TrackSegment) {
|
|
||||||
return {
|
|
||||||
...value,
|
|
||||||
frontNeighbours: value.frontNeighbours.map((n) => n.id),
|
|
||||||
backNeighbours: value.backNeighbours.map((n) => n.id),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "object" && value !== null) {
|
if (typeof value === "object" && value !== null) {
|
||||||
if (seen.has(value)) {
|
if (seen.has(value)) {
|
||||||
return "[Circular]"; // Replace circular references
|
return "[Circular]"; // Replace circular references
|
||||||
}
|
}
|
||||||
seen.add(value);
|
seen.add(value);
|
||||||
}
|
}
|
||||||
|
if (value instanceof Map) {
|
||||||
|
const val: Record<string, unknown> = {};
|
||||||
|
for (const [k, v] of value) {
|
||||||
|
if (typeof k !== "string") continue;
|
||||||
|
val[k] = v;
|
||||||
|
}
|
||||||
|
seen.add(value);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof Set) {
|
||||||
|
seen.add(value);
|
||||||
|
value = Array.from(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof TrackSegment) {
|
||||||
|
seen.add(value);
|
||||||
|
const val = { ...value };
|
||||||
|
(val as any).frontNeighbours = value.frontNeighbours.map((n) => n.id);
|
||||||
|
(val as any).backNeighbours = value.backNeighbours.map((n) => n.id);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (value instanceof Train) {
|
||||||
|
// const val = { ...value };
|
||||||
|
// // val.segments = value.segments.map((s) => s.id);
|
||||||
|
// delete (val as any).path;
|
||||||
|
// delete (val as any).nodes;
|
||||||
|
// delete (val as any).cars;
|
||||||
|
// delete (val as any).t;
|
||||||
|
|
||||||
|
// // val.t
|
||||||
|
// // val.
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (value instanceof InputManager) {
|
||||||
|
// return {};
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (value instanceof TrainCar) {
|
||||||
|
// const val = { ...value };
|
||||||
|
|
||||||
|
// return val;
|
||||||
|
// }
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}, 2);
|
}, 2);
|
||||||
}
|
}
|
||||||
|
35
src/lib/debuggable.ts
Normal file
35
src/lib/debuggable.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { getContextItem } from "./context.ts";
|
||||||
|
|
||||||
|
export abstract class Drawable {
|
||||||
|
abstract draw(...args: unknown[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class Debuggable extends Drawable {
|
||||||
|
constructor(...debugKeys: [boolean | keyof Debug, ...(keyof Debug)[]]) {
|
||||||
|
super();
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
let drawFirst = false;
|
||||||
|
if (typeof debugKeys[0] === "boolean") {
|
||||||
|
drawFirst = debugKeys.shift() as boolean;
|
||||||
|
}
|
||||||
|
const draw = this.draw.bind(this);
|
||||||
|
this.draw = drawFirst
|
||||||
|
? (...args: unknown[]) => {
|
||||||
|
draw(...args);
|
||||||
|
const debug = getContextItem<Debug>("debug");
|
||||||
|
if (debugKeys.some((k) => debug[k as keyof Debug])) {
|
||||||
|
this.debugDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: (...args: unknown[]) => {
|
||||||
|
const debug = getContextItem<Debug>("debug");
|
||||||
|
if (debugKeys.some((k) => debug[k as keyof Debug])) {
|
||||||
|
this.debugDraw();
|
||||||
|
}
|
||||||
|
draw(...args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract debugDraw(...args: unknown[]): void;
|
||||||
|
}
|
30
src/main.ts
30
src/main.ts
@ -24,7 +24,7 @@ const doodler = new ZoomableDoodler({
|
|||||||
(doodler as any as { ctx: CanvasRenderingContext2D }).ctx
|
(doodler as any as { ctx: CanvasRenderingContext2D }).ctx
|
||||||
.imageSmoothingEnabled = false;
|
.imageSmoothingEnabled = false;
|
||||||
// doodler.minScale = 0.1;
|
// doodler.minScale = 0.1;
|
||||||
// (doodler as any).scale = doodler.maxScale;
|
(doodler as any).scale = 3.14;
|
||||||
|
|
||||||
const colors = [
|
const colors = [
|
||||||
"red",
|
"red",
|
||||||
@ -37,12 +37,32 @@ const colors = [
|
|||||||
"violet",
|
"violet",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const _debug: Debug = JSON.parse(localStorage.getItem("debug") || "0") || {
|
||||||
|
track: false,
|
||||||
|
train: false,
|
||||||
|
path: false,
|
||||||
|
car: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const debug = new Proxy(_debug, {
|
||||||
|
get: (_, prop: string) => {
|
||||||
|
// if (prop !in _debug) {
|
||||||
|
// (_debug as any)[prop] = false;
|
||||||
|
// }
|
||||||
|
return prop in _debug ? (_debug as any)[prop] : false;
|
||||||
|
},
|
||||||
|
set: (_, prop: string, value: boolean) => {
|
||||||
|
(_debug as any)[prop] = value;
|
||||||
|
localStorage.setItem("debug", JSON.stringify(_debug));
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setDefaultContext({
|
setDefaultContext({
|
||||||
inputManager,
|
inputManager,
|
||||||
doodler,
|
doodler,
|
||||||
resources,
|
resources,
|
||||||
debug: true,
|
debug,
|
||||||
showEnds: true,
|
|
||||||
colors,
|
colors,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,3 +103,7 @@ setInterval(() => {
|
|||||||
|
|
||||||
const gameLoop = new GameLoop();
|
const gameLoop = new GameLoop();
|
||||||
gameLoop.start(state);
|
gameLoop.start(state);
|
||||||
|
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
console.log("Running in development mode");
|
||||||
|
}
|
||||||
|
@ -61,7 +61,7 @@ export class RunningState extends State<States> {
|
|||||||
const train = new Train(track.path, [new RedEngine(), new Tender()]);
|
const train = new Train(track.path, [new RedEngine(), new Tender()]);
|
||||||
ctx.trains.push(train);
|
ctx.trains.push(train);
|
||||||
});
|
});
|
||||||
// const trainCount = 2000;
|
// const trainCount = 1000;
|
||||||
// for (let i = 0; i < trainCount; i++) {
|
// for (let i = 0; i < trainCount; i++) {
|
||||||
// const train = new Train(track.path, [new RedEngine(), new Tender()]);
|
// const train = new Train(track.path, [new RedEngine(), new Tender()]);
|
||||||
// ctx.trains.push(train);
|
// ctx.trains.push(train);
|
||||||
@ -72,6 +72,9 @@ export class RunningState extends State<States> {
|
|||||||
for (const train of trains) {
|
for (const train of trains) {
|
||||||
train.speed += 1;
|
train.speed += 1;
|
||||||
}
|
}
|
||||||
|
// for (const [i, train] of trains.entries()) {
|
||||||
|
// train.speed += .01 * i;
|
||||||
|
// }
|
||||||
});
|
});
|
||||||
inputManager.onKey("ArrowDown", () => {
|
inputManager.onKey("ArrowDown", () => {
|
||||||
const trains = getContextItem<Train[]>("trains");
|
const trains = getContextItem<Train[]>("trains");
|
||||||
|
@ -4,33 +4,37 @@ import { getContextItem, setDefaultContext } from "../lib/context.ts";
|
|||||||
import { clamp } from "../math/clamp.ts";
|
import { clamp } from "../math/clamp.ts";
|
||||||
|
|
||||||
export class TrackSystem {
|
export class TrackSystem {
|
||||||
private segments: Map<string, TrackSegment> = new Map();
|
private _segments: Map<string, TrackSegment> = new Map();
|
||||||
private doodler: Doodler;
|
private doodler: Doodler;
|
||||||
|
|
||||||
constructor(segments: TrackSegment[]) {
|
constructor(segments: TrackSegment[]) {
|
||||||
this.doodler = getContextItem<Doodler>("doodler");
|
this.doodler = getContextItem<Doodler>("doodler");
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
this.segments.set(segment.id, segment);
|
this._segments.set(segment.id, segment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSegment(id: string) {
|
||||||
|
return this._segments.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
get firstSegment() {
|
get firstSegment() {
|
||||||
return this.segments.values().next().value;
|
return this._segments.values().next().value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get lastSegment() {
|
get lastSegment() {
|
||||||
return this.segments.values().toArray().pop();
|
return this._segments.values().toArray().pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize(percent: number) {
|
optimize(percent: number) {
|
||||||
console.log("Optimizing track", percent * 100 / 4);
|
console.log("Optimizing track", percent * 100 / 4);
|
||||||
for (const segment of this.segments.values()) {
|
for (const segment of this._segments.values()) {
|
||||||
segment.recalculateRailPoints(Math.round(percent * 100 / 4));
|
segment.recalculateRailPoints(Math.round(percent * 100 / 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recalculateAll() {
|
recalculateAll() {
|
||||||
for (const segment of this.segments.values()) {
|
for (const segment of this._segments.values()) {
|
||||||
segment.recalculateRailPoints();
|
segment.recalculateRailPoints();
|
||||||
segment.length = segment.calculateApproxLength();
|
segment.length = segment.calculateApproxLength();
|
||||||
}
|
}
|
||||||
@ -38,11 +42,11 @@ export class TrackSystem {
|
|||||||
|
|
||||||
registerSegment(segment: TrackSegment) {
|
registerSegment(segment: TrackSegment) {
|
||||||
segment.setTrack(this);
|
segment.setTrack(this);
|
||||||
this.segments.set(segment.id, segment);
|
this._segments.set(segment.id, segment);
|
||||||
}
|
}
|
||||||
unregisterSegment(segment: TrackSegment) {
|
unregisterSegment(segment: TrackSegment) {
|
||||||
this.segments.delete(segment.id);
|
this._segments.delete(segment.id);
|
||||||
for (const s of this.segments.values()) {
|
for (const s of this._segments.values()) {
|
||||||
s.backNeighbours = s.backNeighbours.filter((n) => n !== segment);
|
s.backNeighbours = s.backNeighbours.filter((n) => n !== segment);
|
||||||
s.frontNeighbours = s.frontNeighbours.filter((n) => n !== segment);
|
s.frontNeighbours = s.frontNeighbours.filter((n) => n !== segment);
|
||||||
}
|
}
|
||||||
@ -52,7 +56,7 @@ export class TrackSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw(showControls = false) {
|
draw(showControls = false) {
|
||||||
for (const [i, segment] of this.segments.entries()) {
|
for (const [i, segment] of this._segments.entries()) {
|
||||||
segment.draw(showControls);
|
segment.draw(showControls);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +89,7 @@ export class TrackSystem {
|
|||||||
endArray: End[] = [];
|
endArray: End[] = [];
|
||||||
|
|
||||||
findEnds() {
|
findEnds() {
|
||||||
for (const segment of this.segments.values()) {
|
for (const segment of this._segments.values()) {
|
||||||
if (this.ends.has(segment)) continue;
|
if (this.ends.has(segment)) continue;
|
||||||
const ends: [End, End] = [
|
const ends: [End, End] = [
|
||||||
{
|
{
|
||||||
@ -109,14 +113,14 @@ export class TrackSystem {
|
|||||||
|
|
||||||
serialize() {
|
serialize() {
|
||||||
return JSON.stringify(
|
return JSON.stringify(
|
||||||
this.segments.values().map((s) => s.serialize()).toArray(),
|
this._segments.values().map((s) => s.serialize()).toArray(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy() {
|
copy() {
|
||||||
const track = new TrackSystem([]);
|
const track = new TrackSystem([]);
|
||||||
for (const segment of this.segments.values()) {
|
for (const segment of this._segments.values()) {
|
||||||
track.segments.set(segment.id, segment.copy());
|
track._segments.set(segment.id, segment.copy());
|
||||||
}
|
}
|
||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
@ -127,19 +131,19 @@ export class TrackSystem {
|
|||||||
const neighborMap = new Map<string, [string[], string[]]>();
|
const neighborMap = new Map<string, [string[], string[]]>();
|
||||||
|
|
||||||
for (const segment of data) {
|
for (const segment of data) {
|
||||||
track.segments.set(segment.id, TrackSegment.deserialize(segment));
|
track._segments.set(segment.id, TrackSegment.deserialize(segment));
|
||||||
neighborMap.set(segment.id, [segment.fNeighbors, segment.bNeighbors]);
|
neighborMap.set(segment.id, [segment.fNeighbors, segment.bNeighbors]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const segment of track.segments.values()) {
|
for (const segment of track._segments.values()) {
|
||||||
segment.setTrack(track);
|
segment.setTrack(track);
|
||||||
const neighbors = neighborMap.get(segment.id);
|
const neighbors = neighborMap.get(segment.id);
|
||||||
if (neighbors) {
|
if (neighbors) {
|
||||||
segment.backNeighbours = neighbors[1].map((id) =>
|
segment.backNeighbours = neighbors[1].map((id) =>
|
||||||
track.segments.get(id)
|
track._segments.get(id)
|
||||||
).filter((s) => s) as TrackSegment[];
|
).filter((s) => s) as TrackSegment[];
|
||||||
segment.frontNeighbours = neighbors[0].map((id) =>
|
segment.frontNeighbours = neighbors[0].map((id) =>
|
||||||
track.segments.get(id)
|
track._segments.get(id)
|
||||||
).filter((s) => s) as TrackSegment[];
|
).filter((s) => s) as TrackSegment[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +152,7 @@ export class TrackSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
translate(v: Vector) {
|
translate(v: Vector) {
|
||||||
for (const segment of this.segments.values()) {
|
for (const segment of this._segments.values()) {
|
||||||
segment.translate(v);
|
segment.translate(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +168,7 @@ export class TrackSystem {
|
|||||||
|
|
||||||
generatePath() {
|
generatePath() {
|
||||||
if (!this.firstSegment) throw new Error("No first segment");
|
if (!this.firstSegment) throw new Error("No first segment");
|
||||||
const flags = { looping: true };
|
const flags = { looping: false };
|
||||||
const rightOnlyPath = [
|
const rightOnlyPath = [
|
||||||
this.firstSegment.copy(),
|
this.firstSegment.copy(),
|
||||||
...this.findRightPath(
|
...this.findRightPath(
|
||||||
@ -276,15 +280,19 @@ export class TrackSegment extends PathSegment {
|
|||||||
doodler: Doodler;
|
doodler: Doodler;
|
||||||
normalPoints: Vector[] = [];
|
normalPoints: Vector[] = [];
|
||||||
antiNormalPoints: Vector[] = [];
|
antiNormalPoints: Vector[] = [];
|
||||||
|
evenPoints: [Vector, number][] = [];
|
||||||
|
|
||||||
constructor(p: VectorSet, id?: string) {
|
constructor(p: VectorSet, id?: string) {
|
||||||
super(p);
|
super(p);
|
||||||
this.doodler = getContextItem<Doodler>("doodler");
|
this.doodler = getContextItem<Doodler>("doodler");
|
||||||
this.id = id ?? crypto.randomUUID();
|
this.id = id ?? crypto.randomUUID();
|
||||||
this.recalculateRailPoints();
|
this.recalculateRailPoints();
|
||||||
|
|
||||||
|
const spacing = Math.ceil(this.length / 10);
|
||||||
|
this.evenPoints = this.calculateEvenlySpacedPoints(this.length / spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
recalculateRailPoints(resolution = 100) {
|
recalculateRailPoints(resolution = 60) {
|
||||||
this.normalPoints = [];
|
this.normalPoints = [];
|
||||||
this.antiNormalPoints = [];
|
this.antiNormalPoints = [];
|
||||||
for (let i = 0; i <= resolution; i++) {
|
for (let i = 0; i <= resolution; i++) {
|
||||||
@ -330,12 +338,12 @@ export class TrackSegment extends PathSegment {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const spacing = Math.ceil(this.length / 10);
|
// const spacing = Math.ceil(this.length / 10);
|
||||||
const points = this.calculateEvenlySpacedPoints(this.length / spacing);
|
// const points = this.calculateEvenlySpacedPoints(this.length / spacing);
|
||||||
for (let i = 0; i < points.length - 1; i++) {
|
for (let i = 0; i < this.evenPoints.length - 1; i++) {
|
||||||
// const t = i / ties;
|
// const t = i / ties;
|
||||||
// const p = this.getPointAtT(t);
|
// const p = this.getPointAtT(t);
|
||||||
const [p, t] = points[i];
|
const [p, t] = this.evenPoints[i];
|
||||||
// this.doodler.drawCircle(p, 2, {
|
// this.doodler.drawCircle(p, 2, {
|
||||||
// color: "red",
|
// color: "red",
|
||||||
// weight: 3,
|
// weight: 3,
|
||||||
@ -480,11 +488,17 @@ export class TrackSegment extends PathSegment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PathPoint {
|
||||||
|
p: Vector;
|
||||||
|
segmentId: string;
|
||||||
|
tangent: Vector;
|
||||||
|
}
|
||||||
|
|
||||||
export class Spline<T extends PathSegment = PathSegment> {
|
export class Spline<T extends PathSegment = PathSegment> {
|
||||||
segments: T[] = [];
|
segments: T[] = [];
|
||||||
ctx?: CanvasRenderingContext2D;
|
ctx?: CanvasRenderingContext2D;
|
||||||
|
|
||||||
evenPoints: Vector[];
|
evenPoints: PathPoint[];
|
||||||
pointSpacing: number;
|
pointSpacing: number;
|
||||||
|
|
||||||
get points() {
|
get points() {
|
||||||
@ -534,13 +548,17 @@ export class Spline<T extends PathSegment = PathSegment> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateEvenlySpacedPoints(spacing: number, resolution = 1) {
|
calculateEvenlySpacedPoints(spacing: number, resolution = 1): PathPoint[] {
|
||||||
this.pointSpacing = 1;
|
this.pointSpacing = 1;
|
||||||
// return this.segments.flatMap(s => s.calculateEvenlySpacedPoints(spacing, resolution));
|
// return this.segments.flatMap(s => s.calculateEvenlySpacedPoints(spacing, resolution));
|
||||||
const points: Vector[] = [];
|
const points: PathPoint[] = [];
|
||||||
|
|
||||||
points.push(this.segments[0].points[0]);
|
points.push({
|
||||||
let prev = points[0];
|
p: this.segments[0].points[0],
|
||||||
|
segmentId: this.segments[0].id,
|
||||||
|
tangent: this.segments[0].tangent(0),
|
||||||
|
});
|
||||||
|
let prev = points[0].p;
|
||||||
let distSinceLastEvenPoint = 0;
|
let distSinceLastEvenPoint = 0;
|
||||||
for (const seg of this.segments) {
|
for (const seg of this.segments) {
|
||||||
let t = 0;
|
let t = 0;
|
||||||
@ -558,8 +576,13 @@ export class Spline<T extends PathSegment = PathSegment> {
|
|||||||
Vector.sub(point, prev).normalize().mult(overshoot),
|
Vector.sub(point, prev).normalize().mult(overshoot),
|
||||||
);
|
);
|
||||||
distSinceLastEvenPoint = overshoot;
|
distSinceLastEvenPoint = overshoot;
|
||||||
points.push(evenPoint);
|
points.push({
|
||||||
|
p: evenPoint,
|
||||||
|
segmentId: seg.id,
|
||||||
|
tangent: seg.tangent(t),
|
||||||
|
});
|
||||||
prev = evenPoint;
|
prev = evenPoint;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = point;
|
prev = point;
|
||||||
@ -571,13 +594,17 @@ export class Spline<T extends PathSegment = PathSegment> {
|
|||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
followEvenPoints(t: number) {
|
followEvenPoints(t: number): PathPoint {
|
||||||
if (this.looped) {
|
if (this.looped) {
|
||||||
if (t < 0) t += this.evenPoints.length;
|
if (t < 0) t += this.evenPoints.length;
|
||||||
const i = Math.floor(t) % this.evenPoints.length;
|
const i = Math.floor(t) % this.evenPoints.length;
|
||||||
const a = this.evenPoints[i];
|
const a = this.evenPoints[i];
|
||||||
const b = this.evenPoints[(i + 1) % this.evenPoints.length];
|
const b = this.evenPoints[(i + 1) % this.evenPoints.length];
|
||||||
return Vector.lerp(a, b, t % 1);
|
return {
|
||||||
|
p: Vector.lerp(a.p, b.p, t % 1),
|
||||||
|
segmentId: b.segmentId,
|
||||||
|
tangent: b.tangent,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
t = clamp(t, 0, this.evenPoints.length - 1);
|
t = clamp(t, 0, this.evenPoints.length - 1);
|
||||||
const i = clamp(Math.floor(t), 0, this.evenPoints.length - 1);
|
const i = clamp(Math.floor(t), 0, this.evenPoints.length - 1);
|
||||||
@ -586,7 +613,11 @@ export class Spline<T extends PathSegment = PathSegment> {
|
|||||||
.evenPoints[
|
.evenPoints[
|
||||||
clamp((i + 1) % this.evenPoints.length, 0, this.evenPoints.length - 1)
|
clamp((i + 1) % this.evenPoints.length, 0, this.evenPoints.length - 1)
|
||||||
];
|
];
|
||||||
return Vector.lerp(a, b, t % 1);
|
return {
|
||||||
|
p: Vector.lerp(a.p, b.p, t % 1),
|
||||||
|
segmentId: b.segmentId,
|
||||||
|
tangent: b.tangent,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateApproxLength() {
|
calculateApproxLength() {
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { ComplexPath, PathSegment } from "../math/path.ts";
|
import { getContextItem } from "../lib/context.ts";
|
||||||
import { Follower } from "../physics/follower.ts";
|
|
||||||
import { Mover } from "../physics/mover.ts";
|
|
||||||
import { getContext, getContextItem } from "../lib/context.ts";
|
|
||||||
import { Doodler, Vector } from "@bearmetal/doodler";
|
import { Doodler, Vector } from "@bearmetal/doodler";
|
||||||
import { Spline, TrackSegment } from "../track/system.ts";
|
import { Spline, TrackSegment, TrackSystem } from "../track/system.ts";
|
||||||
import { ResourceManager } from "../lib/resources.ts";
|
import { Debuggable } from "../lib/debuggable.ts";
|
||||||
|
import { map } from "../math/lerp.ts";
|
||||||
|
|
||||||
export class Train {
|
export class Train extends Debuggable {
|
||||||
nodes: Vector[] = [];
|
nodes: Vector[] = [];
|
||||||
|
|
||||||
cars: TrainCar[] = [];
|
cars: TrainCar[] = [];
|
||||||
@ -14,32 +12,20 @@ export class Train {
|
|||||||
path: Spline<TrackSegment>;
|
path: Spline<TrackSegment>;
|
||||||
t: number;
|
t: number;
|
||||||
|
|
||||||
engineLength = 40;
|
spacing = 20;
|
||||||
spacing = 30;
|
|
||||||
|
|
||||||
speed = 10;
|
speed = 10;
|
||||||
|
|
||||||
|
get segments() {
|
||||||
|
return Array.from(new Set(this.cars.flatMap((c) => c.segments)));
|
||||||
|
}
|
||||||
|
|
||||||
constructor(track: Spline<TrackSegment>, cars: TrainCar[]) {
|
constructor(track: Spline<TrackSegment>, cars: TrainCar[]) {
|
||||||
|
super("train", "path");
|
||||||
this.path = track;
|
this.path = track;
|
||||||
this.t = 0;
|
this.t = 0;
|
||||||
const resources = getContextItem<ResourceManager>("resources");
|
|
||||||
this.cars = cars;
|
this.cars = cars;
|
||||||
// this.cars.push(
|
|
||||||
// new TrainCar(
|
|
||||||
// 55,
|
|
||||||
// engineSprites,
|
|
||||||
// 80,
|
|
||||||
// 20,
|
|
||||||
// { at: new Vector(0, 60), width: 80, height: 20 },
|
|
||||||
// ),
|
|
||||||
// new TrainCar(
|
|
||||||
// 25,
|
|
||||||
// engineSprites,
|
|
||||||
// 40,
|
|
||||||
// 20,
|
|
||||||
// { at: new Vector(80, 0), width: 40, height: 20 },
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
let currentOffset = 0;
|
let currentOffset = 0;
|
||||||
try {
|
try {
|
||||||
for (const car of this.cars) {
|
for (const car of this.cars) {
|
||||||
@ -47,8 +33,9 @@ export class Train {
|
|||||||
const a = this.path.followEvenPoints(this.t - currentOffset);
|
const a = this.path.followEvenPoints(this.t - currentOffset);
|
||||||
currentOffset += car.length;
|
currentOffset += car.length;
|
||||||
const b = this.path.followEvenPoints(this.t - currentOffset);
|
const b = this.path.followEvenPoints(this.t - currentOffset);
|
||||||
car.points = [a, b];
|
car.points = [a.p, b.p];
|
||||||
this.nodes.push(a, b);
|
this.nodes.push(a.p, b.p);
|
||||||
|
car.segments = [a.segmentId, b.segmentId];
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
currentOffset = 0;
|
currentOffset = 0;
|
||||||
@ -57,24 +44,29 @@ export class Train {
|
|||||||
const a = this.path.followEvenPoints(this.t - currentOffset);
|
const a = this.path.followEvenPoints(this.t - currentOffset);
|
||||||
currentOffset += car.length;
|
currentOffset += car.length;
|
||||||
const b = this.path.followEvenPoints(this.t - currentOffset);
|
const b = this.path.followEvenPoints(this.t - currentOffset);
|
||||||
car.points = [a, b];
|
car.points = [a.p, b.p];
|
||||||
this.nodes.push(a, b);
|
this.nodes.push(a.p, b.p);
|
||||||
|
car.segments = [a.segmentId, b.segmentId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
move(dTime: number) {
|
move(dTime: number) {
|
||||||
|
if (!this.speed) return;
|
||||||
this.t = this.t + this.speed * dTime * 10;
|
this.t = this.t + this.speed * dTime * 10;
|
||||||
// % this.path.evenPoints.length; // This should probably be on the track system
|
// % this.path.evenPoints.length; // This should probably be on the track system
|
||||||
// console.log(this.t);
|
|
||||||
let currentOffset = 0;
|
let currentOffset = 0;
|
||||||
for (const car of this.cars) {
|
for (const car of this.cars) {
|
||||||
|
// This needs to be moved to the car itself
|
||||||
if (!car.points) return;
|
if (!car.points) return;
|
||||||
const [a, b] = car.points;
|
const [a, b] = car.points;
|
||||||
a.set(this.path.followEvenPoints(this.t - currentOffset));
|
const nA = this.path.followEvenPoints(this.t - currentOffset);
|
||||||
|
a.set(nA.p);
|
||||||
currentOffset += car.length;
|
currentOffset += car.length;
|
||||||
b.set(this.path.followEvenPoints(this.t - currentOffset));
|
const nB = this.path.followEvenPoints(this.t - currentOffset);
|
||||||
|
b.set(nB.p);
|
||||||
currentOffset += this.spacing;
|
currentOffset += this.spacing;
|
||||||
|
car.segments = [nA.segmentId, nB.segmentId];
|
||||||
// car.draw();
|
// car.draw();
|
||||||
}
|
}
|
||||||
// this.draw();
|
// this.draw();
|
||||||
@ -96,19 +88,44 @@ export class Train {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
const ctx = getContext();
|
for (const car of this.cars) {
|
||||||
if (ctx.debug) {
|
car.draw();
|
||||||
const doodler = getContextItem<Doodler>("doodler");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override debugDraw(): void {
|
||||||
|
const debug = getContextItem<Debug>("debug");
|
||||||
|
const doodler = getContextItem<Doodler>("doodler");
|
||||||
|
if (debug.path) {
|
||||||
// doodler.drawLine(this.path.points, {
|
// doodler.drawLine(this.path.points, {
|
||||||
// color: "red",
|
// color: "red",
|
||||||
// weight: 3,
|
// weight: 3,
|
||||||
// });
|
// });
|
||||||
for (const p of this.path.evenPoints) {
|
const colors = getContextItem<string[]>("colors");
|
||||||
doodler.drawCircle(p, 2, { color: "red", weight: .5 });
|
for (const [i, p] of this.path.evenPoints.entries()) {
|
||||||
|
const color = colors[
|
||||||
|
Math.floor(
|
||||||
|
map(i, 0, this.path.evenPoints.length, 0, colors.length),
|
||||||
|
)
|
||||||
|
];
|
||||||
|
doodler.drawCircle(p.p, 2, { color, weight: .5 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const car of this.cars) {
|
|
||||||
car.draw();
|
if (debug.train) {
|
||||||
|
const track = getContextItem<TrackSystem>("track");
|
||||||
|
const colors = getContextItem<string[]>("colors").slice();
|
||||||
|
colors.push(colors.shift()!);
|
||||||
|
colors.push(colors.shift()!);
|
||||||
|
colors.push(colors.shift()!);
|
||||||
|
for (const [i, segmentId] of this.segments.entries()) {
|
||||||
|
const segment = track.getSegment(segmentId);
|
||||||
|
segment &&
|
||||||
|
doodler.drawBezier(...segment.points, {
|
||||||
|
color: colors[i % colors.length],
|
||||||
|
weight: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +134,7 @@ export class Train {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TrainCar {
|
export class TrainCar extends Debuggable {
|
||||||
img: HTMLImageElement;
|
img: HTMLImageElement;
|
||||||
imgWidth: number;
|
imgWidth: number;
|
||||||
imgHeight: number;
|
imgHeight: number;
|
||||||
@ -126,6 +143,8 @@ export class TrainCar {
|
|||||||
points?: [Vector, Vector, ...Vector[]];
|
points?: [Vector, Vector, ...Vector[]];
|
||||||
length: number;
|
length: number;
|
||||||
|
|
||||||
|
segments: string[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
length: number,
|
length: number,
|
||||||
img: HTMLImageElement,
|
img: HTMLImageElement,
|
||||||
@ -133,6 +152,7 @@ export class TrainCar {
|
|||||||
h: number,
|
h: number,
|
||||||
sprite?: ISprite,
|
sprite?: ISprite,
|
||||||
) {
|
) {
|
||||||
|
super(true, "car");
|
||||||
this.img = img;
|
this.img = img;
|
||||||
this.sprite = sprite;
|
this.sprite = sprite;
|
||||||
this.imgWidth = w;
|
this.imgWidth = w;
|
||||||
@ -165,14 +185,14 @@ export class TrainCar {
|
|||||||
origin.copy().sub(this.imgWidth / 2, this.imgHeight / 2),
|
origin.copy().sub(this.imgWidth / 2, this.imgHeight / 2),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
const ctx = getContext();
|
override debugDraw(...args: unknown[]): void {
|
||||||
if (ctx.debug) {
|
if (!this.points) return;
|
||||||
doodler.drawLine(this.points, {
|
const doodler = getContextItem<Doodler>("doodler");
|
||||||
color: "blue",
|
doodler.drawLine(this.points, {
|
||||||
weight: 3,
|
color: "blue",
|
||||||
});
|
weight: 3,
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,4 +15,11 @@ declare global {
|
|||||||
bNeighbors: string[];
|
bNeighbors: string[];
|
||||||
fNeighbors: string[];
|
fNeighbors: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Debug = {
|
||||||
|
track: boolean;
|
||||||
|
train: boolean;
|
||||||
|
car: boolean;
|
||||||
|
path: boolean;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from "vite";
|
||||||
import deno from '@deno/vite-plugin'
|
import deno from "@deno/vite-plugin";
|
||||||
|
import { strip } from "./vite/plugins/strip.ts";
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [deno()],
|
plugins: [deno(), strip()],
|
||||||
})
|
});
|
||||||
|
67
vite/plugins/strip.ts
Normal file
67
vite/plugins/strip.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { Plugin } from "vite";
|
||||||
|
|
||||||
|
export function strip(): Plugin {
|
||||||
|
const p: Plugin = {
|
||||||
|
name: "debug-strip",
|
||||||
|
enforce: "pre",
|
||||||
|
apply: "build",
|
||||||
|
transform(code: string, id: string) {
|
||||||
|
if (!id.endsWith(".ts") || import.meta.env.DEV) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyword = "override debugDraw";
|
||||||
|
const results = [];
|
||||||
|
let currentIndex = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Find the next occurrence of the keyword starting from currentIndex.
|
||||||
|
const startIndex = code.indexOf(keyword, currentIndex);
|
||||||
|
if (startIndex === -1) {
|
||||||
|
break; // No more occurrences.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the first opening brace '{' after the keyword.
|
||||||
|
const braceStart = code.indexOf("{", startIndex);
|
||||||
|
if (braceStart === -1) {
|
||||||
|
// No opening brace found; skip this occurrence.
|
||||||
|
currentIndex = startIndex + keyword.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a counter to find the matching closing brace.
|
||||||
|
let openBraces = 0;
|
||||||
|
let endIndex = -1;
|
||||||
|
for (let i = braceStart; i < code.length; i++) {
|
||||||
|
if (code[i] === "{") {
|
||||||
|
openBraces++;
|
||||||
|
} else if (code[i] === "}") {
|
||||||
|
openBraces--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When openBraces returns to 0, we found the matching closing brace.
|
||||||
|
if (openBraces === 0) {
|
||||||
|
endIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a matching closing brace was found, extract the substring.
|
||||||
|
if (endIndex !== -1) {
|
||||||
|
results.push(code.substring(startIndex, endIndex + 1));
|
||||||
|
// Move the currentIndex past the extracted block.
|
||||||
|
currentIndex = endIndex + 1;
|
||||||
|
} else {
|
||||||
|
// If no matching closing brace is found, skip this occurrence.
|
||||||
|
currentIndex = startIndex + keyword.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const result of results) {
|
||||||
|
code = code.replace(result, "");
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return p;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user