destroy event listeners when code is stopped, refactor away codestopper

This commit is contained in:
Reimar 2025-10-14 14:49:36 +02:00
parent eb04bc72d1
commit 809c272bd8
4 changed files with 87 additions and 93 deletions

View File

@ -1,9 +1,10 @@
export class CodeRunner { export class CodeRunner {
constructor(console, codeStopper) { constructor(console, gamelib) {
this.console = console; this.console = console;
this.codeStopper = codeStopper; this.gamelib = gamelib;
this.isRunning = false; this.isRunning = false;
this.evalScope = {}; this.evalScope = {};
this.abortController = new AbortController();
globalThis.playgroundConsole = this.console; globalThis.playgroundConsole = this.console;
} }
@ -14,12 +15,13 @@ export class CodeRunner {
async run() { async run() {
this.isRunning = true; this.isRunning = true;
this.abortController = new AbortController();
this.gamelib.init();
this.console.clear(); this.console.clear();
this.console.log("Running code..."); this.console.log("Running code...");
this.codeStopper.start();
// Use RNG to prevent caching // Use RNG to prevent caching
const encodedText = encodeURIComponent( const encodedText = encodeURIComponent(
`let console=playgroundConsole;${this.code}/*(tph): ${Math.random()}*/`, `let console=playgroundConsole;${this.code}/*(tph): ${Math.random()}*/`,
@ -35,7 +37,10 @@ export class CodeRunner {
stop() { stop() {
this.isRunning = false; this.isRunning = false;
this.codeStopper.stop(); this.abortController.abort();
this.gamelib.destroy();
this.console.log("Stopping code..."); this.console.log("Stopping code...");
} }

View File

@ -1,24 +0,0 @@
export class CodeStopper {
constructor() {
this.abortController = new AbortController();
}
start() {
this.abortController = new AbortController();
}
stop() {
this.abortController.abort();
}
isStopped() {
return this.abortController.signal.aborted;
}
addListener(fn) {
this.abortController.signal
.addEventListener("abort", () => {
fn();
});
}
}

View File

@ -1,13 +1,5 @@
export class Gamelib { export class Gamelib {
keysPressed = new Set(); #loopInterval;
keyPressHandlers = new Map();
keyReleaseHandlers = new Map();
mouseMoveHandler = null;
mouseButtonsPressed = new Set();
mouseDownHandlers = new Map();
mouseUpHandlers = new Map();
mouseX = null;
mouseY = null;
MouseButton = { MouseButton = {
Left: 0, Left: 0,
@ -15,9 +7,8 @@ export class Gamelib {
Middle: 2, Middle: 2,
}; };
constructor(console, codeStopper, assetProvider, canvasElement) { constructor(console, assetProvider, canvasElement) {
this.console = console; this.console = console;
this.codeStopper = codeStopper;
this.assetProvider = assetProvider; this.assetProvider = assetProvider;
this.canvas = canvasElement; this.canvas = canvasElement;
@ -28,50 +19,37 @@ export class Gamelib {
this.cx = this.canvas.getContext("2d"); this.cx = this.canvas.getContext("2d");
this.cx.imageSmootingEnabled = false; this.cx.imageSmootingEnabled = false;
document.body.addEventListener("keydown", (ev) => { this.keysPressed = new Set();
this.keysPressed.add(ev.key); this.keyPressHandlers = new Map();
this.keyPressHandlers.get(ev.key)?.(); this.keyReleaseHandlers = new Map();
}); this.mouseMoveHandler = null;
this.mouseButtonsPressed = new Set();
this.mouseDownHandlers = new Map();
this.mouseUpHandlers = new Map();
this.mouseX = null;
this.mouseY = null;
}
document.body.addEventListener("keyup", (ev) => { init() {
this.keysPressed.delete(ev.key); document.body.addEventListener("keydown", this.#keydownListener.bind(this));
this.keyReleaseHandlers.get(ev.key)?.(); document.body.addEventListener("keyup", this.#keyupListener.bind(this));
});
canvasElement.addEventListener("mousemove", (ev) => { this.canvas.addEventListener("mousemove", this.#mousemoveListener.bind(this));
const ratioX = canvasElement.width / canvasElement.clientWidth; this.canvas.addEventListener("mousedown", this.#mousedownListener.bind(this));
const ratioY = canvasElement.height / canvasElement.clientHeight; this.canvas.addEventListener("mouseup", this.#mouseupListener.bind(this));
this.canvas.addEventListener("contextmenu", this.#contextMenuListener.bind(this));
}
this.mouseX = ev.offsetX * ratioX; destroy() {
this.mouseY = ev.offsetY * ratioY; document.body.removeEventListener("keydown", this.#keydownListener);
document.body.removeEventListener("keyup", this.#keyupListener);
this.mouseMoveHandler?.( this.canvas.removeEventListener("mousemove", this.#mousemoveListener);
ev.offsetX * ratioX, this.canvas.removeEventListener("mousedown", this.#mousedownListener);
ev.offsetY * ratioY, this.canvas.removeEventListener("mouseup", this.#mouseupListener);
ev.movementX * ratioX, this.canvas.removeEventListener("contextmenu", this.#contextMenuListener);
ev.movementY * ratioY,
);
});
canvasElement.addEventListener("mousedown", (ev) => { clearInterval(this.#loopInterval);
const ratioX = canvasElement.width / canvasElement.clientWidth;
const ratioY = canvasElement.height / canvasElement.clientHeight;
this.mouseButtonsPressed.add(ev.button);
this.mouseDownHandlers.get(ev.button)?.(ev.offsetX * ratioX, ev.offsetY * ratioY);
});
canvasElement.addEventListener("mouseup", (ev) => {
const ratioX = canvasElement.width / canvasElement.clientWidth;
const ratioY = canvasElement.height / canvasElement.clientHeight;
this.mouseButtonsPressed.delete(ev.button);
this.mouseUpHandlers.get(ev.button)?.(ev.offsetX * ratioX, ev.offsetY * ratioY);
});
canvasElement.addEventListener("contextmenu", (ev) => {
ev.preventDefault();
});
} }
println(msg) { println(msg) {
@ -80,7 +58,8 @@ export class Gamelib {
startGameLoop(loopFunction) { startGameLoop(loopFunction) {
let before = Date.now(); let before = Date.now();
const loopInterval = setInterval(() => {
this.#loopInterval = setInterval(() => {
const now = Date.now(); const now = Date.now();
const deltaT = (now - before) / 1000; const deltaT = (now - before) / 1000;
before = now; before = now;
@ -90,14 +69,16 @@ export class Gamelib {
this.console.error(error); this.console.error(error);
} }
}, 16); }, 16);
}
if (this.codeStopper?.isStopped()) { #keydownListener(ev) {
clearInterval(loopInterval); this.keysPressed.add(ev.key);
} this.keyPressHandlers.get(ev.key)?.();
}
this.codeStopper?.addListener(() => { #keyupListener(ev) {
clearInterval(loopInterval); this.keysPressed.delete(ev.key);
}); this.keyReleaseHandlers.get(ev.key)?.();
} }
isPressed(key) { isPressed(key) {
@ -112,6 +93,37 @@ export class Gamelib {
this.keyReleaseHandlers.set(key, handlerFunction); this.keyReleaseHandlers.set(key, handlerFunction);
} }
#mousemoveListener(ev) {
const ratioX = this.canvas.width / this.canvas.clientWidth;
const ratioY = this.canvas.height / this.canvas.clientHeight;
this.mouseX = ev.offsetX * ratioX;
this.mouseY = ev.offsetY * ratioY;
this.mouseMoveHandler?.(
ev.offsetX * ratioX,
ev.offsetY * ratioY,
ev.movementX * ratioX,
ev.movementY * ratioY,
);
}
#mousedownListener(ev) {
const ratioX = this.canvas.width / this.canvas.clientWidth;
const ratioY = this.canvas.height / this.canvas.clientHeight;
this.mouseButtonsPressed.add(ev.button);
this.mouseDownHandlers.get(ev.button)?.(ev.offsetX * ratioX, ev.offsetY * ratioY);
}
#mouseupListener(ev) {
const ratioX = this.canvas.width / this.canvas.clientWidth;
const ratioY = this.canvas.height / this.canvas.clientHeight;
this.mouseButtonsPressed.delete(ev.button);
this.mouseUpHandlers.get(ev.button)?.(ev.offsetX * ratioX, ev.offsetY * ratioY);
}
onMouseMove(handlerFunction) { onMouseMove(handlerFunction) {
this.mouseMoveHandler = handlerFunction; this.mouseMoveHandler = handlerFunction;
} }
@ -128,6 +140,10 @@ export class Gamelib {
this.mouseUpHandlers.set(button, handlerFunction); this.mouseUpHandlers.set(button, handlerFunction);
} }
#contextMenuListener(ev) {
ev.preventDefault();
}
rgb(red, green, blue) { rgb(red, green, blue) {
return `rgb(${red}, ${green}, ${blue})`; return `rgb(${red}, ${green}, ${blue})`;
} }

View File

@ -6,7 +6,6 @@ import { CodeRunner } from "./code_runner.js";
import { AssetEditor } from "./asset_editor.js"; import { AssetEditor } from "./asset_editor.js";
import { AssetProvider } from "./asset_provider.js"; import { AssetProvider } from "./asset_provider.js";
import { Gamelib } from "./gamelib.js"; import { Gamelib } from "./gamelib.js";
import { CodeStopper } from "./code_stopper.js";
import { KarlkoderCodec } from "./karlkoder_codec.js"; import { KarlkoderCodec } from "./karlkoder_codec.js";
import { promptUpload } from "./prompt_upload.js"; import { promptUpload } from "./prompt_upload.js";
import { GamelibCompleter } from "./gamelib_completer.js"; import { GamelibCompleter } from "./gamelib_completer.js";
@ -40,20 +39,14 @@ addEventListener("DOMContentLoaded", () => {
playgroundConsole.getInterface().log("Karlkode 1.0"); playgroundConsole.getInterface().log("Karlkode 1.0");
}); });
const codeStopper = new CodeStopper();
const assetProvider = new AssetProvider(); const assetProvider = new AssetProvider();
const codeRunner = new CodeRunner(playgroundConsole.getInterface(), codeStopper);
const assetEditor = new AssetEditor(document.querySelector("#asset-editor-container"), []); const assetEditor = new AssetEditor(document.querySelector("#asset-editor-container"), []);
new ConsoleInput(document.querySelector("#console-input"), playgroundConsole, codeRunner);
const htmlExporter = new HtmlExporter(assetProvider); const htmlExporter = new HtmlExporter(assetProvider);
const gamelib = new Gamelib( const gamelib = new Gamelib(
playgroundConsole.getInterface(), playgroundConsole.getInterface(),
codeStopper,
assetProvider, assetProvider,
document.querySelector("canvas"), document.querySelector("canvas"),
); );
@ -64,6 +57,10 @@ globalThis.karlkoder = {
}, },
}; };
const codeRunner = new CodeRunner(playgroundConsole.getInterface(), gamelib);
new ConsoleInput(document.querySelector("#console-input"), playgroundConsole, codeRunner);
const runButton = document.querySelector("#run-button"); const runButton = document.querySelector("#run-button");
const toggleAssetEditorButton = document.querySelector("#toggle-asset-editor-button"); const toggleAssetEditorButton = document.querySelector("#toggle-asset-editor-button");
const projectName = document.querySelector("#project-name"); const projectName = document.querySelector("#project-name");