Change typings to distinguish dense and sparse stores, and have the container add the "generation" field instead of the container
This commit is contained in:
parent
e8415da145
commit
8434e7046c
5 changed files with 36 additions and 37 deletions
|
@ -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",
|
||||
|
|
|
@ -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<Location> = [];
|
||||
bounds: Store<Polygon> = [];
|
||||
renderBounds: Store<RenderBounds> = {};
|
||||
renderSprite: Store<RenderSprite> = {};
|
||||
collisionSourceClass: Store<CollisionClass> = {};
|
||||
collisionTargetClass: Store<CollisionClass> = {};
|
||||
renderBounds: SparseStore<RenderBounds> = {};
|
||||
renderSprite: SparseStore<RenderSprite> = {};
|
||||
collisionSourceClass: SparseStore<CollisionClass> = {};
|
||||
collisionTargetClass: SparseStore<CollisionClass> = {};
|
||||
}
|
||||
|
|
|
@ -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> = (T & Component)[] | Record<number, T & Component>;
|
||||
export type Store<T> = (T & HasGeneration)[];
|
||||
export type SparseStore<T> = Record<number, T & HasGeneration>;
|
||||
export class Data {
|
||||
entity: EntityState[] = [];
|
||||
entity: Store<EntityState> = [];
|
||||
|
||||
[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<T, N> = {
|
||||
[P in keyof T]: P extends N ? never : P
|
||||
}[keyof T];
|
||||
type Assigner<DATA extends Data> = {
|
||||
[S in keyof DATA]?: Pick<DATA[S][number], StripKeys<DATA[S][number], "generation">>
|
||||
[S in keyof DATA]?: Pick<DATA[S][number], Exclude<keyof DATA[S][number], "generation">>
|
||||
};
|
||||
export function Create<DATA extends Data>(data: DATA, assign: Assigner<DATA>, 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 extends Data, K extends keyof DATA>(data: DATA, [id, generation]: Id, ...components: K[]): (Component | null)[] {
|
||||
export function Lookup<DATA extends Data, K extends keyof DATA>(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 extends Data, K extends keyof DATA>(data: DATA, ...components: K[]): [Id, ...Component[]][] {
|
||||
export function Join<DATA extends Data, K extends keyof DATA>(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 extends Data, K extends keyof DATA>(data: DATA, ...com
|
|||
}
|
||||
return results;
|
||||
}
|
||||
function JoinLoop(id: number, entities: Store<EntityState>, stores: Store<{}>[], results: [Id, ...Component[]][]) {
|
||||
const result: [Id, ...Component[]] = [[id, -1]];
|
||||
function JoinLoop(id: number, entities: Store<EntityState>, stores: (Store<{}>|SparseStore<{}>)[], results: [Id, ...{}[]][]) {
|
||||
const result: [Id, ...{}[]] = [[id, -1]];
|
||||
|
||||
let generation = -1;
|
||||
for (const store of stores) {
|
||||
|
|
|
@ -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<Apple> = [
|
||||
{generation: 5},
|
||||
{generation: 5},
|
||||
{generation: -1},
|
||||
|
@ -33,11 +33,11 @@ class TestData extends Data {
|
|||
{generation: 5},
|
||||
{generation: 5},
|
||||
];
|
||||
banana: Record<number, Banana> = {
|
||||
banana: SparseStore<Banana> = {
|
||||
3: {generation: 5, peeled: false},
|
||||
4: {generation: 5, peeled: true},
|
||||
};
|
||||
carrot: Record<number, Carrot> = {
|
||||
carrot: SparseStore<Carrot> = {
|
||||
0: {generation: 5, cronch: 1},
|
||||
1: {generation: 5, cronch: 1},
|
||||
2: {generation: 4, cronch: 10},
|
||||
|
|
|
@ -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<Boss> = {};
|
||||
bullet: Store<Bullet> = {};
|
||||
hp: Store<Hp> = {};
|
||||
lifetime: Store<Lifetime> = {};
|
||||
message: Store<Message> = {};
|
||||
boss: SparseStore<Boss> = {};
|
||||
bullet: SparseStore<Bullet> = {};
|
||||
hp: SparseStore<Hp> = {};
|
||||
lifetime: SparseStore<Lifetime> = {};
|
||||
message: SparseStore<Message> = {};
|
||||
}
|
||||
|
||||
export enum Teams {
|
||||
|
|
Loading…
Reference in a new issue