diff --git a/assets/Script/ECS/lib/ECSEntity.ts b/assets/Script/ECS/lib/ECSEntity.ts deleted file mode 100755 index ade8172..0000000 --- a/assets/Script/ECS/lib/ECSEntity.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {ECSWorld} from "./ECSWorld" -import {ECSComConstructor, GetComConstructorType } from "./ECSComponent"; -import { ComPoolIndex, ComType } from "./Const"; -import { ECSComponentPool } from "./ECSComponentPool"; - -/** 实体 */ -export class Entity { - public id: number; // 唯一标识 - public index: number; // - public dead: boolean; // - - // 实体上的组件, 存放的是ComponentPool的index - private _components: Array = new Array(Object.keys(ComType).length/2).fill(-1); - - private _world: ECSWorld = null; - public get world(): ECSWorld { - return this._world; - } - public set world(world: ECSWorld) { - this._world = world; - } - - /** 获取实体上的组件 */ - public getComponent(typeOrFunc: ComType | {prototype: T}): ComPoolIndex { - let type = typeof typeOrFunc == 'number' ? typeOrFunc : GetComConstructorType(typeOrFunc); - let comPoolIdx = this._components[type]; - if(comPoolIdx == -1) return -1; - return comPoolIdx; - } - - /** 添加组件 */ - public addComponent(func: {prototype: T}): ComPoolIndex { - let type = GetComConstructorType(func); - if(this._components[type] !== -1) { - return this._components[type]; - } - let comPoolIdx = this._components[type] = this._world.getComponentPool(func).alloc(); - this._world.setEntityDirty(this); - return comPoolIdx; - } - - /** 移除组件 */ - public removeComponent(func: ECSComConstructor, dirty = true) { - let comPoolIdx = this._components[GetComConstructorType(func)]; - if(comPoolIdx == -1) { - console.error(`[ECSEntity]: removeComponent error, type: ${GetComConstructorType(func)}`); - return false; - } - this._components[GetComConstructorType(func)] = -1; - this._world.getComponentPool>(func).free(comPoolIdx); - dirty && this._world.setEntityDirty(this); - return true; - } - - /** 移除所有组件 */ - public removeAllComponents(dirty: boolean) { - for(let type = 0; type < this._components.length; type++) { - let comPoolIdx = this._components[type]; - if(comPoolIdx == -1) continue; - this._world.getComponentPool>(type).free(comPoolIdx); - } - this._components.fill(-1); - if(dirty) { - this._world.setEntityDirty(this); - } - } -} \ No newline at end of file diff --git a/assets/Script/ECS/lib/ECSEntity.ts.meta b/assets/Script/ECS/lib/ECSEntity.ts.meta deleted file mode 100755 index f609e4f..0000000 --- a/assets/Script/ECS/lib/ECSEntity.ts.meta +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ver": "1.1.0", - "uuid": "f6eafcbc-0cee-4a3d-90a7-d1d89d934869", - "importer": "typescript", - "isPlugin": false, - "loadPluginInWeb": true, - "loadPluginInNative": true, - "loadPluginInEditor": false, - "subMetas": {} -} \ No newline at end of file diff --git a/assets/Script/ECS/lib/ECSFillter.ts b/assets/Script/ECS/lib/ECSFillter.ts index bc3aed4..4426f67 100755 --- a/assets/Script/ECS/lib/ECSFillter.ts +++ b/assets/Script/ECS/lib/ECSFillter.ts @@ -1,5 +1,4 @@ import { ComType, EntityIndex } from "./Const"; -import { Entity } from "./ECSEntity"; import { ECSWorld } from "./ECSWorld"; export class ECSFillter { @@ -43,14 +42,14 @@ export class ECSFillter { }); } - public isAccept(entity: Entity) { + public isAccept(entityIndex: EntityIndex) { for(let i = 0; i < this._acceptComTypes.length; i++) { - if(entity.getComponent(this._acceptComTypes[i]) == -1) { + if(this._world.getComponentPoolIdx(entityIndex, this._acceptComTypes[i]) == -1) { return false; } } for(let i = 0; i < this._rejectComTypes.length; i++) { - if(entity.getComponent(this._rejectComTypes[i]) !== -1) { + if(this._world.getComponentPoolIdx(entityIndex, this._rejectComTypes[i]) != -1) { return false; } } diff --git a/assets/Script/ECS/lib/ECSWorld.ts b/assets/Script/ECS/lib/ECSWorld.ts index 4cd61a0..2e19f32 100755 --- a/assets/Script/ECS/lib/ECSWorld.ts +++ b/assets/Script/ECS/lib/ECSWorld.ts @@ -1,4 +1,3 @@ -import { Entity } from "./ECSEntity" import { ECSFillter } from "./ECSFillter" import { ECSComConstructor, GetComConstructor as GetComConstructor, GetComConstructorType } from "./ECSComponent"; import { ECSSystem } from "./ECSSystem"; @@ -10,14 +9,11 @@ import { ECSComponentPool } from "./ECSComponentPool"; */ export class ECSWorld { private _systems: ECSSystem[] = []; // world内所有的system - private _entities: Entity[] = []; // world内所有的entity private _reservedIds: number[] = []; // 缓存 - + private _entityToComponents: number[][] = []; private _componentPools: ECSComponentPool[] = []; private _fillters = new Map(); - - private _entitiesToDelete: number[] = []; - private _entityIdSeed: number = 0; + private _entitiesToDelete: Set = new Set(); /** 获取ComponentPool */ public getComponentPool(typeOrFunc: ComType | {prototype: T}): ECSComponentPool { @@ -32,20 +28,16 @@ export class ECSWorld { public addSystem(system: ECSSystem) { this._systems.push(system); system.onAdd(this); - for(let i = 0; i < this._entities.length; i++) { - if(this._entities[i].id !== -1) { - system.onEntityEnter(this, i); - } + for(let i = 0; i < this._entityToComponents.length; i++) { + system.onEntityEnter(this, i); } } /** 移除system */ public removeSystem(system: ECSSystem) { system.onRemove(this); - for(let i = 0; i < this._entities.length; i++) { - if(this._entities[i].id !== -1) { - system.onEntityLeave(this, i); - } + for(let i = 0; i < this._entityToComponents.length; i++) { + system.onEntityLeave(this, i); } for(let i = this._systems.length - 1; i >= 0; i--) { if(this._systems[i] == system) { @@ -56,83 +48,106 @@ export class ECSWorld { /** 创建实体 */ public createEntity(): number { - let entity: Entity = null; let index = -1; if(this._reservedIds.length > 0) { index = this._reservedIds.pop(); - entity = this._entities[index]; + this._entityToComponents[index].fill(-1); }else { - entity = new Entity(); - index = this._entities.length; - this._entities.push(entity); + index = this._entityToComponents.length; + this._entityToComponents[index] = new Array(Object.keys(ComType).length/2).fill(-1); } - entity.id = this._entityIdSeed++; - entity.world = this; - entity.index = index; - entity.dead = false; for(let system of this._systems) { - system.onEntityEnter(this, entity.index); + system.onEntityEnter(this, index); } - return entity.index; + return index; } /** 移除实体 */ - public removeEntity(entity: EntityIndex): boolean { - if(entity <= 0) return false; - if(!this._entities[entity] || this._entities[entity].dead) { + public removeEntity(entityIndex: EntityIndex): boolean { + if(entityIndex <= 0) return false; + if(!this._entityToComponents[entityIndex]) { console.warn(`[ECSWorld] removeEntity entity is removed`); return false; } - this._entities[entity].dead = true; - this._entitiesToDelete.push(entity); this._fillters.forEach((fillter, key) => { - fillter.isContains(entity) && fillter.onEntityLeave(entity); + fillter.isContains(entityIndex) && fillter.onEntityLeave(entityIndex); }); for(let system of this._systems) { - system.onEntityLeave(this, entity); + system.onEntityLeave(this, entityIndex); } + + this._entitiesToDelete.add(entityIndex); return true; } - public getComponent(entity: EntityIndex, com: {prototype: T}) { - if(!this._entities[entity]) return null; - let comPoolIdx = this._entities[entity].getComponent(com); + public getComponentPoolIdx(entityIndex: EntityIndex, com: {prototype: T} | ComType) { + let entity = this._entityToComponents[entityIndex]; + if(!entity) return -1; + let type = typeof com == 'number' ? com : GetComConstructorType(com); + return entity[type]; + } + + public getComponent(entityIndex: EntityIndex, com: {prototype: T} | ComType) { + let comPoolIdx = this.getComponentPoolIdx(entityIndex, com); + if(comPoolIdx == -1) return null; return this.getComponentPool(com).get(comPoolIdx); } - public removeComponent(entity: EntityIndex, com: ECSComConstructor) { - if(!this._entities[entity]) return ; - this._entities[entity].removeComponent(com); - } - - public addComponent(entity: EntityIndex, com: {prototype: T}) { - if(!this._entities[entity]) return null; - let comPoolIdx = this._entities[entity].addComponent(com); + public addComponent(entityIndex: EntityIndex, com: {prototype: T}, dirty = true) { + let entity = this._entityToComponents[entityIndex]; + if(!entity) return null; + let type = GetComConstructorType(com); + let comPoolIdx = entity[type]; + if(comPoolIdx == -1) { + comPoolIdx = this.getComponentPool(com).alloc(); + } + entity[type] = comPoolIdx; + dirty && this.setEntityDirty(entityIndex); return this.getComponentPool(com).get(comPoolIdx) } - public getSingletonComponent(com: {prototype: T}): T { - let entity = this._entities[0]; - let comPoolIdx = entity.getComponent(com); - let pool = this.getComponentPool(com); - if(comPoolIdx >= 0) return pool.get(comPoolIdx); - return pool.get(entity.addComponent(com)); + public removeComponent(entityIndex: EntityIndex, com: ECSComConstructor, dirty = true) { + let entity = this._entityToComponents[entityIndex]; + if(!entity) return true; + let type = GetComConstructorType(com); + let comPoolIdx = entity[type]; + if(comPoolIdx == -1) return true; + entity[type] = -1; + this.getComponentPool(com).free(comPoolIdx); + dirty && this.setEntityDirty(entityIndex); + return true; } - public setEntityDirty(entity: Entity): void { + public removeAllComponents(entityIndex: EntityIndex, dirty = true) { + let entity = this._entityToComponents[entityIndex]; + if(!entity) return null; + for(let i=0; i(com: {prototype: T}): T { + let component = this.getComponent(0, com); + if(!component) { + component = this.addComponent(0, com); + } + return component; + } + + public setEntityDirty(entityIndex: EntityIndex): void { this._fillters.forEach((fillter, key) => { - let accept = !entity.dead && fillter.isAccept(entity); - if(accept != fillter.isContains(entity.index)) { - accept ? fillter.onEntityEnter(entity.index) : fillter.onEntityLeave(entity.index); + let accept = !this._entitiesToDelete.has(entityIndex) && fillter.isAccept(entityIndex); + if(accept != fillter.isContains(entityIndex)) { + accept ? fillter.onEntityEnter(entityIndex) : fillter.onEntityLeave(entityIndex); } }); } - public getEntityId(entity: EntityIndex) : number { - return this._entities[entity].id; - } - public getFilter(fillterKey: string): ECSFillter { if(this._fillters.has(fillterKey)) { return this._fillters.get(fillterKey); @@ -143,10 +158,9 @@ export class ECSWorld { let fillter = new ECSFillter(this, accept, reject); this._fillters.set(fillterKey, fillter); // 将当期的entity放入fillter - for(let i=1; i 0) { + if(this._entitiesToDelete.size > 0) { this._realRemoveEntity(); } } private _realRemoveEntity() { - for(let entityIdx of this._entitiesToDelete) { - this._entities[entityIdx].removeAllComponents(false); - this._entities[entityIdx].id = -1; - this._reservedIds.push(entityIdx); - } - this._entitiesToDelete.length = 0; + this._entitiesToDelete.forEach((value) => { + this.removeAllComponents(value); + this._reservedIds.push(value); + }); + this._entitiesToDelete.clear(); } }