@valeera/x
Version:
ECS framework written in TS for web application.
132 lines (108 loc) • 4.44 kB
text/typescript
import { IdGeneratorInstance } from "./Global";
import { TreeNode } from "@valeera/tree";
import { Component, ComponentConstructor } from "./Component";
import { World } from "./World";
import { IECSObject } from "./interfaces/IECSObject";
import { add, clear, get, has, remove } from "./utils/ecsManagerOperations";
import { EntitiesCache } from "./cache";
export type EntityConstructor = new (...args: any[]) => Entity;
export class Entity extends TreeNode implements IECSObject<World> {
public readonly id: number = IdGeneratorInstance.next();
public readonly isEntity = true;
public readonly components = new Map<number, Component<any>>();
public disabled = false;
public name: string;
public usedBy: World[] = [];
public children: Entity[] = [];
public constructor(name = "Untitled Entity") {
super();
this.name = name;
}
public add<T extends EntityConstructor>(child: T, ...args: ConstructorParameters<T>): this;
public add<T extends ComponentConstructor<any>>(componentOrChild: T, ...args: ConstructorParameters<T>): this;
public add(componentOrChild: Component<any> | Entity): this
public add(componentOrChild: Component<any> | Entity | ComponentConstructor<any> | EntityConstructor, ...args: ConstructorParameters<ComponentConstructor<any> | EntityConstructor>[]): this {
if (componentOrChild instanceof Entity) {
return this.addChild(componentOrChild);
}
if (componentOrChild instanceof Component) {
return this.addComponent(componentOrChild);
}
return this.add(new componentOrChild(...args));
}
public addComponent(component: Component<any>): this;
public addComponent<T extends ComponentConstructor<any>>(componentOrChild: T, ...args: ConstructorParameters<T>): this;
public addComponent(component: Component<any> | ComponentConstructor<any>, ...args: ConstructorParameters<ComponentConstructor<any>>): this {
if (component instanceof Component) {
add(component, this.components, this as Entity);
} else {
add(new component(...args), this.components, this as Entity);
}
for (let i = 0, len = this.usedBy.length; i < len; i++) {
EntitiesCache.get(this.usedBy[i]).add(this);
}
return this;
}
public addChild<T extends EntityConstructor>(entity: T, ...args: ConstructorParameters<T>): this
public addChild(entity: Entity): this;
public addChild<T extends EntityConstructor>(entity: Entity | T, ...args: ConstructorParameters<T>): this {
const e = entity instanceof Entity ? entity : new entity(...args);
for (const world of this.usedBy) {
world.add(e);
}
return super.addChild(e);
}
public clone(cloneComponents?: boolean, includeChildren?: boolean) {
const entity = new (this.constructor as EntityConstructor)(this.name);
if (cloneComponents) {
this.components.forEach((component) => {
entity.addComponent(component.clone());
});
} else {
this.components.forEach((component) => {
entity.addComponent(component);
});
}
if (includeChildren) {
for (let i = 0, len = this.children.length; i < len; i++) {
entity.addChild(this.children[i].clone());
}
}
return entity;
}
public destroy(): this {
for (const manager of this.usedBy) {
manager.remove(this);
}
this.components.forEach((c) => {
c.destroy();
});
return clear(this.components, this as Entity) as this;
}
public getComponent<T>(nameOrId: string | number | ComponentConstructor<T>): Component<T> | null {
return get(this.components, nameOrId);
}
public hasComponent(component: Component<any> | string | number | ComponentConstructor<any>): boolean {
return has(this.components, component);
}
public remove(entityOrComponent: Entity | Component<any> | ComponentConstructor<any>) {
if (entityOrComponent instanceof Entity) {
return this.removeChild(entityOrComponent);
}
return this.removeComponent(entityOrComponent);
}
public removeChild(entity: Entity): this {
for (const world of this.usedBy) {
world.removeEntity(entity);
}
return super.removeChild(entity);
}
public removeComponent(component: Component<any> | string | ComponentConstructor<any>): this {
if (remove(this.components, component, this as Entity)) {
for (let i = 0, len = this.usedBy.length; i < len; i++) {
EntitiesCache.get(this.usedBy[i]).add(this);
}
}
return this;
}
}