From 8434e7046cbd83b75dc6a103859a9d3b0bb2fb92 Mon Sep 17 00:00:00 2001 From: Tangent Wantwight Date: Wed, 15 Jan 2020 22:49:52 -0500 Subject: [PATCH] Change typings to distinguish dense and sparse stores, and have the container add the "generation" field instead of the container --- package.json | 3 ++- src/Ecs/Components.ts | 10 +++++----- src/Ecs/Data.ts | 34 ++++++++++++++++------------------ src/Ecs/test.ts | 14 +++++++------- src/Game/GameComponents.ts | 12 ++++++------ 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index 527dfe2..a86162e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "private": true, "scripts": { "build": "webpack", - "buildProduction": "webpack --mode=production" + "buildProduction": "webpack --mode=production", + "tsc:check": "tsc --noEmit" }, "author": "Tangent 128", "license": "ISC", diff --git a/src/Ecs/Components.ts b/src/Ecs/Components.ts index 9e0776f..f0a5a25 100644 --- a/src/Ecs/Components.ts +++ b/src/Ecs/Components.ts @@ -1,5 +1,5 @@ -import { Data as CoreData, Store } from "./Data"; +import { Data as CoreData, Store, SparseStore } from "./Data"; import { Layer, SpriteSheet } from "../Applet/Render"; export class Box { @@ -68,8 +68,8 @@ export class RenderSprite { export class Data extends CoreData { location: Store = []; bounds: Store = []; - renderBounds: Store = {}; - renderSprite: Store = {}; - collisionSourceClass: Store = {}; - collisionTargetClass: Store = {}; + renderBounds: SparseStore = {}; + renderSprite: SparseStore = {}; + collisionSourceClass: SparseStore = {}; + collisionTargetClass: SparseStore = {}; } diff --git a/src/Ecs/Data.ts b/src/Ecs/Data.ts index 1cbb58d..5eaabcf 100644 --- a/src/Ecs/Data.ts +++ b/src/Ecs/Data.ts @@ -1,25 +1,26 @@ -export interface Component { - generation: number; -} export type Id = [number, number]; -export enum Liveness { +export const enum Liveness { DEAD = 0, ALIVE = 1, INACTIVE = 2 } -export interface EntityState extends Component { +export interface HasGeneration { + generation: number; +} +export interface EntityState { alive: Liveness; } -export type Store = (T & Component)[] | Record; +export type Store = (T & HasGeneration)[]; +export type SparseStore = Record; export class Data { - entity: EntityState[] = []; + entity: Store = []; - [name: string]: Store<{}>; + [name: string]: Store<{}> | SparseStore<{}>; } /** @@ -29,11 +30,8 @@ export class Data { * @param state Liveness state, allows creating an inactive entity * @returns the new entity's ID and generation */ -type StripKeys = { - [P in keyof T]: P extends N ? never : P -}[keyof T]; type Assigner = { - [S in keyof DATA]?: Pick> + [S in keyof DATA]?: Pick> }; export function Create(data: DATA, assign: Assigner, state = Liveness.ALIVE): Id { const entities = data.entity; @@ -126,7 +124,7 @@ export function Lookup< * @param components names of components to look for * @returns the cooresponding components, with unfound ones replaced by nulls */ -export function Lookup(data: DATA, [id, generation]: Id, ...components: K[]): (Component | null)[] { +export function Lookup(data: DATA, [id, generation]: Id, ...components: K[]): ({} | null)[] { const entity = data.entity[id]; // inactive entities are fine to lookup, but dead ones are not if(entity && entity.generation == generation && entity.alive != Liveness.DEAD) { @@ -206,11 +204,11 @@ export function Join< * Query a Data collection for all Alive entities possessing the named set of Components. * @returns an array of tuples containing the matching entity [ID, generation]s & associated Components */ -export function Join(data: DATA, ...components: K[]): [Id, ...Component[]][] { +export function Join(data: DATA, ...components: K[]): [Id, ...{}[]][] { const entities = data.entity; - const stores: Store<{}>[] = components.map(name => data[name]); + const stores: (Store<{}>|SparseStore<{}>)[] = components.map(name => data[name]); - const results: [Id, ...Component[]][] = []; + const results: [Id, ...{}[]][] = []; const firstStore = stores[0]; if(Array.isArray(firstStore)) { for(let id = 0; id < firstStore.length; id++) { @@ -223,8 +221,8 @@ export function Join(data: DATA, ...com } return results; } -function JoinLoop(id: number, entities: Store, stores: Store<{}>[], results: [Id, ...Component[]][]) { - const result: [Id, ...Component[]] = [[id, -1]]; +function JoinLoop(id: number, entities: Store, stores: (Store<{}>|SparseStore<{}>)[], results: [Id, ...{}[]][]) { + const result: [Id, ...{}[]] = [[id, -1]]; let generation = -1; for (const store of stores) { diff --git a/src/Ecs/test.ts b/src/Ecs/test.ts index b11aa1d..69e8160 100644 --- a/src/Ecs/test.ts +++ b/src/Ecs/test.ts @@ -4,15 +4,15 @@ import { Loop } from "../Applet/Loop"; import { Layer, DrawSet } from "../Applet/Render"; import { Data, Location, Polygon, RenderBounds, CollisionClass } from "./Components"; import { FindCollisions } from "./Collision"; -import { Component, Join, Liveness, Remove, Create, Lookup } from "./Data"; +import { Join, Liveness, Remove, Create, Lookup, Store, SparseStore } from "./Data"; import { DumbMotion } from "./Location"; import { RunRenderBounds } from "./Renderers"; -interface Apple extends Component {} -interface Banana extends Component { +interface Apple {} +interface Banana { peeled: boolean } -interface Carrot extends Component { +interface Carrot { cronch: number } @@ -25,7 +25,7 @@ class TestData extends Data { {generation: 5, alive: Liveness.INACTIVE}, {generation: 5, alive: Liveness.ALIVE}, ]; - apple: Apple[] = [ + apple: Store = [ {generation: 5}, {generation: 5}, {generation: -1}, @@ -33,11 +33,11 @@ class TestData extends Data { {generation: 5}, {generation: 5}, ]; - banana: Record = { + banana: SparseStore = { 3: {generation: 5, peeled: false}, 4: {generation: 5, peeled: true}, }; - carrot: Record = { + carrot: SparseStore = { 0: {generation: 5, cronch: 1}, 1: {generation: 5, cronch: 1}, 2: {generation: 4, cronch: 10}, diff --git a/src/Game/GameComponents.ts b/src/Game/GameComponents.ts index 538dff5..2811c5b 100644 --- a/src/Game/GameComponents.ts +++ b/src/Game/GameComponents.ts @@ -1,5 +1,5 @@ import { Layer, DrawSet } from "../Applet/Render"; -import { Store } from "../Ecs/Data"; +import { SparseStore } from "../Ecs/Data"; import { Data as EcsData } from "../Ecs/Components"; export enum GamePhase { @@ -54,11 +54,11 @@ export class World { } export class Data extends EcsData { - boss: Store = {}; - bullet: Store = {}; - hp: Store = {}; - lifetime: Store = {}; - message: Store = {}; + boss: SparseStore = {}; + bullet: SparseStore = {}; + hp: SparseStore = {}; + lifetime: SparseStore = {}; + message: SparseStore = {}; } export enum Teams {