remove unnecessary data structs Dict+MapArray
This commit is contained in:
@@ -1,22 +0,0 @@
|
|||||||
structure,size,latency_ns_avg,latency_ns_med
|
|
||||||
MapArray,100,0.03,0.03
|
|
||||||
Dictionary,100,0.00,0.00
|
|
||||||
Map,100,0.00,0.00
|
|
||||||
MapArray,250,0.05,0.05
|
|
||||||
Dictionary,250,0.00,0.00
|
|
||||||
Map,250,0.00,0.00
|
|
||||||
MapArray,500,0.09,0.09
|
|
||||||
Dictionary,500,0.00,0.00
|
|
||||||
Map,500,0.00,0.00
|
|
||||||
MapArray,999,0.16,0.16
|
|
||||||
Dictionary,999,0.01,0.00
|
|
||||||
Map,999,0.00,0.00
|
|
||||||
MapArray,2500,0.42,0.42
|
|
||||||
Dictionary,2500,0.01,0.01
|
|
||||||
Map,2500,0.01,0.01
|
|
||||||
MapArray,5000,0.81,0.80
|
|
||||||
Dictionary,5000,0.02,0.02
|
|
||||||
Map,5000,0.01,0.01
|
|
||||||
MapArray,10000,1.66,1.66
|
|
||||||
Dictionary,10000,0.05,0.04
|
|
||||||
Map,10000,0.02,0.02
|
|
||||||
|
@@ -1,89 +0,0 @@
|
|||||||
// bench/churn-sweep.ts
|
|
||||||
import { Bench } from "tinybench";
|
|
||||||
import { type Box, box } from "../engine/lib/box.ts";
|
|
||||||
import {
|
|
||||||
createDictionary,
|
|
||||||
deleteEntry,
|
|
||||||
setEntry,
|
|
||||||
} from "../engine/lib/Dictionary.ts";
|
|
||||||
import MapArray from "../engine/lib/MapArray.ts";
|
|
||||||
|
|
||||||
const SIZES = [100, 250, 500, 999, 2500, 5000, 10000];
|
|
||||||
const CHURN_N = 100;
|
|
||||||
const churnKeys = Array.from({ length: CHURN_N }, (_, i) => `churn-${i}`);
|
|
||||||
|
|
||||||
let sink = 0;
|
|
||||||
|
|
||||||
function makeBaseData(size: number): Array<[string, Box<number>]> {
|
|
||||||
const data: Array<[string, Box<number>]> = [];
|
|
||||||
let i = size;
|
|
||||||
while (i-- > 0) data.push([String(i), box(i)]);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Row = {
|
|
||||||
structure: string;
|
|
||||||
size: number;
|
|
||||||
latencyNsAvg: number;
|
|
||||||
latencyNsMed: number;
|
|
||||||
};
|
|
||||||
const rows: Row[] = [];
|
|
||||||
|
|
||||||
for (const size of SIZES) {
|
|
||||||
const baseData = makeBaseData(size);
|
|
||||||
|
|
||||||
const ma = new MapArray(structuredClone(baseData));
|
|
||||||
const dict = createDictionary(structuredClone(baseData));
|
|
||||||
const map = new Map(structuredClone(baseData));
|
|
||||||
|
|
||||||
const bench = new Bench({ name: `churn @ size=${size}`, time: 500 });
|
|
||||||
|
|
||||||
bench
|
|
||||||
.add("MapArray", () => {
|
|
||||||
for (const key of churnKeys) ma.set(key, box(1));
|
|
||||||
for (const key of churnKeys) ma.delete(key);
|
|
||||||
sink += ma.entries().length;
|
|
||||||
})
|
|
||||||
.add("Dictionary", () => {
|
|
||||||
for (const key of churnKeys) setEntry(dict, [key, box(1)]);
|
|
||||||
for (const key of churnKeys) deleteEntry(dict, key);
|
|
||||||
sink += dict.entries.length;
|
|
||||||
})
|
|
||||||
.add("Map", () => {
|
|
||||||
for (const key of churnKeys) map.set(key, box(1));
|
|
||||||
for (const key of churnKeys) map.delete(key);
|
|
||||||
sink += map.size;
|
|
||||||
});
|
|
||||||
|
|
||||||
await bench.run();
|
|
||||||
|
|
||||||
for (const task of bench.tasks) {
|
|
||||||
const res = task.result;
|
|
||||||
if (!res) continue;
|
|
||||||
rows.push({
|
|
||||||
structure: task.name,
|
|
||||||
size,
|
|
||||||
latencyNsAvg: res.latency.mean,
|
|
||||||
latencyNsMed: res.latency.p50 ?? res.latency.mean,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`-- size=${size} done --`);
|
|
||||||
console.table(bench.table());
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSV output
|
|
||||||
const header = "structure,size,latency_ns_avg,latency_ns_med";
|
|
||||||
const csvLines = rows.map(
|
|
||||||
(r) =>
|
|
||||||
`${r.structure},${r.size},${r.latencyNsAvg.toFixed(2)},${r.latencyNsMed.toFixed(2)}`,
|
|
||||||
);
|
|
||||||
const csv = [header, ...csvLines].join("\n");
|
|
||||||
|
|
||||||
(await Deno.writeTextFile?.("churn-sweep.csv", csv)) ??
|
|
||||||
(await import("node:fs/promises")).then((fs) =>
|
|
||||||
fs.writeFile("churn-sweep.csv", csv),
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log("\nWrote churn-sweep.csv");
|
|
||||||
console.log("sink (ignore):", sink);
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// bench/churn.ts
|
|
||||||
import { Bench } from "tinybench";
|
|
||||||
import { type Box, box } from "./../engine/lib/box.ts";
|
|
||||||
import {
|
|
||||||
createDictionary,
|
|
||||||
deleteEntry,
|
|
||||||
getEntry,
|
|
||||||
setEntry,
|
|
||||||
} from "./../engine/lib/Dictionary.ts";
|
|
||||||
import MapArray from "./../engine/lib/MapArray.ts";
|
|
||||||
|
|
||||||
const bench = new Bench({ name: "churn", time: 1000 });
|
|
||||||
|
|
||||||
const SIZE = 999;
|
|
||||||
const baseData: Array<[string, Box<number>]> = [];
|
|
||||||
{
|
|
||||||
let i = SIZE;
|
|
||||||
while (i-- > 0) baseData.push([String(i), box(i)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Churn keys: a rotating window of "new" entities not in the base set,
|
|
||||||
// so every set/delete pair actually does real insert+remove work
|
|
||||||
// rather than repeatedly hitting the same already-resident key.
|
|
||||||
const CHURN_N = 100;
|
|
||||||
const churnKeys = Array.from({ length: CHURN_N }, (_, i) => `churn-${i}`);
|
|
||||||
|
|
||||||
let sink = 0; // anti-DCE: something observable reads this later
|
|
||||||
|
|
||||||
function freshMapArray() {
|
|
||||||
return new MapArray(structuredClone(baseData));
|
|
||||||
}
|
|
||||||
function freshDictionary() {
|
|
||||||
return createDictionary(structuredClone(baseData));
|
|
||||||
}
|
|
||||||
function freshMap() {
|
|
||||||
return new Map(structuredClone(baseData));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each task rebuilds nothing per-iteration except doing insert+remove
|
|
||||||
// on a fixed churn window against a persistent SIZE-element base structure —
|
|
||||||
// this mirrors "N entities steady-state, M entering/leaving per frame".
|
|
||||||
const ma = freshMapArray();
|
|
||||||
const dict = freshDictionary();
|
|
||||||
const map = freshMap();
|
|
||||||
|
|
||||||
bench
|
|
||||||
.add("MapArray churn (set+delete)", () => {
|
|
||||||
for (const key of churnKeys) {
|
|
||||||
ma.set(key, box(1));
|
|
||||||
}
|
|
||||||
for (const key of churnKeys) {
|
|
||||||
ma.delete(key);
|
|
||||||
}
|
|
||||||
sink += ma.entries().length;
|
|
||||||
})
|
|
||||||
.add("Dictionary churn (set+delete)", () => {
|
|
||||||
for (const key of churnKeys) {
|
|
||||||
setEntry(dict, [key, box(1)]);
|
|
||||||
}
|
|
||||||
for (const key of churnKeys) {
|
|
||||||
deleteEntry(dict, key);
|
|
||||||
}
|
|
||||||
sink += dict.entries.length;
|
|
||||||
})
|
|
||||||
.add("Map churn (set+delete)", () => {
|
|
||||||
for (const key of churnKeys) {
|
|
||||||
map.set(key, box(1));
|
|
||||||
}
|
|
||||||
for (const key of churnKeys) {
|
|
||||||
map.delete(key);
|
|
||||||
}
|
|
||||||
sink += map.size;
|
|
||||||
});
|
|
||||||
|
|
||||||
await bench.run();
|
|
||||||
console.table(bench.table());
|
|
||||||
console.log("sink (ignore):", sink);
|
|
||||||
+4
-46
@@ -1,53 +1,11 @@
|
|||||||
import { Bench } from "tinybench";
|
import { Bench } from "tinybench";
|
||||||
import { type Box, box } from "./../engine/lib/box.ts";
|
|
||||||
import {
|
|
||||||
createDictionary,
|
|
||||||
forEntry,
|
|
||||||
getEntry,
|
|
||||||
} from "./../engine/lib/Dictionary.ts";
|
|
||||||
import MapArray from "./../engine/lib/MapArray.ts";
|
|
||||||
|
|
||||||
const bench = new Bench({ name: "MapArray get", time: 3000 });
|
const bench = new Bench({ name: "", time: 1000 });
|
||||||
let sink = 0;
|
let sink = 0;
|
||||||
|
|
||||||
const testData: Array<[string, Box<number>]> = [];
|
bench.add("", () => {
|
||||||
let i = 999;
|
sink += 1;
|
||||||
while (i-- > 0) {
|
});
|
||||||
testData.push([String(i), box(i)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ma = new MapArray(structuredClone(testData));
|
|
||||||
const dict = createDictionary(structuredClone(testData));
|
|
||||||
const map = new Map(structuredClone(testData));
|
|
||||||
|
|
||||||
bench
|
|
||||||
.add("MapArray iter/get reads", () => {
|
|
||||||
let sum = 0;
|
|
||||||
|
|
||||||
for (const [key] of ma.entries()) {
|
|
||||||
sum += ma.get(key)!.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
sink += sum;
|
|
||||||
})
|
|
||||||
.add("Dictionary iter/get reads", () => {
|
|
||||||
let sum = 0;
|
|
||||||
|
|
||||||
forEntry(dict, (_, key) => {
|
|
||||||
sum += getEntry(dict, key)!.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
sink += sum;
|
|
||||||
})
|
|
||||||
.add("Map iter/get reads", () => {
|
|
||||||
let sum = 0;
|
|
||||||
|
|
||||||
for (const [key] of map.entries()) {
|
|
||||||
sum += map.get(key)!.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
sink += sum;
|
|
||||||
});
|
|
||||||
|
|
||||||
await bench.run();
|
await bench.run();
|
||||||
|
|
||||||
|
|||||||
+6
-7
@@ -4,9 +4,8 @@ import {
|
|||||||
entityProcessMap,
|
entityProcessMap,
|
||||||
} from "#/engine/Entity.ts";
|
} from "#/engine/Entity.ts";
|
||||||
import { type Graph, getNeighbours } from "#/engine/Graph.ts";
|
import { type Graph, getNeighbours } from "#/engine/Graph.ts";
|
||||||
import { box } from "#/engine/lib/box";
|
import { type Box, box } from "#/engine/lib/box";
|
||||||
import { memoize } from "#/engine/lib/cache.ts";
|
import { memoize } from "#/engine/lib/cache.ts";
|
||||||
import MapArray from "#/engine/lib/MapArray.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;
|
||||||
@@ -24,7 +23,7 @@ export type SceneData = {
|
|||||||
entities: Array<EntityData<unknown>>;
|
entities: Array<EntityData<unknown>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ComponentsMap = Map<string, MapArray<string, unknown>>;
|
export type ComponentsMap = Map<string, Map<string, Box<unknown>>>;
|
||||||
|
|
||||||
export type Scene = {
|
export type Scene = {
|
||||||
data: SceneData;
|
data: SceneData;
|
||||||
@@ -113,7 +112,7 @@ const [loadScene, sceneCache] = memoize(async (name: string) => {
|
|||||||
const localEntityProcessMap = new Map<string, EntityProcess>();
|
const localEntityProcessMap = new Map<string, EntityProcess>();
|
||||||
sceneEntityProcessMap.set(name, localEntityProcessMap);
|
sceneEntityProcessMap.set(name, localEntityProcessMap);
|
||||||
|
|
||||||
const componentsMap = new Map<string, MapArray<string, unknown>>();
|
const componentsMap: ComponentsMap = new Map();
|
||||||
sceneComponentsMap.set(name, componentsMap);
|
sceneComponentsMap.set(name, componentsMap);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -138,7 +137,7 @@ const [loadScene, sceneCache] = memoize(async (name: string) => {
|
|||||||
if (componentsMap.has(key)) {
|
if (componentsMap.has(key)) {
|
||||||
componentsMap.get(key)!.set(id, boxedValue);
|
componentsMap.get(key)!.set(id, boxedValue);
|
||||||
} else {
|
} else {
|
||||||
componentsMap.set(key, new MapArray([[id, boxedValue]]));
|
componentsMap.set(key, new Map([[id, boxedValue]]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -179,6 +178,6 @@ export async function setScene(name: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function <T>(name: string): MapArray<string, T> {
|
export default function <T>(name: string): Map<string, Box<T>> {
|
||||||
return currentScene.components.get(name) as MapArray<string, T>;
|
return currentScene.components.get(name) as Map<string, Box<T>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import { expect, test } from "vitest";
|
|
||||||
import {
|
|
||||||
createDictionary,
|
|
||||||
type Dictionary,
|
|
||||||
deleteEntrySave,
|
|
||||||
forEntry,
|
|
||||||
getEntry,
|
|
||||||
setEntrySave,
|
|
||||||
} from "./Dictionary.ts";
|
|
||||||
|
|
||||||
test("Dictionary", () => {
|
|
||||||
const dict: Dictionary<string, number> = createDictionary([
|
|
||||||
["a", 1],
|
|
||||||
["b", 2],
|
|
||||||
["c", 3],
|
|
||||||
]);
|
|
||||||
setEntrySave(dict, "foo", 42);
|
|
||||||
setEntrySave(dict, "bar", 0);
|
|
||||||
deleteEntrySave(dict, "bar");
|
|
||||||
|
|
||||||
expect(getEntry(dict, "foo")).toBe(42);
|
|
||||||
expect(getEntry(dict, "bar")).toBe(undefined);
|
|
||||||
expect(dict.indices.size).toBe(dict.entries.length);
|
|
||||||
|
|
||||||
let sum = 0;
|
|
||||||
forEntry(dict, (value) => {
|
|
||||||
sum += value;
|
|
||||||
});
|
|
||||||
expect(sum).toBe(48);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Dictionary don't mutate, when used 'save', while iterating", () => {
|
|
||||||
const dict: Dictionary<string, number> = createDictionary([
|
|
||||||
["a", 1],
|
|
||||||
["b", 2],
|
|
||||||
["c", 3],
|
|
||||||
]);
|
|
||||||
|
|
||||||
let sum = 0;
|
|
||||||
forEntry(dict, (value, _, index) => {
|
|
||||||
if (index < 1) {
|
|
||||||
setEntrySave(dict, "d", 4);
|
|
||||||
setEntrySave(dict, "e", 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
sum += value;
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(sum).toBe(6);
|
|
||||||
expect(dict.indices.size === 5).toEqual(dict.entries.length === 5);
|
|
||||||
|
|
||||||
sum = 0;
|
|
||||||
forEntry(dict, (value, _, index) => {
|
|
||||||
if (index < 1) {
|
|
||||||
deleteEntrySave(dict, "d");
|
|
||||||
deleteEntrySave(dict, "e");
|
|
||||||
}
|
|
||||||
|
|
||||||
sum += value;
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(sum).toBe(15);
|
|
||||||
expect(dict.indices.size === 3).toEqual(dict.entries.length === 3);
|
|
||||||
});
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
export type Dictionary<K, V> = {
|
|
||||||
entries: Array<[K, V]>;
|
|
||||||
indices: Map<K, number>;
|
|
||||||
isIterating: boolean;
|
|
||||||
deleteQueue: Array<K>;
|
|
||||||
setQueue: Array<[K, V]>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function createDictionary<K, V>(
|
|
||||||
iterable?: Iterable<[K, V]>,
|
|
||||||
): Dictionary<K, V> {
|
|
||||||
const entries = iterable ? [...iterable] : [];
|
|
||||||
const indices = new Map(entries.map(([k], i) => [k, i]));
|
|
||||||
|
|
||||||
return {
|
|
||||||
entries,
|
|
||||||
indices,
|
|
||||||
isIterating: false,
|
|
||||||
deleteQueue: [],
|
|
||||||
setQueue: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteEntry<K, V>(dict: Dictionary<K, V>, key: K): void {
|
|
||||||
const index = dict.indices.get(key);
|
|
||||||
if (index === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const last = dict.entries.length - 1;
|
|
||||||
if (index !== last) {
|
|
||||||
dict.entries[index] = dict.entries[last];
|
|
||||||
dict.indices.set(dict.entries[index][0], index);
|
|
||||||
}
|
|
||||||
|
|
||||||
dict.entries.pop();
|
|
||||||
dict.indices.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteEntrySave<K, V>(dict: Dictionary<K, V>, key: K): void {
|
|
||||||
if (dict.isIterating) {
|
|
||||||
dict.deleteQueue.push();
|
|
||||||
} else {
|
|
||||||
deleteEntry(dict, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setEntry<K, V>(
|
|
||||||
dict: Dictionary<K, V>,
|
|
||||||
[key, value]: [K, V],
|
|
||||||
): void {
|
|
||||||
const index = dict.indices.get(key);
|
|
||||||
if (index === undefined) {
|
|
||||||
dict.indices.set(key, dict.entries.length);
|
|
||||||
dict.entries.push([key, value]);
|
|
||||||
} else {
|
|
||||||
dict.entries[index][1] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setEntrySave<K, V>(
|
|
||||||
dict: Dictionary<K, V>,
|
|
||||||
key: K,
|
|
||||||
value: V,
|
|
||||||
): void {
|
|
||||||
if (dict.isIterating) {
|
|
||||||
dict.setQueue.push([key, value]);
|
|
||||||
} else {
|
|
||||||
setEntry(dict, [key, value]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEntry<K, V>(dict: Dictionary<K, V>, key: K): V | undefined {
|
|
||||||
const index = dict.indices.get(key);
|
|
||||||
return index === undefined ? undefined : dict.entries[index][1];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function forEntry<K, V>(
|
|
||||||
dict: Dictionary<K, V>,
|
|
||||||
callback: (value: V, key: K, index: number) => void,
|
|
||||||
): void {
|
|
||||||
dict.isIterating = true;
|
|
||||||
for (let i = 0; i < dict.entries.length; i++) {
|
|
||||||
callback(dict.entries[i][1], dict.entries[i][0], i);
|
|
||||||
}
|
|
||||||
dict.isIterating = false;
|
|
||||||
|
|
||||||
while (dict.deleteQueue.length > 0) {
|
|
||||||
deleteEntry(dict, dict.deleteQueue.pop()!);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (dict.setQueue.length > 0) {
|
|
||||||
setEntry(dict, dict.setQueue.pop()!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { expect, test } from "vitest";
|
|
||||||
import { box } from "./box.ts";
|
|
||||||
import MapArray from "./MapArray.ts";
|
|
||||||
|
|
||||||
test("MapArray", () => {
|
|
||||||
const mapArray = new MapArray([
|
|
||||||
["a", box(1)],
|
|
||||||
["b", box(2)],
|
|
||||||
["c", box(3)],
|
|
||||||
]);
|
|
||||||
mapArray.set("foo", box(42));
|
|
||||||
mapArray.set("bar", box(0));
|
|
||||||
mapArray.delete("bar");
|
|
||||||
|
|
||||||
expect(mapArray.get("foo")!.value).toBe(42);
|
|
||||||
expect(mapArray.get("bar")).toBe(undefined);
|
|
||||||
expect(mapArray.map.size).toBe(mapArray.array.length);
|
|
||||||
expect(
|
|
||||||
mapArray.entries().reduce(
|
|
||||||
(a, c) => {
|
|
||||||
a[1].value = a[1].value + c[1].value;
|
|
||||||
return a;
|
|
||||||
},
|
|
||||||
["_", box(0)],
|
|
||||||
)[1].value,
|
|
||||||
).toBe(48);
|
|
||||||
});
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import type { Box } from "./box.ts";
|
|
||||||
|
|
||||||
export default class MapArray<K, V> {
|
|
||||||
map: Map<K, Box<V>>;
|
|
||||||
array: Array<[K, Box<V>]>;
|
|
||||||
|
|
||||||
constructor(iterable?: Iterable<[K, Box<V>]>) {
|
|
||||||
this.map = new Map(iterable);
|
|
||||||
this.array = iterable ? [...iterable] : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(key: K): void {
|
|
||||||
if (this.map.delete(key)) {
|
|
||||||
this.array[this.array.findIndex((e) => e[0] === key)] =
|
|
||||||
this.array[this.array.length - 1];
|
|
||||||
this.array.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key: K, value: Box<V>): void {
|
|
||||||
if (this.map.has(key)) {
|
|
||||||
this.array.find((e) => e[0] === key)![1] = value;
|
|
||||||
} else {
|
|
||||||
this.array.push([key, value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.map.set(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key: K): Box<V> | undefined {
|
|
||||||
return this.map.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
entries(): Array<[K, Box<V>]> {
|
|
||||||
return this.array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,13 +13,13 @@ sceneChangeSet.add((sceneData) => {
|
|||||||
drawables.length = 0;
|
drawables.length = 0;
|
||||||
|
|
||||||
const sprites = [
|
const sprites = [
|
||||||
...sceneComponentsMap.get(sceneData.name)!.get("sprite")!.map.values(),
|
...sceneComponentsMap.get(sceneData.name)!.get("sprite")!.values(),
|
||||||
] as Array<Box<Sprite>>;
|
] as Array<Box<Sprite>>;
|
||||||
|
|
||||||
sceneComponentsMap
|
sceneComponentsMap
|
||||||
.get(sceneData.name)!
|
.get(sceneData.name)!
|
||||||
.get("position")!
|
.get("position")!
|
||||||
.map.values()
|
.values()
|
||||||
.forEach((box, index) => {
|
.forEach((box, index) => {
|
||||||
drawables.push({
|
drawables.push({
|
||||||
position: box as Box<Vector>,
|
position: box as Box<Vector>,
|
||||||
|
|||||||
Reference in New Issue
Block a user