Update framework
This commit is contained in:
12
framework/ecs/component.d.ts
vendored
Normal file
12
framework/ecs/component.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export declare class BaseComponent {
|
||||
id: number;
|
||||
properties: any;
|
||||
constructor();
|
||||
clone(): BaseComponent;
|
||||
}
|
||||
export interface Component {
|
||||
id: number;
|
||||
properties: any;
|
||||
clone(): BaseComponent;
|
||||
new (): BaseComponent;
|
||||
}
|
11
framework/ecs/component.js
Normal file
11
framework/ecs/component.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export class BaseComponent {
|
||||
constructor() {
|
||||
this.id = 0;
|
||||
this.properties = {};
|
||||
}
|
||||
clone() {
|
||||
const comp = new BaseComponent();
|
||||
comp.properties = this.properties;
|
||||
return comp;
|
||||
}
|
||||
}
|
19
framework/ecs/entity.d.ts
vendored
Normal file
19
framework/ecs/entity.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { BaseComponent, Component } from './component';
|
||||
export declare class BaseEntity {
|
||||
id: number;
|
||||
components: Map<number, BaseComponent>;
|
||||
constructor();
|
||||
addComponent(component: Component): void;
|
||||
removeComponent(component: BaseComponent): void;
|
||||
getComponentIDs(): number[];
|
||||
getComponent(component: BaseComponent): BaseComponent;
|
||||
getComponentByID(id: number): BaseComponent;
|
||||
}
|
||||
export interface Entity {
|
||||
new (): BaseComponent;
|
||||
addComponent(component: Component): any;
|
||||
removeComponent(component: BaseComponent): any;
|
||||
getComponentIDs(): number[];
|
||||
getComponent(component: BaseComponent): any;
|
||||
getComponentByID(id: number): BaseComponent;
|
||||
}
|
23
framework/ecs/entity.js
Normal file
23
framework/ecs/entity.js
Normal file
@@ -0,0 +1,23 @@
|
||||
export class BaseEntity {
|
||||
constructor() {
|
||||
this.components = new Map();
|
||||
this.id = 0;
|
||||
}
|
||||
addComponent(component) {
|
||||
let comp = new component();
|
||||
comp.id = component.id;
|
||||
this.components.set(component.id, comp);
|
||||
}
|
||||
removeComponent(component) {
|
||||
this.components.delete(component.id);
|
||||
}
|
||||
getComponentIDs() {
|
||||
return [...this.components.keys()];
|
||||
}
|
||||
getComponent(component) {
|
||||
return this.components.get(component.id);
|
||||
}
|
||||
getComponentByID(id) {
|
||||
return this.components.get(id);
|
||||
}
|
||||
}
|
28
framework/ecs/index.d.ts
vendored
Normal file
28
framework/ecs/index.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Component } from './component';
|
||||
import { BaseEntity, Entity } from './entity';
|
||||
import { EventBus } from '../event-bus';
|
||||
import { Query } from './query';
|
||||
import { System } from './system';
|
||||
export declare class World {
|
||||
entities: Array<BaseEntity>;
|
||||
components: Map<number, Component>;
|
||||
componentNamesToIDs: Map<string, number>;
|
||||
systems: Set<System>;
|
||||
nextEntityID: number;
|
||||
nextComponentID: number;
|
||||
nextQueryID: number;
|
||||
queryCache: Array<Query>;
|
||||
eventBus: EventBus;
|
||||
constructor();
|
||||
run(): void;
|
||||
createSystem(systemExecutor: Function): void;
|
||||
addSystem(system: System): void;
|
||||
addEntity(entity: BaseEntity): void;
|
||||
removeEntity(entityToRemove: BaseEntity): void;
|
||||
createEntity(components: Array<Component>): BaseEntity;
|
||||
extendEntity(entity: Entity, components: Array<Component>): BaseEntity;
|
||||
createComponent(component: Component): Component;
|
||||
query(include: Array<Component>, exclude: Array<Component>): Array<BaseEntity>;
|
||||
createQuery(include: Array<Component>, exclude: Array<Component>): Query;
|
||||
markQueriesDirty(): void;
|
||||
}
|
105
framework/ecs/index.js
Normal file
105
framework/ecs/index.js
Normal file
@@ -0,0 +1,105 @@
|
||||
import { BaseEntity } from './entity';
|
||||
import { EventBus } from '../event-bus';
|
||||
import { Query } from './query';
|
||||
import { System } from './system';
|
||||
export class World {
|
||||
constructor() {
|
||||
this.nextEntityID = 0;
|
||||
this.nextComponentID = 0;
|
||||
this.nextQueryID = 0;
|
||||
this.entities = new Array();
|
||||
this.systems = new Set();
|
||||
this.components = new Map();
|
||||
this.componentNamesToIDs = new Map();
|
||||
this.queryCache = new Array();
|
||||
this.eventBus = new EventBus();
|
||||
}
|
||||
run() {
|
||||
this.systems.forEach((system) => {
|
||||
system.execute(this);
|
||||
});
|
||||
}
|
||||
createSystem(systemExecutor) {
|
||||
const newSystem = new System(systemExecutor);
|
||||
this.systems.add(newSystem);
|
||||
}
|
||||
addSystem(system) {
|
||||
this.systems.add(system);
|
||||
}
|
||||
addEntity(entity) {
|
||||
this.entities.push(entity);
|
||||
this.markQueriesDirty();
|
||||
}
|
||||
removeEntity(entityToRemove) {
|
||||
this.entities = this.entities.filter((entity) => entity !== entityToRemove);
|
||||
this.markQueriesDirty();
|
||||
}
|
||||
createEntity(components) {
|
||||
const newEntity = new BaseEntity();
|
||||
newEntity.id = this.nextEntityID;
|
||||
this.nextEntityID++;
|
||||
components.forEach((component) => {
|
||||
if (this.componentNamesToIDs.has(component.name)) {
|
||||
component.id = this.componentNamesToIDs.get(component.name);
|
||||
}
|
||||
else {
|
||||
this.componentNamesToIDs.set(component.name, this.nextComponentID);
|
||||
component.id = this.nextComponentID;
|
||||
this.nextComponentID++;
|
||||
}
|
||||
newEntity.addComponent(component);
|
||||
});
|
||||
this.entities.push(newEntity);
|
||||
this.markQueriesDirty();
|
||||
return newEntity;
|
||||
}
|
||||
extendEntity(entity, components) {
|
||||
const toClone = this.entities.find((found) => entity.name === found.constructor.name);
|
||||
const cloned = new BaseEntity();
|
||||
cloned.id = this.nextEntityID;
|
||||
this.nextEntityID++;
|
||||
toClone.components.forEach((component) => {
|
||||
cloned.addComponent(this.components.get(component.id));
|
||||
});
|
||||
components.forEach((component) => {
|
||||
if (this.componentNamesToIDs.has(component.name)) {
|
||||
component.id = this.componentNamesToIDs.get(component.name);
|
||||
}
|
||||
else {
|
||||
this.componentNamesToIDs.set(component.name, this.nextComponentID);
|
||||
component.id = this.nextComponentID;
|
||||
this.nextComponentID++;
|
||||
}
|
||||
cloned.addComponent(component);
|
||||
});
|
||||
this.entities.push(cloned);
|
||||
return cloned;
|
||||
}
|
||||
createComponent(component) {
|
||||
const newComponent = component;
|
||||
newComponent.id = this.nextComponentID;
|
||||
this.nextComponentID++;
|
||||
this.components.set(newComponent.id, newComponent);
|
||||
this.componentNamesToIDs.set(component.name, component.id);
|
||||
return newComponent;
|
||||
}
|
||||
query(include, exclude) {
|
||||
const query = new Query(include, exclude, this);
|
||||
const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude);
|
||||
if (cache) {
|
||||
return cache.execute();
|
||||
}
|
||||
this.queryCache.push(query);
|
||||
return query.execute();
|
||||
}
|
||||
createQuery(include, exclude) {
|
||||
const newQuery = new Query(include, exclude, this);
|
||||
newQuery.id = this.nextQueryID;
|
||||
this.nextQueryID++;
|
||||
this.queryCache.push(newQuery);
|
||||
return newQuery;
|
||||
}
|
||||
markQueriesDirty() {
|
||||
this.queryCache.forEach((query) => (query.isDirty = true));
|
||||
}
|
||||
}
|
15
framework/ecs/query.d.ts
vendored
Normal file
15
framework/ecs/query.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { World } from '.';
|
||||
import { Component } from './component';
|
||||
import { BaseEntity } from './entity';
|
||||
export declare class Query {
|
||||
include: Array<Component>;
|
||||
exclude: Array<Component>;
|
||||
world: World;
|
||||
id: number;
|
||||
private results;
|
||||
isDirty: boolean;
|
||||
includeComponentIds: number[];
|
||||
excludeComponentIds: number[];
|
||||
constructor(include: Array<Component>, exclude: Array<Component>, world: World);
|
||||
execute(): Array<BaseEntity>;
|
||||
}
|
34
framework/ecs/query.js
Normal file
34
framework/ecs/query.js
Normal file
@@ -0,0 +1,34 @@
|
||||
export class Query {
|
||||
constructor(include, exclude, world) {
|
||||
this.include = include;
|
||||
this.exclude = exclude;
|
||||
this.world = world;
|
||||
this.isDirty = true;
|
||||
this.results = new Array();
|
||||
this.includeComponentIds = include.map((component) => component.id);
|
||||
this.excludeComponentIds = exclude.map((component) => component.id);
|
||||
this.id = 0;
|
||||
}
|
||||
execute() {
|
||||
if (!this.isDirty && this.results) {
|
||||
return this.results;
|
||||
}
|
||||
let filtered;
|
||||
this.includeComponentIds = this.include.map((component) => this.world.componentNamesToIDs.get(component.name));
|
||||
this.excludeComponentIds = this.exclude.map((component) => this.world.componentNamesToIDs.get(component.name));
|
||||
const entities = this.world.entities.filter((entity) => {
|
||||
let ids = entity.getComponentIDs();
|
||||
// let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true);
|
||||
let excludes = ids
|
||||
.map((id) => this.excludeComponentIds.includes(id))
|
||||
.includes(true);
|
||||
let includes = ids.filter((id) => this.includeComponentIds.includes(id));
|
||||
return includes.length === this.includeComponentIds.length && !excludes;
|
||||
});
|
||||
if (entities.length > 0) {
|
||||
this.isDirty = false;
|
||||
this.results = entities;
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
}
|
6
framework/ecs/system.d.ts
vendored
Normal file
6
framework/ecs/system.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { World } from '.';
|
||||
export declare class System {
|
||||
executor: Function;
|
||||
constructor(executor: Function);
|
||||
execute(world: World): void;
|
||||
}
|
10
framework/ecs/system.js
Normal file
10
framework/ecs/system.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export class System {
|
||||
constructor(executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
execute(world) {
|
||||
if (this.executor) {
|
||||
this.executor(world);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user