diff --git a/dev/GraphBrowser.tsx b/dev/GraphBrowser.tsx index 872a866..260e54d 100644 --- a/dev/GraphBrowser.tsx +++ b/dev/GraphBrowser.tsx @@ -1,5 +1,6 @@ import "./GraphBrowser.css"; import { type Component, createSignal, onMount } from "solid-js"; +import { currentScene, sceneCache } from "#/engine/Scene.ts"; import { type Edge, type Graph, @@ -92,25 +93,13 @@ function hookEdge([a, b]: Edge): void { } export const GraphBrowser: Component<{ - graph: Graph; + graph: Graph; }> = (props) => { let canvasRef!: HTMLCanvasElement; const [width] = createSignal(300); const [height] = createSignal(300); - const nodes: Array> = [...props.graph.keys()]; - - const edges: Array> = props.graph.entries().reduce( - (acc, [node, neighbours]) => { - for (const neighbour of neighbours) { - acc.push([node, neighbour]); - } - return acc; - }, - [] as Array>, - ); - onMount(() => { const ctx: CanvasRenderingContext2D = canvasRef.getContext("2d", { alpha: false, @@ -118,8 +107,34 @@ export const GraphBrowser: Component<{ const damping = 0.8; - const activeNode = props.graph.keys().find((_, i) => i === 3); - const activeNeighbours = getNeighbours(props.graph, activeNode); + const nodes: Array> = [ + ...props.graph.keys(), + ].map((node: string) => ({ + name: node, + position: createVector(Math.random(), Math.random()), + velocity: createVector(), + acceleration: createVector(), + })); + + const edges: Array> = props.graph.entries().reduce( + (acc, [name, neighbours]) => { + const node = nodes.find((n) => n.name === name)!; + for (const neighbour of neighbours) { + const n = nodes.find((node) => node.name === neighbour); + if (n !== undefined) { + acc.push([node, n]); + } + } + return acc; + }, + [] as Array>, + ); + + const activeNode = props.graph + .keys() + .find((name) => name === currentScene.data.name); + + const activeNeighbours = getNeighbours(props.graph, activeNode!); const animate = (): void => { applyRepulsion(nodes); @@ -151,14 +166,10 @@ export const GraphBrowser: Component<{ } for (const node of nodes) { - if (node === activeNode) { + if (node.name === activeNode) { drawNode(node, ctx, "#ee459e"); } else { - if ( - activeNeighbours.includes( - node as PhysicsPartial & { label: string }, - ) - ) { + if (activeNeighbours.includes(node.name)) { drawNode(node, ctx, "#6572f5"); } else { drawNode(node, ctx, "#404249"); diff --git a/dev/main.tsx b/dev/main.tsx index 5a29e8d..65069bb 100644 --- a/dev/main.tsx +++ b/dev/main.tsx @@ -10,10 +10,13 @@ import { FileIcon, ZoomScanIcon, } from "#/dev/icons/index.ts"; -import { currentScene, loadScene, type SceneData } from "#/engine/Scene.ts"; +import { + currentScene, + type SceneData, + sceneGraph, + setScene, +} from "#/engine/Scene.ts"; import { setScale, viewport } from "#/engine/Viewport.ts"; -import { createGraph, type Edge, type Node } from "#/lib/Graph.ts"; -import { createVector, type Vector } from "#/lib/Vector.ts"; import { GraphBrowser } from "./GraphBrowser.tsx"; async function fetchScenes(): Promise { @@ -33,46 +36,6 @@ function adjustGameContainer(gameContainer: HTMLElement, width: number): void { const scenesRaw = await fetchScenes(); -type TestNode = Node<{ - position: Vector; - velocity: Vector; - acceleration: Vector; - label: string; -}>; - -function createTestNode(label: string): TestNode { - return { - label, - position: createVector(Math.random(), Math.random()), - velocity: createVector(), - acceleration: createVector(), - }; -} - -const nodes: Array = [ - createTestNode("foo"), - createTestNode("bar"), - createTestNode("lol"), - createTestNode("hai"), - createTestNode("sea"), - createTestNode("vot"), - createTestNode("zoe"), - createTestNode("asm"), -]; - -const edges: Array> = [ - [nodes[0], nodes[1]], - [nodes[0], nodes[2]], - [nodes[1], nodes[2]], - [nodes[2], nodes[3]], - [nodes[4], nodes[5]], - [nodes[4], nodes[3]], - [nodes[5], nodes[6]], - [nodes[3], nodes[6]], -]; - -const graph = createGraph(nodes, edges); - const DevTools: Component<{ gameContainer: HTMLElement }> = ({ gameContainer, }) => { @@ -103,7 +66,7 @@ const DevTools: Component<{ gameContainer: HTMLElement }> = ({ const setCurrentScene = async (items: ItemsRef): Promise => { const name = items.find((ref) => ref.item.isActive)!.item.label; - await loadScene(name); + await setScene(name); setEntities(mapSceneEntities(currentScene.data)); }; @@ -177,7 +140,7 @@ const DevTools: Component<{ gameContainer: HTMLElement }> = ({ - +
diff --git a/engine/Scene.ts b/engine/Scene.ts index ec5412b..4c2e59c 100644 --- a/engine/Scene.ts +++ b/engine/Scene.ts @@ -1,3 +1,4 @@ +import { useWithAsyncCache } from "#/lib/cache.ts"; import { type Graph, getNeighbours } from "#/lib/Graph.ts"; import { type Animate as AnimateEntity, @@ -38,7 +39,38 @@ export type SceneChangeCallback = (from: Scene, to: Scene) => void; const sceneDataMap = new Map(); const sceneProcessMap = new Map(); const sceneEntiyMap = new Map(); -const sceneGraph: Graph = new Map(); +export const sceneGraph: Graph = new Map(); + +export const [loadScene, sceneCache] = useWithAsyncCache( + async (name: string) => { + await import(`#/scenes/${name}/index.ts`); + + const data = sceneDataMap.get(name)!; + const entityInstanceMap = sceneEntiyMap.get(name)!; + entityInstanceMap.clear(); + + Promise.all( + data.entities.map(async (entity: Entity) => { + await import(`#/entities/${entity.name}/index.ts`); + + if (!entityInstanceMap.has(entity.name)) { + entityInstanceMap.set(entity.name, { + animate: entityAnimateMap.get(entity.name) ?? (() => {}), + process: entityProcessMap.get(entity.name) ?? (() => {}), + instances: [], + }); + } + + const instance: Entity = structuredClone({ + ...entityMap.get(entity.name)!, + ...entity, + }); + + entityInstanceMap.get(entity.name)!.instances.push(instance); + }), + ); + }, +); export const currentScene: Scene = { data: { @@ -77,8 +109,8 @@ function linkScenes(a: string, b: string): void { export function useScene(data: SceneData): { linkScenes: ( - ids: T, - ) => (id: T[number]) => Promise; + names: T, + ) => (name: T[number]) => Promise; process: (fn: Process) => void; } { sceneDataMap.set(data.name, data); @@ -91,7 +123,7 @@ export function useScene(data: SceneData): { } return async (id) => { - return changeScene(id); + return setScene(id); }; }, process(fn) { @@ -104,48 +136,17 @@ export function useScene(data: SceneData): { }; } -export function changeScene(id: string): Promise { - const data = sceneDataMap.get(id)!; - const process = sceneProcessMap.get(id)!; - const entityInstanceMap = sceneEntiyMap.get(id)!; - for (const neighbour of getNeighbours(sceneGraph, id)) { +export async function setScene(name: string): Promise { + await loadScene(name); + for (const neighbour of getNeighbours(sceneGraph, name)) { if (!sceneCache.has(neighbour)) { sceneCache.set(neighbour, loadScene(neighbour)); } } - currentScene.data = data; - currentScene.process = process; - currentScene.entityInstanceMap = entityInstanceMap; -} -export async function loadScene(id: string): Promise { - await import(`#/scenes/${id}/index.ts`); - - const data = sceneDataMap.get(id)!; - const process = sceneProcessMap.get(id)!; - const entityInstanceMap = sceneEntiyMap.get(id)!; - entityInstanceMap.clear(); - - Promise.all( - data.entities.map(async (entity: Entity) => { - await import(`#/entities/${entity.name}/index.ts`); - - if (!entityInstanceMap.has(entity.name)) { - entityInstanceMap.set(entity.name, { - animate: entityAnimateMap.get(entity.name) ?? (() => {}), - process: entityProcessMap.get(entity.name) ?? (() => {}), - instances: [], - }); - } - - const instance: Entity = structuredClone({ - ...entityMap.get(entity.name)!, - ...entity, - }); - - entityInstanceMap.get(entity.name)!.instances.push(instance); - }), - ); + const data = sceneDataMap.get(name)!; + const process = sceneProcessMap.get(name)!; + const entityInstanceMap = sceneEntiyMap.get(name)!; currentScene.data = data; currentScene.process = process; diff --git a/lib/cache.ts b/lib/cache.ts index 9a5a859..3b38cf1 100644 --- a/lib/cache.ts +++ b/lib/cache.ts @@ -1,7 +1,7 @@ export type Cache = Map; export type AsyncCache = Map>; -export function withCache T>( +export function withCache T>( callback: U, key: string, cache: Cache, @@ -18,7 +18,7 @@ export function withCache T>( }; } -export function withAsyncCache Promise>( +export function withAsyncCache Promise>( callback: U, key: string, cache: AsyncCache, @@ -36,7 +36,7 @@ export function withAsyncCache Promise>( } export function useWithCache( - callback: (...args: unknown[]) => T, + callback: (...args: any[]) => T, ): [(uri: string) => T, Cache] { const cache: Cache = new Map(); @@ -44,7 +44,7 @@ export function useWithCache( } export function useWithAsyncCache( - callback: (...args: unknown[]) => Promise, + callback: (...args: any[]) => Promise, ): [(uri: string) => Promise, AsyncCache] { const cache: AsyncCache = new Map(); diff --git a/main.ts b/main.ts index 5d13647..038d497 100644 --- a/main.ts +++ b/main.ts @@ -1,4 +1,4 @@ -import { currentScene, loadScene } from "#/engine/Scene.ts"; +import { currentScene, setScene } from "#/engine/Scene.ts"; import { initViewport, resetCtx, @@ -23,7 +23,7 @@ function animate(timestamp: number): void { } initViewport(); - await loadScene("testScene"); + await setScene("testScene"); resizeCanvas(currentScene.data.width, currentScene.data.height); self.addEventListener("resize", () => { diff --git a/scenes/barScene/data.json b/scenes/barScene/data.json index a894e26..5fb79f4 100644 --- a/scenes/barScene/data.json +++ b/scenes/barScene/data.json @@ -1,7 +1,7 @@ { "name": "barScene", - "width": 80, - "height": 48, + "width": 240, + "height": 160, "entities": [ { "name": "fooEntity", diff --git a/scenes/barScene/index.ts b/scenes/barScene/index.ts index 8a4c4a0..ea96f4a 100644 --- a/scenes/barScene/index.ts +++ b/scenes/barScene/index.ts @@ -3,8 +3,6 @@ import data from "./data.json"; const { process, linkScenes } = useScene(data); -// const changeScene = linkScenes(["testScene"] as const); - -// changeScene("testScene"); +linkScenes(["testScene"] as const); process((_ctx, _delta) => {}); diff --git a/scenes/fooScene/index.ts b/scenes/fooScene/index.ts index 8a4c4a0..d75f519 100644 --- a/scenes/fooScene/index.ts +++ b/scenes/fooScene/index.ts @@ -3,8 +3,6 @@ import data from "./data.json"; const { process, linkScenes } = useScene(data); -// const changeScene = linkScenes(["testScene"] as const); - -// changeScene("testScene"); +linkScenes(["barScene"] as const); process((_ctx, _delta) => {}); diff --git a/scenes/testScene/index.ts b/scenes/testScene/index.ts index 5bf8bd6..849e01b 100644 --- a/scenes/testScene/index.ts +++ b/scenes/testScene/index.ts @@ -1,6 +1,8 @@ import { useScene } from "#/engine/Scene.ts"; import data from "./data.json"; -const { process } = useScene(data); +const { process, linkScenes } = useScene(data); + +linkScenes(["fooScene"] as const); process((_ctx, _delta) => {});