Skip to content

Commit

Permalink
chore(types): entities, components and data types (#7)
Browse files Browse the repository at this point in the history
* wip custom IComponents and IEntities types

* update README.md

* chore(types): working

* chore(types): entities, components and data typed

* chore(types): entities, components and data typed
  • Loading branch information
alqubo authored Aug 4, 2023
1 parent 5bf801c commit f411211
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 108 deletions.
70 changes: 35 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,85 +95,85 @@ import {
SystemFunction,
} from "darker-engine";

export const Engine = darkerEngine();
export const Engine = darkerEngine()

enum EntityType {
EXAMPLE,
enum IEntities {
EXAMPLE_ENTITY,
}

enum Components {
EXAMPLE_COMPONENT = "EXAMPLE_COMPONENT",
enum IComponents {
EXAMPLE_COMPONENT,
OTHER_COMPONENT,
}

const exampleEntity = (): EntityType => ({
id: Engine.getUID(),
type: EntityType.EXAMPLE,
type: IEntities.EXAMPLE_ENTITY,
data: {
[Components.EXAMPLE_COMPONENT]: {
[IComponents.EXAMPLE_COMPONENT]: {
foo: "faa",
},
}
},
components: [
Components.EXAMPLE_COMPONENT,
],
});
components: [IComponents.EXAMPLE_COMPONENT],
})

const exampleSystem: SystemFunction = () => {
let interval;
let interval: number

Engine.onLoad(() => {
const onLoad = () => {
console.log("welcome!");
Engine.addEntity(exampleEntity());

interval = setInterval(() => {
const entityList = Engine.getEntityList();
const entityListByType = Engine.getEntityListByType(EntityType.EXAMPLE);
const entityListByType = Engine.getEntityListByType(IEntities.EXAMPLE_ENTITY);
const entityListByComponents = Engine.getEntityListByComponents(
Components.EXAMPLE_COMPONENT,
IComponents.EXAMPLE_COMPONENT,
);

console.log(`Entities`);
console.log(` - total: ${entityList.length}`);
console.log(` - type: ${entityListByType.length}`);
console.log(` - component: ${entityListByComponents.length}`);
}, 5_000);
});
}, 5000);
}

Engine.onDestroy(() => {
const onDestroy = () => {
clearInterval(interval);
console.log("bye!");
});
}

const onAdd = (entityId: number) => {
const onAdd = (id: number) => {
const entity = Engine.getEntity(id);
entity.updateComponent(Components.EXAMPLE_COMPONENT, { foo: "fii" });
};
entity.updateComponent?.(IComponents.EXAMPLE_COMPONENT, { foo: "fii" });
}

const onUpdate = (entityId: number, component: string) => {
const onUpdate = (id: number, component: IComponents) => {
const entity = Engine.getEntity(id);

if (component !== Components.EXAMPLE_COMPONENT) return;
if (component !== IComponents.EXAMPLE_COMPONENT) return;

const { foo } = entity.getComponent(Components.EXAMPLE_COMPONENT);
if (foo === "fii" && !entity.hasComponent("FAKE_COMPONENT")) {
entity.removeComponent(Components.EXAMPLE_COMPONENT);
const { foo } = entity.getComponent?.(IComponents.EXAMPLE_COMPONENT);
if (foo === "fii" && !entity.hasComponent?.(IComponents.OTHER_COMPONENT)) {
entity.removeComponent?.(IComponents.EXAMPLE_COMPONENT);
}
};
}

const onRemove = (entityId: number) => {
Engine.removeEntity(entityId);
};

return {
components: [
Components.EXAMPLE_COMPONENT,
],
id: Engine.getUID(),
components: [IComponents.EXAMPLE_COMPONENT],
onLoad,
onDestroy,
onAdd,
onUpdate,
onRemove,
};
};
}
}

