Skip to content

Commit

Permalink
Overload addComponent to support both TypedComponent interface and ty…
Browse files Browse the repository at this point in the history
…pe: string interface. Tests
  • Loading branch information
anderoonies committed Aug 10, 2021
1 parent a52a2a2 commit b24f84f
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 34 deletions.
8 changes: 5 additions & 3 deletions docs/World.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,19 +219,21 @@ The `type` of the `Component` is used to check the types of the initial argument
class Position extends TypedComponent<{x: number, y?: number}> {};
class Texture extends TypedComponent<{filePath: string}> {};

const playerEntity = world.createEntityTypesafe({
const playerEntity = world.createEntityTypesafe<[{type: Position}, {type: Texture}]>({
id: 'Player', // optional
tags: ['Character', 'Visible'], //optional
c: [ // optional
{
type: Position,
x: 15
x: 15,
z: 1
// ^ errors
},
{
type: Texture,
filePath: "/assets/img.png",
}
}
]
});
```

Expand Down
6 changes: 4 additions & 2 deletions src/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ class Entity {
}

addComponent(properties) {
const type = properties.type;
let type = properties.type;
if (typeof type !== 'string') {
type = type.name;
}
const pool = this.world.componentPool.get(type);
if (pool === undefined) {
throw new Error(`Component "${type}" has not been registered.`);
Expand Down Expand Up @@ -163,7 +166,6 @@ class Entity {
}

destroy() {

if (this.destroyed) return;
if (this.world.refs[this.id]) {
for (const ref of this.world.refs[this.id]) {
Expand Down
46 changes: 17 additions & 29 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,11 @@ export interface IComponentUpdate {
}

type DefaultProperties = Record<string, any>;
type Constructor<T> = new (...args: any[]) => T;
type ComponentClass<T = DefaultProperties> = ClassType<Component<T>>;
type ClassType<T> = { new (): T };
type Constructor<T> = { new (...args: any[]): T };
type ComponentClass<T = DefaultProperties> = Constructor<Component<T>>;
export function TypedComponent<TProperties extends DefaultProperties>(
properties: TProperties
): ClassType<Component<TProperties>> & Constructor<Component & TProperties>;
properties?: TProperties
): Constructor<Component<TProperties>> & Constructor<Component & TProperties>;

export declare class Component<TProperties extends DefaultProperties = {}> {
preInit(initial: any): any;
Expand Down Expand Up @@ -192,21 +191,15 @@ export interface IEntityObject {
// export interface IWorldSubscriptions {
// [name: string]: System;
// }
type TypedComponentConfig<T = any> = T extends Component<infer TProperties>
type TypedComponentConfig<T> = T extends Component<infer TProperties>
? {
type: ClassType<T>;
type: Constructor<T>;
key?: string;
} & TProperties
: never;

export type TypedComponentConfigVal<T = any> = T extends Component<
infer TProperties
>
? {
type: ClassType<T>;
id?: string;
entity?: string;
} & TProperties
export type TypedComponentConfigVal<T> = T extends Component<infer TProperties>
? { type: Constructor<T>; id?: string; entity?: string } & TProperties
: never;

export declare class Entity {
Expand All @@ -225,11 +218,10 @@ export declare class Entity {
getComponents<T extends Component>(type: { new (): T }): Set<T>;
addTag(tag: string): void;
removeTag(tag: string): void;
addComponent(
properties: IComponentConfig | IComponentObject
): Component | undefined;
addTypedComponent<T extends Component>(
properties: TypedComponentConfig<T>
addComponent<T>(
properties: T extends Component<infer TProperties>
? TypedComponentConfig<T>
: IComponentConfig | IComponentObject
): Component | undefined;
removeComponent(component: Component | string): boolean;
getObject(componentIds?: boolean): IEntityObject;
Expand All @@ -251,15 +243,11 @@ export interface IEntityConfig {
c?: IComponentConfigValObject;
}

export type TypedEntityConfig<TComponents extends Component[] = []> = {
export type TypedEntityConfig<TComponents extends readonly any[]> = {
id?: string;
tags?: string[];
c?: {
[TComponent in keyof TComponents]: TComponents[TComponent] extends Component<
infer TProperties
>
? TypedComponentConfigVal<TComponents[TComponent]>
: never;
c: {
[K in keyof TComponents]: TypedComponentConfigVal<TComponents[K]>;
};
};

Expand Down Expand Up @@ -301,8 +289,8 @@ export declare class World {
logStats(freq: number, callback?: Function): void;

createEntity(definition: IEntityConfig | IEntityObject): Entity;
createEntityTypesafe<T extends Array<Component>>(
definition: TypedEntityConfig<T>
createEntityTypesafe<T extends readonly any[]>(
definition: TypedEntityConfig<[...T]>
): Entity;
getObject(): IEntityObject[];
createEntities(definition: IEntityConfig[] | IEntityObject[]): void;
Expand Down
7 changes: 7 additions & 0 deletions tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ describe('express components', () => {
expect(results.size).to.equal(1);
});

it('addComponent with type!=string', () => {
const e = ecs.createEntity({});
e.addComponent({ type: Position, x: 1 });
const results = ecs.createQuery().fromAll(Position).execute();
expect(results.size).to.equal(2);
});

it('entity refs', () => {
class Storage extends ECS.Component {
static properties = {
Expand Down

0 comments on commit b24f84f

Please sign in to comment.