123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /** @format */
- import {ECSFilter} from './ECSFilter'
- import {ECSComConstructor, GetComConstructor as GetComConstructor, GetComConstructorType} from './ECSComponent'
- import {ECSSystem} from './ECSSystem'
- import {ComPoolIndex, ComType, EntityIndex} from './Const'
- import {ECSComponentPool} from './ECSComponentPool'
- export class ECSWorld {
- private _systems: ECSSystem[] = [] // world内所有的system
- private _entityToComponents: number[][] = [] // entity component 二维表
- private _entitiesToDelete: Set<EntityIndex> = new Set() // 统一删除entity
- private _componentPools: ECSComponentPool<any>[] = [] // component pools
- private _filters = new Map<string, ECSFilter>() // filter
- public curFrame: number = 0
- /** 获取ComponentPool */
- public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
- let type = typeof typeOrFunc == 'number' ? typeOrFunc : GetComConstructorType(typeOrFunc)
- if (!this._componentPools[type]) {
- this._componentPools[type] = new ECSComponentPool<T>(GetComConstructor(type))
- }
- return this._componentPools[type] as any
- }
- /** 添加system */
- public addSystem(system: ECSSystem) {
- this._systems.push(system)
- system.onAdd(this)
- for (let i = 0; i < this._entityToComponents.length; i++) {
- system.onEntityEnter(this, i)
- }
- }
- public getSystem<T extends ECSSystem>(args: new () => T): T | undefined {
- return this._systems.find(system => system.constructor == args) as T | undefined
- }
- /** 移除system */
- public removeSystem(system: ECSSystem) {
- system.onRemove(this)
- 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) {
- this._systems.splice(i, 1)
- }
- }
- }
- /** 创建实体 */
- public createEntity(): number {
- let index = this._entityToComponents.length
- this._entityToComponents[index] = new Array<ComPoolIndex>(Object.keys(ComType).length / 2).fill(-1)
- for (let system of this._systems) {
- system.onEntityEnter(this, index)
- }
- return index
- }
- /** 移除实体 */
- public removeEntity(entityIndex: EntityIndex): boolean {
- if (entityIndex <= 0) return false
- if (!this._entityToComponents[entityIndex]) {
- console.warn(`[ECSWorld] removeEntity entity is removed`)
- return false
- }
- this._filters.forEach((fillter, key) => {
- fillter.isContains(entityIndex) && fillter.onEntityLeave(entityIndex)
- })
- for (let system of this._systems) {
- system.onEntityLeave(this, entityIndex)
- }
- this._entitiesToDelete.add(entityIndex)
- return true
- }
- public getComponentPoolIdx<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType): ComPoolIndex {
- let entity = this._entityToComponents[entityIndex]
- 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)
- }
- public addComponent<T>(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<T>(com).alloc()
- }
- entity[type] = comPoolIdx
- dirty && this.setEntityDirty(entityIndex)
- return this.getComponentPool<T>(com).get(comPoolIdx)
- }
- 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 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[i] = -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._filters.forEach((fillter, key) => {
- let accept = !this._entitiesToDelete.has(entityIndex) && fillter.isAccept(entityIndex)
- if (accept != fillter.isContains(entityIndex)) {
- accept ? fillter.onEntityEnter(entityIndex) : fillter.onEntityLeave(entityIndex)
- }
- })
- }
- public getFilter(filterKey: string): ECSFilter {
- if (this._filters.has(filterKey)) {
- return this._filters.get(filterKey)
- }
- let [acceptStr, rejectStr] = filterKey.split('-')
- let accept = acceptStr && acceptStr.length > 0 ? acceptStr.split(',').map(Number) : null
- let reject = rejectStr && rejectStr.length > 0 ? rejectStr.split(',').map(Number) : null
- let filter = new ECSFilter(this, accept, reject)
- this._filters.set(filterKey, filter)
- // 将当期的entity放入filter
- for (let i = 1; i < this._entityToComponents.length; i++) {
- if (filter.isAccept(i)) {
- filter.onEntityEnter(i)
- }
- }
- return filter
- }
- public update(dt: number) {
- for (let system of this._systems) {
- system.onUpdate(this, dt)
- }
- if (this._entitiesToDelete.size > 0) {
- this._realRemoveEntity()
- }
- this.curFrame += 1
- }
- public clear(isRemoveSystem: boolean = true) {
- if (isRemoveSystem) this._systems = []
- for (let i = 0; i < this._entityToComponents.length; i++) {
- this.putNode(i)
- this.removeEntity(i)
- }
- //不能清楚0号实体
- this._entityToComponents.length = 1
- if (this._entitiesToDelete.size > 0) {
- this._realRemoveEntity()
- }
- this.curFrame = 0
- }
- private _realRemoveEntity() {
- this._entitiesToDelete.forEach(value => {
- this.removeAllComponents(value)
- })
- this._entitiesToDelete.clear()
- }
- public putNode(entityIndex: EntityIndex) {}
- }
|