Engine.setSystems(exampleSystem);
Engine.load();
Engine.load()
```
84 changes: 38 additions & 46 deletions src/engine.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { EngineFunction, EntityType, SystemFunction, SystemType } from './types.ts';
import { DarkerMap, EngineType, EntityType, SystemFunction, SystemType } from './types.ts';
import { uid } from './uid.ts';

export const engine: EngineFunction = () => {
let systems: SystemType[] = [];
let entityList: EntityType[] = [];
let typeEntityMap: number[][] = [];
let entityComponentMap: number[][] = [];
export const engine = <I extends string | number, C extends string | number, D>(): EngineType<
I,
C,
D
> => {
let systems: SystemType<C>[] = [];
let entityList: EntityType<I, C, D>[] = [];
let typeEntityMap: DarkerMap<I, number[]> = {} as DarkerMap<I, number[]>;
let entityComponentMap: DarkerMap<number, C[]> = {};
// Contains which components/data has every entity
let entityDataMap: any[] = [];
let entityDataMap: DarkerMap<number, any> = [];
// Contains which entities has every system
let systemEntitiesMap: number[][] = [];

const { getUID } = uid();

const setSystems = (..._systems: SystemFunction[]) => {
const setSystems = (..._systems: SystemFunction<C>[]) => {
systems = [];
systemEntitiesMap = [];

Expand All @@ -25,7 +29,7 @@ export const engine: EngineFunction = () => {
});
};

const _entity_removeComponent = (entityId: number, component: number) => {
const _entity_removeComponent = (entityId: number, component: C) => {
const entity = getEntity(entityId);
entityComponentMap[entityId] = entityComponentMap[entityId].filter(
(_component) => _component !== component,
Expand Down Expand Up @@ -59,7 +63,7 @@ export const engine: EngineFunction = () => {

const _entity_updateComponent = (
entityId: number,
component: number,
component: C,
data = {},
) => {
const entity = getEntity(entityId);
Expand Down Expand Up @@ -96,7 +100,7 @@ export const engine: EngineFunction = () => {

const _entity_addComponent = (
entityId: number,
component: number,
component: C,
data = {},
) => {
const entity = getEntity(entityId);
Expand Down Expand Up @@ -134,12 +138,13 @@ export const engine: EngineFunction = () => {
// TODO: maintain original order, not this shit
const _entity_getComponents = (entityId: number) => entityComponentMap[entityId];

const _entity_getComponent = (
const _entity_getComponent = <T extends keyof D>(
entityId: number,
component: number,
component: T,
deepClone = false,
) => {
): D[T] | undefined => {
const entityData = entityDataMap[entityId];

return entityData && entityData[component]
? (
deepClone ? structuredClone(entityData[component]) : { ...entityData[component] }
Expand All @@ -152,46 +157,33 @@ export const engine: EngineFunction = () => {

const _entity_getData = (entityId: number) => structuredClone(entityDataMap[entityId]);

const getEntityList = (): EntityType[] => Object.values(entityList) || [];
const getEntityList = (): EntityType<I, C, D>[] => Object.values(entityList) || [];

const getEntityListByType = (type: number): EntityType[] =>
const getEntityListByType = (type: I): EntityType<I, C, D>[] =>
typeEntityMap[type]?.map((entityId) => entityList[entityId]) || [];

const getEntityListByComponents = (
...componentList: number[]
): EntityType[] => {
const entityIdList = entityComponentMap.reduce(
(acc: number[], element: number[], index: number) => {
if (element !== null) {
acc.push(index);
}
return acc;
},
[],
);

return entityIdList.reduce(
(currentEntityList, entityId, index) => {
const entityComponents = entityComponentMap[entityId];
if (
componentList.length === 0 ||
componentList.every((component) => entityComponents.includes(component))
) {
return [
...currentEntityList,
entityList[entityIdList[index]],
];
}
...componentList: C[]
): EntityType<I, C, D>[] => {
return entityList.reduce((list, entity) => {
const entityComponents = entityComponentMap[entity.id];
if (
componentList.length === 0 ||
componentList.every((component) => entityComponents.includes(component))
) {
return [
...list,
entity,
];
}

return currentEntityList;
},
Array<EntityType>(),
).filter(Boolean);
return list;
}, Array<EntityType<I, C, D>>()).filter(Boolean);
};

const getEntity = (entityId: number) => entityList[entityId];

const addEntity = (...entities: EntityType[]): EntityType[] => {
const addEntity = (...entities: EntityType<I, C, D>[]): EntityType<I, C, D>[] => {
const date = Date.now();
entities.forEach((entity) => {
entity.getData = () => _entity_getData(entity.id);
Expand Down Expand Up @@ -311,7 +303,7 @@ export const engine: EngineFunction = () => {
const clear = () => {
systems = [];
entityList = [];
typeEntityMap = [];
typeEntityMap = {} as DarkerMap<I, number[]>;
entityComponentMap = [];
entityDataMap = [];
systemEntitiesMap = [];
Expand Down
55 changes: 28 additions & 27 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/**
* Engine
*/
export interface EngineType {
setSystems: (...systems: SystemFunction[]) => void;
export interface EngineType<I, C extends string | number, D> {
setSystems: (...systems: SystemFunction<C>[]) => void;

getEntityList: () => EntityType[];
getEntityListByType: (type: number) => EntityType[];
getEntityListByComponents: (...componentList: number[]) => EntityType[];
getEntityList: () => EntityType<I, C, D>[];
getEntityListByType: (type: I) => EntityType<I, C, D>[];
getEntityListByComponents: (...componentList: C[]) => EntityType<I, C, D>[];

getEntity: (id: number) => EntityType;
addEntity: (...entities: EntityType[]) => EntityType[];
getEntity: (id: number) => EntityType<I, C, D>;
addEntity: (...entities: EntityType<I, C, D>[]) => EntityType<I, C, D>[];
removeEntity: (...idList: number[]) => void;

getSystem: (name: number) => SystemType | undefined;
getSystem: (name: number) => SystemType<C> | undefined;

clear: () => void;

Expand All @@ -22,47 +22,48 @@ export interface EngineType {
getUID: () => number;
}

export type EngineFunction = () => EngineType;

/**
* System
*/
export interface SystemType {
export interface SystemType<C> {
id: number;
components: number[];
components: C[];
onAdd?: (id: number) => void;
onUpdate?: (id: number, component?: number) => void;
onUpdate?: (id: number, component?: C) => void;
onRemove?: (id: number) => void;

onLoad?: () => void;
onDestroy?: () => void;
}

export type SystemFunction = () => SystemType;
export type SystemFunction<C> = () => SystemType<C>;

/**
* Entity
*/
export interface EntityType {

export interface EntityType<I, C extends string | number, D> {
//Only initial declaration
readonly id: number;
readonly type: number;
readonly data: Record<number, any>;
readonly components: number[];
readonly type: I;
readonly data: Partial<D>;
readonly components: C[];

getData?: () => Record<number, any>;
getComponent?: <ComponentType>(
component: number,
getComponent?: <T extends keyof D>(
component: T,
deepClone?: boolean,
) => ComponentType;
getComponents?: () => number[];
) => D[T] | undefined;
getComponents?: () => C[];
hasComponent?: (component: number) => boolean;
updateComponent?: UpdateComponentFunctionType;
removeComponent?: RemoveComponentFunctionType;
updateComponent?: UpdateComponentFunctionType<C>;
removeComponent?: RemoveComponentFunctionType<C>;
}

export type UpdateComponentFunctionType = <ComponentType>(
component: number,
export type UpdateComponentFunctionType<C> = <ComponentType>(
component: C,
data: ComponentType,
) => void;
export type RemoveComponentFunctionType = (component: number) => void;
export type RemoveComponentFunctionType<C> = (component: C) => void;

export type DarkerMap<T extends string | number, S> = { [key in T]: S };

0 comments on commit f411211

Please sign in to comment.