mirror of
https://github.com/kirikayakazuto/CocosCreator_ECS
synced 2024-12-25 03:09:21 +00:00
干掉entity类
This commit is contained in:
parent
625434393e
commit
bad7227eec
@ -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<ComPoolIndex> = new Array<ComPoolIndex>(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<T>(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<T>(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<T extends ECSComConstructor>(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<ECSComponentPool<T>>(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<ECSComponentPool<any>>(type).free(comPoolIdx);
|
|
||||||
}
|
|
||||||
this._components.fill(-1);
|
|
||||||
if(dirty) {
|
|
||||||
this._world.setEntityDirty(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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": {}
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
import { ComType, EntityIndex } from "./Const";
|
import { ComType, EntityIndex } from "./Const";
|
||||||
import { Entity } from "./ECSEntity";
|
|
||||||
import { ECSWorld } from "./ECSWorld";
|
import { ECSWorld } from "./ECSWorld";
|
||||||
|
|
||||||
export class ECSFillter {
|
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++) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(let i = 0; i < this._rejectComTypes.length; i++) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { Entity } from "./ECSEntity"
|
|
||||||
import { ECSFillter } from "./ECSFillter"
|
import { ECSFillter } from "./ECSFillter"
|
||||||
import { ECSComConstructor, GetComConstructor as GetComConstructor, GetComConstructorType } from "./ECSComponent";
|
import { ECSComConstructor, GetComConstructor as GetComConstructor, GetComConstructorType } from "./ECSComponent";
|
||||||
import { ECSSystem } from "./ECSSystem";
|
import { ECSSystem } from "./ECSSystem";
|
||||||
@ -10,14 +9,11 @@ import { ECSComponentPool } from "./ECSComponentPool";
|
|||||||
*/
|
*/
|
||||||
export class ECSWorld {
|
export class ECSWorld {
|
||||||
private _systems: ECSSystem[] = []; // world内所有的system
|
private _systems: ECSSystem[] = []; // world内所有的system
|
||||||
private _entities: Entity[] = []; // world内所有的entity
|
|
||||||
private _reservedIds: number[] = []; // 缓存
|
private _reservedIds: number[] = []; // 缓存
|
||||||
|
private _entityToComponents: number[][] = [];
|
||||||
private _componentPools: ECSComponentPool<any>[] = [];
|
private _componentPools: ECSComponentPool<any>[] = [];
|
||||||
private _fillters = new Map<string, ECSFillter>();
|
private _fillters = new Map<string, ECSFillter>();
|
||||||
|
private _entitiesToDelete: Set<EntityIndex> = new Set();
|
||||||
private _entitiesToDelete: number[] = [];
|
|
||||||
private _entityIdSeed: number = 0;
|
|
||||||
|
|
||||||
/** 获取ComponentPool */
|
/** 获取ComponentPool */
|
||||||
public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
|
public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
|
||||||
@ -32,20 +28,16 @@ export class ECSWorld {
|
|||||||
public addSystem(system: ECSSystem) {
|
public addSystem(system: ECSSystem) {
|
||||||
this._systems.push(system);
|
this._systems.push(system);
|
||||||
system.onAdd(this);
|
system.onAdd(this);
|
||||||
for(let i = 0; i < this._entities.length; i++) {
|
for(let i = 0; i < this._entityToComponents.length; i++) {
|
||||||
if(this._entities[i].id !== -1) {
|
system.onEntityEnter(this, i);
|
||||||
system.onEntityEnter(this, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 移除system */
|
/** 移除system */
|
||||||
public removeSystem(system: ECSSystem) {
|
public removeSystem(system: ECSSystem) {
|
||||||
system.onRemove(this);
|
system.onRemove(this);
|
||||||
for(let i = 0; i < this._entities.length; i++) {
|
for(let i = 0; i < this._entityToComponents.length; i++) {
|
||||||
if(this._entities[i].id !== -1) {
|
system.onEntityLeave(this, i);
|
||||||
system.onEntityLeave(this, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(let i = this._systems.length - 1; i >= 0; i--) {
|
for(let i = this._systems.length - 1; i >= 0; i--) {
|
||||||
if(this._systems[i] == system) {
|
if(this._systems[i] == system) {
|
||||||
@ -56,83 +48,106 @@ export class ECSWorld {
|
|||||||
|
|
||||||
/** 创建实体 */
|
/** 创建实体 */
|
||||||
public createEntity(): number {
|
public createEntity(): number {
|
||||||
let entity: Entity = null;
|
|
||||||
let index = -1;
|
let index = -1;
|
||||||
if(this._reservedIds.length > 0) {
|
if(this._reservedIds.length > 0) {
|
||||||
index = this._reservedIds.pop();
|
index = this._reservedIds.pop();
|
||||||
entity = this._entities[index];
|
this._entityToComponents[index].fill(-1);
|
||||||
}else {
|
}else {
|
||||||
entity = new Entity();
|
index = this._entityToComponents.length;
|
||||||
index = this._entities.length;
|
this._entityToComponents[index] = new Array<ComPoolIndex>(Object.keys(ComType).length/2).fill(-1);
|
||||||
this._entities.push(entity);
|
|
||||||
}
|
}
|
||||||
entity.id = this._entityIdSeed++;
|
|
||||||
entity.world = this;
|
|
||||||
entity.index = index;
|
|
||||||
entity.dead = false;
|
|
||||||
for(let system of this._systems) {
|
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 {
|
public removeEntity(entityIndex: EntityIndex): boolean {
|
||||||
if(entity <= 0) return false;
|
if(entityIndex <= 0) return false;
|
||||||
if(!this._entities[entity] || this._entities[entity].dead) {
|
if(!this._entityToComponents[entityIndex]) {
|
||||||
console.warn(`[ECSWorld] removeEntity entity is removed`);
|
console.warn(`[ECSWorld] removeEntity entity is removed`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this._entities[entity].dead = true;
|
|
||||||
this._entitiesToDelete.push(entity);
|
|
||||||
|
|
||||||
this._fillters.forEach((fillter, key) => {
|
this._fillters.forEach((fillter, key) => {
|
||||||
fillter.isContains(entity) && fillter.onEntityLeave(entity);
|
fillter.isContains(entityIndex) && fillter.onEntityLeave(entityIndex);
|
||||||
});
|
});
|
||||||
for(let system of this._systems) {
|
for(let system of this._systems) {
|
||||||
system.onEntityLeave(this, entity);
|
system.onEntityLeave(this, entityIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._entitiesToDelete.add(entityIndex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getComponent<T>(entity: EntityIndex, com: {prototype: T}) {
|
public getComponentPoolIdx<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType) {
|
||||||
if(!this._entities[entity]) return null;
|
let entity = this._entityToComponents[entityIndex];
|
||||||
let comPoolIdx = this._entities[entity].getComponent(com);
|
if(!entity) return -1;
|
||||||
|
let type = typeof com == 'number' ? com : GetComConstructorType(com);
|
||||||
|
return entity[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getComponent<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType) {
|
||||||
|
let comPoolIdx = this.getComponentPoolIdx(entityIndex, com);
|
||||||
|
if(comPoolIdx == -1) return null;
|
||||||
return this.getComponentPool<T>(com).get(comPoolIdx);
|
return this.getComponentPool<T>(com).get(comPoolIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeComponent(entity: EntityIndex, com: ECSComConstructor) {
|
public addComponent<T>(entityIndex: EntityIndex, com: {prototype: T}, dirty = true) {
|
||||||
if(!this._entities[entity]) return ;
|
let entity = this._entityToComponents[entityIndex];
|
||||||
this._entities[entity].removeComponent(com);
|
if(!entity) return null;
|
||||||
}
|
let type = GetComConstructorType(com);
|
||||||
|
let comPoolIdx = entity[type];
|
||||||
public addComponent<T>(entity: EntityIndex, com: {prototype: T}) {
|
if(comPoolIdx == -1) {
|
||||||
if(!this._entities[entity]) return null;
|
comPoolIdx = this.getComponentPool<T>(com).alloc();
|
||||||
let comPoolIdx = this._entities[entity].addComponent(com);
|
}
|
||||||
|
entity[type] = comPoolIdx;
|
||||||
|
dirty && this.setEntityDirty(entityIndex);
|
||||||
return this.getComponentPool<T>(com).get(comPoolIdx)
|
return this.getComponentPool<T>(com).get(comPoolIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSingletonComponent<T>(com: {prototype: T}): T {
|
public removeComponent(entityIndex: EntityIndex, com: ECSComConstructor, dirty = true) {
|
||||||
let entity = this._entities[0];
|
let entity = this._entityToComponents[entityIndex];
|
||||||
let comPoolIdx = entity.getComponent(<ECSComConstructor>com);
|
if(!entity) return true;
|
||||||
let pool = this.getComponentPool<T>(com);
|
let type = GetComConstructorType(com);
|
||||||
if(comPoolIdx >= 0) return pool.get(comPoolIdx);
|
let comPoolIdx = entity[type];
|
||||||
return pool.get(entity.addComponent(com));
|
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<entity.length; i++) {
|
||||||
|
if(entity[i] == -1) continue;
|
||||||
|
this.getComponentPool(i).free(entity[i]);
|
||||||
|
}
|
||||||
|
entity.fill(-1);
|
||||||
|
dirty && this.setEntityDirty(entityIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getSingletonComponent<T>(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) => {
|
this._fillters.forEach((fillter, key) => {
|
||||||
let accept = !entity.dead && fillter.isAccept(entity);
|
let accept = !this._entitiesToDelete.has(entityIndex) && fillter.isAccept(entityIndex);
|
||||||
if(accept != fillter.isContains(entity.index)) {
|
if(accept != fillter.isContains(entityIndex)) {
|
||||||
accept ? fillter.onEntityEnter(entity.index) : fillter.onEntityLeave(entity.index);
|
accept ? fillter.onEntityEnter(entityIndex) : fillter.onEntityLeave(entityIndex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEntityId(entity: EntityIndex) : number {
|
|
||||||
return this._entities[entity].id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFilter(fillterKey: string): ECSFillter {
|
public getFilter(fillterKey: string): ECSFillter {
|
||||||
if(this._fillters.has(fillterKey)) {
|
if(this._fillters.has(fillterKey)) {
|
||||||
return this._fillters.get(fillterKey);
|
return this._fillters.get(fillterKey);
|
||||||
@ -143,10 +158,9 @@ export class ECSWorld {
|
|||||||
let fillter = new ECSFillter(this, accept, reject);
|
let fillter = new ECSFillter(this, accept, reject);
|
||||||
this._fillters.set(fillterKey, fillter);
|
this._fillters.set(fillterKey, fillter);
|
||||||
// 将当期的entity放入fillter
|
// 将当期的entity放入fillter
|
||||||
for(let i=1; i<this._entities.length; i++) {
|
for(let i=1; i<this._entityToComponents.length; i++) {
|
||||||
const entity = this._entities[i];
|
if(fillter.isAccept(i)) {
|
||||||
if(fillter.isAccept(entity)) {
|
fillter.onEntityEnter(i);
|
||||||
fillter.onEntityEnter(entity.index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fillter;
|
return fillter;
|
||||||
@ -156,18 +170,17 @@ export class ECSWorld {
|
|||||||
for(let system of this._systems) {
|
for(let system of this._systems) {
|
||||||
system.onUpdate(this, dt);
|
system.onUpdate(this, dt);
|
||||||
}
|
}
|
||||||
if(this._entitiesToDelete.length > 0) {
|
if(this._entitiesToDelete.size > 0) {
|
||||||
this._realRemoveEntity();
|
this._realRemoveEntity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _realRemoveEntity() {
|
private _realRemoveEntity() {
|
||||||
for(let entityIdx of this._entitiesToDelete) {
|
this._entitiesToDelete.forEach((value) => {
|
||||||
this._entities[entityIdx].removeAllComponents(false);
|
this.removeAllComponents(value);
|
||||||
this._entities[entityIdx].id = -1;
|
this._reservedIds.push(value);
|
||||||
this._reservedIds.push(entityIdx);
|
});
|
||||||
}
|
this._entitiesToDelete.clear();
|
||||||
this._entitiesToDelete.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user