From c6b1755d3227747f968e3bdd45eba9253bb6875f Mon Sep 17 00:00:00 2001 From: kolaflash Date: Thu, 25 Dec 2025 20:01:32 +0100 Subject: [PATCH] Meh --- {public/assets => assets}/bgm.wav | Bin {public/assets => assets}/char-idle.png | Bin {public/assets => assets}/char-walk.png | Bin {public/assets => assets}/portal.png | Bin {public/assets => assets}/portal2.png | Bin {public/assets => assets}/tiles.png | Bin dev/main.tsx | 12 ++- engine/Entity.ts | 12 ++- engine/Scene.ts | 125 +++++++++++++----------- entities/fooEntity/index.ts | 23 +++++ entities/testEntity/index.ts | 6 +- lib/Sprite.ts | 10 ++ scenes/fooScene/data.json | 14 +++ scenes/fooScene/index.ts | 6 ++ scenes/testScene/data.json | 2 +- 15 files changed, 140 insertions(+), 70 deletions(-) rename {public/assets => assets}/bgm.wav (100%) rename {public/assets => assets}/char-idle.png (100%) rename {public/assets => assets}/char-walk.png (100%) rename {public/assets => assets}/portal.png (100%) rename {public/assets => assets}/portal2.png (100%) rename {public/assets => assets}/tiles.png (100%) create mode 100644 entities/fooEntity/index.ts create mode 100644 scenes/fooScene/data.json create mode 100644 scenes/fooScene/index.ts diff --git a/public/assets/bgm.wav b/assets/bgm.wav similarity index 100% rename from public/assets/bgm.wav rename to assets/bgm.wav diff --git a/public/assets/char-idle.png b/assets/char-idle.png similarity index 100% rename from public/assets/char-idle.png rename to assets/char-idle.png diff --git a/public/assets/char-walk.png b/assets/char-walk.png similarity index 100% rename from public/assets/char-walk.png rename to assets/char-walk.png diff --git a/public/assets/portal.png b/assets/portal.png similarity index 100% rename from public/assets/portal.png rename to assets/portal.png diff --git a/public/assets/portal2.png b/assets/portal2.png similarity index 100% rename from public/assets/portal2.png rename to assets/portal2.png diff --git a/public/assets/tiles.png b/assets/tiles.png similarity index 100% rename from public/assets/tiles.png rename to assets/tiles.png diff --git a/dev/main.tsx b/dev/main.tsx index cd367dd..831b31a 100644 --- a/dev/main.tsx +++ b/dev/main.tsx @@ -11,7 +11,7 @@ import { ZoomScanIcon, } from "#/dev/icons/index.ts"; import type { Entity } from "#/engine/Entity"; -import { currentScene, type SceneData } from "#/engine/Scene.ts"; +import { currentScene, loadScene, type SceneData } from "#/engine/Scene.ts"; import { setScale, viewport } from "#/engine/Viewport.ts"; async function fetchBrowserData(dir: string): Promise { @@ -42,9 +42,13 @@ const entites = mapSceneEntities(currentScene.data); let activeEntity = null; function setActiveEntity(entity: string): void { const [id, index] = entity.split(":"); - const entities = currentScene.entityMap.get(id)!.entities; + const entities = currentScene.entityInstanceMap.get(id)!.instances; activeEntity = entities[parseInt(index)] as Entity; - console.log(activeEntity.position); + console.log(activeEntity); +} + +function setCurrentScene(name: string): void { + loadScene(name); } function adjustGameContainer(gameContainer: HTMLElement, width: number): void { @@ -126,7 +130,7 @@ const DevTools: Component<{ gameContainer: HTMLElement }> = ({ > - +
diff --git a/engine/Entity.ts b/engine/Entity.ts index e06f822..de71dd3 100644 --- a/engine/Entity.ts +++ b/engine/Entity.ts @@ -1,5 +1,7 @@ import { createVector, type Vector } from "#/lib/Vector.ts"; +export type Indirect = never; + export type Entity = { id: string; position: Vector; @@ -14,10 +16,10 @@ export type Animate = ( export type Process = (entity: Entity, delta: number) => void; export const entityMap = new Map>(); -export const entityAnimateMap = new Map>(); -export const entityProcessMap = new Map>(); +export const entityAnimateMap = new Map>(); +export const entityProcessMap = new Map>(); -export function useEntity( +export function useEntity( id: string, data: T, ): { @@ -31,10 +33,10 @@ export function useEntity( }); return { - animate(fn: Animate): void { + animate(fn) { entityAnimateMap.set(id, fn); }, - process(fn: Process): void { + process(fn) { entityProcessMap.set(id, fn); }, }; diff --git a/engine/Scene.ts b/engine/Scene.ts index f6b8656..ed5685d 100644 --- a/engine/Scene.ts +++ b/engine/Scene.ts @@ -1,10 +1,11 @@ -import type { Vector } from "#/lib/Vector.ts"; +import { type Graph, getNeighbours } from "#/lib/Graph.ts"; import { type Animate as AnimateEntity, type Entity, entityAnimateMap, entityMap, entityProcessMap, + type Indirect, type Process as ProcessEntity, } from "./Entity.ts"; @@ -12,22 +13,21 @@ export type SceneData = { id: string; width: number; height: number; - entities: Array<{ - id: string; - position: Vector; - }>; + entities: Array>; }; +export type EntityInstanceMap = Map< + string, + { + animate: AnimateEntity; + process: ProcessEntity; + instances: Array>; + } +>; + export type Scene = { data: SceneData; - entityMap: Map< - string, - { - animate: AnimateEntity; - process: ProcessEntity; - entities: Array>; - } - >; + entityInstanceMap: EntityInstanceMap; process: Process; }; @@ -35,10 +35,10 @@ export type Process = (ctx: CanvasRenderingContext2D, delta: number) => void; export type SceneChangeCallback = (from: Scene, to: Scene) => void; -let sceneChangeCallback: SceneChangeCallback = (): void => {}; - const sceneDataMap = new Map(); const sceneProcessMap = new Map(); +const sceneEntiyMap = new Map(); +const sceneGraph: Graph = new Map(); export const currentScene: Scene = { data: { @@ -48,33 +48,50 @@ export const currentScene: Scene = { entities: [], }, process: () => {}, - entityMap: new Map(), + entityInstanceMap: new Map(), }; function animateEntities(ctx: CanvasRenderingContext2D, delta: number): void { - for (const entry of currentScene.entityMap.values()) { - for (const entity of entry.entities) { - entry.animate(entity as Entity, ctx, delta); + for (const entity of currentScene.entityInstanceMap.values()) { + for (const instance of entity.instances) { + entity.animate(instance as Entity, ctx, delta); } } } function processEntities(delta: number): void { - for (const entry of currentScene.entityMap.values()) { - for (const entity of entry.entities) { - entry.process(entity as Entity, delta); + for (const entity of currentScene.entityInstanceMap.values()) { + for (const instance of entity.instances) { + entity.process(instance as Entity, delta); } } } +function linkScenes(a: string, b: string): void { + if (sceneGraph.has(a)) { + sceneGraph.get(a)!.push(b); + } else { + sceneGraph.set(a, [b]); + } +} + export function useScene(data: SceneData): { + linkScenes: (ids: string[]) => () => Promise; process: (fn: Process) => void; } { sceneDataMap.set(data.id, data); + sceneEntiyMap.set(data.id, new Map()); return { - process(fn: Process): void { - sceneProcessMap.set(data.id, (ctx, delta): void => { + linkScenes(ids) { + for (const id of ids) { + linkScenes(data.id, id); + } + + return async () => {}; + }, + process(fn) { + sceneProcessMap.set(data.id, (ctx, delta) => { animateEntities(ctx, delta); processEntities(delta); fn(ctx, delta); @@ -83,43 +100,35 @@ export function useScene(data: SceneData): { }; } -export function setSceneChangeCallback(callback: SceneChangeCallback) { - sceneChangeCallback = callback; -} +export async function loadScene(id: string): Promise { + await import(`#/scenes/${id}/index.ts`); -export function changeScene(scene: Scene): void { - sceneChangeCallback(currentScene, scene); - currentScene.data = scene.data; - currentScene.process = scene.process; -} + const data = sceneDataMap.get(id)!; + const process = sceneProcessMap.get(id)!; + const entityInstanceMap = sceneEntiyMap.get(id)!; -export async function loadScene(name: string): Promise { - await import(`#/scenes/${name}/index.ts`); + Promise.all( + data.entities.map(async (entity: Entity) => { + await import(`#/entities/${entity.id}/index.ts`); + + if (!entityInstanceMap.has(entity.id)) { + entityInstanceMap.set(entity.id, { + animate: entityAnimateMap.get(entity.id) ?? (() => {}), + process: entityProcessMap.get(entity.id) ?? (() => {}), + instances: [], + }); + } + + const instance: Entity = { + ...structuredClone(entityMap.get(entity.id)!), + position: entity.position, + }; + + entityInstanceMap.get(entity.id)!.instances.push(instance); + }), + ); - const data = sceneDataMap.get(name)!; currentScene.data = data; - - for (const entityData of data.entities) { - await import(`#/entities/${entityData.id}/index.ts`); - - const entity = entityMap.get(entityData.id) as Entity; - const instance: Entity = { - ...structuredClone(entity), - position: entityData.position, - }; - - if (currentScene.entityMap.has(entity.id)) { - const entry = currentScene.entityMap.get(entity.id); - entry!.entities.push(instance); - } else { - currentScene.entityMap.set(entity.id, { - animate: entityAnimateMap.get(entityData.id) ?? (() => {}), - process: entityProcessMap.get(entityData.id) ?? (() => {}), - entities: [instance], - }); - } - } - - const process = sceneProcessMap.get(name)!; currentScene.process = process; + currentScene.entityInstanceMap = entityInstanceMap; } diff --git a/entities/fooEntity/index.ts b/entities/fooEntity/index.ts new file mode 100644 index 0000000..d5efa94 --- /dev/null +++ b/entities/fooEntity/index.ts @@ -0,0 +1,23 @@ +import charIdle from "#/assets/char-idle.png"; +import { useEntity } from "#/engine/Entity.ts"; +import { animateSprite, createAnimation } from "#/lib/Animation.ts"; +import { fromSrc, type Sprite } from "#/lib/Sprite.ts"; + +const idle: Sprite = await fromSrc(charIdle, 2, 4); + +const { animate, process } = useEntity("fooEntity", { + animation: createAnimation(2, 500), +}); + +animate((entity, ctx, delta) => { + animateSprite( + ctx, + idle, + entity.animation, + entity.position.x, + entity.position.y, + delta, + ); +}); + +process((entity, delta) => {}); diff --git a/entities/testEntity/index.ts b/entities/testEntity/index.ts index 7053c77..5530722 100644 --- a/entities/testEntity/index.ts +++ b/entities/testEntity/index.ts @@ -1,3 +1,5 @@ +import charIdle from "#/assets/char-idle.png"; +import charWalk from "#/assets/char-walk.png"; import { useEntity } from "#/engine/Entity.ts"; import { viewport } from "#/engine/Viewport.ts"; import { @@ -9,8 +11,8 @@ import { loadImage } from "#/lib/loadImage.ts"; import { createSprite } from "#/lib/Sprite.ts"; const sprites = { - idle: createSprite(await loadImage("/assets/char-idle.png"), 2, 4), - walk: createSprite(await loadImage("/assets/char-walk.png"), 4, 4), + idle: createSprite(await loadImage(charIdle), 2, 4), + walk: createSprite(await loadImage(charWalk), 4, 4), }; const { animate, process } = useEntity<{ diff --git a/lib/Sprite.ts b/lib/Sprite.ts index b1a2754..b809c5f 100644 --- a/lib/Sprite.ts +++ b/lib/Sprite.ts @@ -1,3 +1,5 @@ +import { loadImage } from "./loadImage.ts"; + export type Sprite = { image: HTMLImageElement; xFrames: number; @@ -20,6 +22,14 @@ export function createSprite( }; } +export async function fromSrc( + src: string, + xFrames: number, + yFrames: number, +): Promise { + return createSprite(await loadImage(src), xFrames, yFrames); +} + export function drawSprite( ctx: CanvasRenderingContext2D, sprite: Sprite, diff --git a/scenes/fooScene/data.json b/scenes/fooScene/data.json new file mode 100644 index 0000000..cbedab9 --- /dev/null +++ b/scenes/fooScene/data.json @@ -0,0 +1,14 @@ +{ + "id": "fooScene", + "width": 80, + "height": 48, + "entities": [ + { + "id": "fooEntity", + "position": { + "x": 24, + "y": 16 + } + } + ] +} diff --git a/scenes/fooScene/index.ts b/scenes/fooScene/index.ts new file mode 100644 index 0000000..5bf8bd6 --- /dev/null +++ b/scenes/fooScene/index.ts @@ -0,0 +1,6 @@ +import { useScene } from "#/engine/Scene.ts"; +import data from "./data.json"; + +const { process } = useScene(data); + +process((_ctx, _delta) => {}); diff --git a/scenes/testScene/data.json b/scenes/testScene/data.json index 79c9ae1..5c92173 100644 --- a/scenes/testScene/data.json +++ b/scenes/testScene/data.json @@ -11,7 +11,7 @@ } }, { - "id": "testEntity", + "id": "fooEntity", "position": { "x": 16, "y": 16