This commit is contained in:
Schluffe
2026-03-06 23:03:33 +01:00
parent c6bb4abac0
commit eef8adfa5f
3 changed files with 54 additions and 133 deletions
+3 -3
View File
@@ -1,13 +1,13 @@
export type Process = (id: string, delta: number) => void; export type Process = (id: string, delta: number) => void;
export const entityProcessMap = new Map<string, Process>(); export const entityProcessMap = new Map<string, Process>();
export const entityBlueprintsMap = new Map<string, Map<string, unknown>>(); export const entityBlueprintMap = new Map<string, Map<string, unknown>>();
export function defineEntity<T extends { [key: string]: unknown }>( export function defineEntity<T extends { [key: string]: unknown }>(
name: string, name: string,
blueprints: T, blueprint: T,
): (fn: Process) => void { ): (fn: Process) => void {
entityBlueprintsMap.set(name, new Map(Object.entries(blueprints))); entityBlueprintMap.set(name, new Map(Object.entries(blueprint)));
return (fn) => { return (fn) => {
entityProcessMap.set(name, fn); entityProcessMap.set(name, fn);
+44 -122
View File
@@ -1,21 +1,22 @@
import { type Box, box } from "#/engine/Box.ts"; import { entityBlueprintMap, entityProcessMap } from "#/engine/Entity.ts";
import { type Drawable, draw, isDrawable } from "#/engine/Drawable.ts";
import { entityBlueprintsMap, entityProcessMap } from "#/engine/Entity.ts";
import { type Graph, getNeighbours } from "#/engine/Graph.ts"; import { type Graph, getNeighbours } from "#/engine/Graph.ts";
import { useWithAsyncCache } from "#/engine/lib/cache.ts"; import { useWithAsyncCache } from "#/engine/lib/cache.ts";
import type MapProxy from "#/engine/lib/MapProxy.ts"; import type MapProxy from "#/engine/lib/MapProxy.ts";
import { mulberry32 } from "#/engine/lib/mulberry32.ts";
import { animateSprite, type SpritePlayback } from "#/engine/Sprite.ts";
export type Process = (ctx: CanvasRenderingContext2D, delta: number) => void; export type Process = (ctx: CanvasRenderingContext2D, delta: number) => void;
export type PreProcess = () => void; export type PreProcess = () => void;
export type PostProcess = () => void; export type PostProcess = () => void;
export type EntityData<T> = {
name: string;
init: T;
};
export type SceneData = { export type SceneData = {
name: string; name: string;
width: number; width: number;
height: number; height: number;
entities: string[]; entities: Array<EntityData<unknown>>;
}; };
export type ComponentsMap = Map<string, MapProxy<string, unknown>>; export type ComponentsMap = Map<string, MapProxy<string, unknown>>;
@@ -38,41 +39,6 @@ export const scenePostProcessMap = new Map<string, PostProcess>();
export const sceneChangeSet = new Set<SceneChange>(); export const sceneChangeSet = new Set<SceneChange>();
export const sceneGraph: Graph<string> = new Map(); export const sceneGraph: Graph<string> = new Map();
export const [loadScene, sceneCache] = useWithAsyncCache(
async (name: string) => {
await import(`#/game/scenes/${name}/scene.ts`);
const data = sceneDataMap.get(name)!;
const entityInstanceMap = sceneEntiyMap.get(name)!;
entityInstanceMap.clear();
await Promise.all(
data.entities.map(async (entityData: EntityData, index: number) => {
await import(`#/game/entities/${entityData.name}/entity.ts`);
if (!entityInstanceMap.has(entityData.name)) {
entityInstanceMap.set(entityData.name, {
process: entityProcessMap.get(entityData.name) ?? (() => {}),
instances: [],
});
}
try {
entityInstanceMap.get(entityData.name)!.instances.push(
structuredClone({
...entityMap.get(entityData.name)!,
...entityData,
id: index,
}),
);
} catch (error) {
console.error(entityData.name, error);
}
}),
);
},
);
export const currentScene: Scene = { export const currentScene: Scene = {
data: { data: {
name: "", name: "",
@@ -81,29 +47,12 @@ export const currentScene: Scene = {
entities: [], entities: [],
}, },
process: () => {}, process: () => {},
entityMap: new Map(), components: new Map(),
}; };
function processEntities(delta: number): void { function processEntities(delta: number): void {
for (const entry of currentScene.entityMap.values()) { for (const entity of currentScene.data.entities) {
for (const instance of entry.instances) { entityProcessMap.get(entity.name)!("", delta); // TODO
entry.process(instance, delta);
}
}
}
function processSystems(ctx: CanvasRenderingContext2D, delta: number): void {
const drawables = sceneInstancesDrawMap.get(currentScene.data.name)!;
const animationsMap = sceneInstancesAnimationMap.get(currentScene.data.name)!;
for (const drawable of drawables.sort(
(a, b) => a.position.y - b.position.y,
)) {
// this dosn't belong here
if (animationsMap.has(drawable.id)) {
animateSprite(animationsMap.get(drawable.id)!.value, delta);
}
draw(ctx, drawable);
} }
} }
@@ -116,17 +65,28 @@ function linkScenes(a: string, b: string): void {
} }
export function defineScene(data: SceneData): { export function defineScene(data: SceneData): {
linkScenes: <T extends readonly string[]>(
names: T,
) => (name: T[number]) => Promise<void>;
process: (fn: Process) => void; process: (fn: Process) => void;
preProcess: (fn: PreProcess) => void; preProcess: (fn: PreProcess) => void;
postProcess: (fn: PostProcess) => void; postProcess: (fn: PostProcess) => void;
linkScenes: <T extends readonly string[]>(
names: T,
) => (name: T[number]) => Promise<void>;
} { } {
sceneDataMap.set(data.name, data); sceneDataMap.set(data.name, data);
sceneEntiyMap.set(data.name, new Map());
return { return {
process(fn) {
sceneProcessMap.set(data.name, (ctx, delta) => {
fn(ctx, delta);
processEntities(delta);
});
},
preProcess(fn) {
scenePreProcessMap.set(data.name, fn);
},
postProcess(fn) {
scenePostProcessMap.set(data.name, fn);
},
linkScenes(ids) { linkScenes(ids) {
for (const id of ids) { for (const id of ids) {
linkScenes(data.name, id); linkScenes(data.name, id);
@@ -136,22 +96,24 @@ export function defineScene(data: SceneData): {
return setScene(id); return setScene(id);
}; };
}, },
process(fn) {
sceneProcessMap.set(data.name, (ctx, delta) => {
fn(ctx, delta);
processEntities(delta);
processSystems(ctx, delta);
});
},
preProcess(fn) {
scenePreProcessMap.set(data.name, fn);
},
postProcess(fn) {
scenePostProcessMap.set(data.name, fn);
},
}; };
} }
const [loadScene, sceneCache] = useWithAsyncCache(async (name: string) => {
await import(`#/game/scenes/${name}/scene.ts`);
const data = sceneDataMap.get(name)!;
await Promise.all(
data.entities.map(
async (entityData: EntityData<unknown>, index: number) => {
await import(`#/game/entities/${entityData.name}/entity.ts`);
// TODO
},
),
);
});
export async function setScene(name: string): Promise<void> { export async function setScene(name: string): Promise<void> {
await loadScene(name); await loadScene(name);
for (const neighbour of getNeighbours(sceneGraph, name)) { for (const neighbour of getNeighbours(sceneGraph, name)) {
@@ -162,39 +124,15 @@ export async function setScene(name: string): Promise<void> {
const data = sceneDataMap.get(name)!; const data = sceneDataMap.get(name)!;
const process = sceneProcessMap.get(name)!; const process = sceneProcessMap.get(name)!;
const entityInstanceMap = sceneEntiyMap.get(name)!;
const drawableInstances: Array<Drawable & { id: number }> = [];
sceneInstancesDrawMap.set(data.name, drawableInstances);
const animateInstances: AnimationMap = new Map();
sceneInstancesAnimationMap.set(data.name, animateInstances);
for (const entity of entityInstanceMap.values()) {
for (const instance of entity.instances) {
if (isDrawable(instance)) {
drawableInstances.push(instance);
}
if (
(instance as { id: number; animation: object }).animation !== undefined
) {
animateInstances.set(
instance.id,
(instance as { id: number; animation: Box<SpritePlayback> })
.animation, // TODO
);
}
}
}
const preProcess = scenePreProcessMap.get(name); const preProcess = scenePreProcessMap.get(name);
if (preProcess) { if (preProcess) {
preProcess(sceneEntiyMap.get(name)!); preProcess();
} }
const postProcess = scenePostProcessMap.get(currentScene.data.name); const postProcess = scenePostProcessMap.get(currentScene.data.name);
if (postProcess) { if (postProcess) {
postProcess(sceneEntiyMap.get(name)!); postProcess();
} }
currentScene.data = data; currentScene.data = data;
@@ -202,27 +140,11 @@ export async function setScene(name: string): Promise<void> {
currentScene.process = process; currentScene.process = process;
currentScene.entityMap = entityInstanceMap; for (const callback of sceneChangeSet.values()) {
callback(data, currentScene.data);
for (const handler of sceneChangeSet.values()) {
handler(data, currentScene.data);
} }
} }
const next = mulberry32(54850268);
export function def(name: string): <T>(key: string, value: T) => void {
const id = next().toString(16).slice(2);
defineComponent<string>("name").set(id, name);
return (key, value) => {
const components = defineComponent(key);
components.set(id, value);
console.log(componentMap);
};
}
export default function <T>(name: string): MapProxy<string, T> { export default function <T>(name: string): MapProxy<string, T> {
return currentScene.components.get(name) as MapProxy<string, T>; return currentScene.components.get(name) as MapProxy<string, T>;
} }
+7 -8
View File
@@ -1,24 +1,23 @@
import { createCircle, strokeCircle } from "#/engine/Circle.ts"; import { createCircle, strokeCircle } from "#/engine/Circle.ts";
import { pointer } from "#/engine/Pointer.ts"; import { pointer } from "#/engine/Pointer.ts";
import { defineScene } from "#/engine/Scene.ts"; import { defineScene } from "#/engine/Scene.ts";
import { spriteSheetMap } from "#/engine/Sprite.ts";
import { createVector } from "#/engine/Vector"; import { createVector } from "#/engine/Vector";
import data from "./data.json"; import data from "./data.json";
const { process, preProcess, linkScenes } = defineScene(data); const { process, preProcess, postProcess, linkScenes } = defineScene(data);
linkScenes(["fooScene"] as const); linkScenes(["fooScene"] as const);
preProcess((entityInstanceMap) => { preProcess(() => {
const entry = entityInstanceMap.get("hero")!; console.log("pre: ", data.name);
const instance = entry.instances[0]; });
// const sheet = spriteSheetMap.get(instance.animation.src)!;
instance.position.x = data.width - 16; postProcess(() => {
instance.position.y = data.height - 16; console.log("post: ", data.name);
}); });
const cirle = createCircle(createVector(), 4); const cirle = createCircle(createVector(), 4);
process((ctx, _delta) => { process((ctx, _delta) => {
if (!pointer.isDown) { if (!pointer.isDown) {
cirle.position.x = pointer.position.x; cirle.position.x = pointer.position.x;