ECSWorld.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /** @format */
  2. import {ECSFilter} from './ECSFilter'
  3. import {ECSComConstructor, GetComConstructor as GetComConstructor, GetComConstructorType} from './ECSComponent'
  4. import {ECSSystem} from './ECSSystem'
  5. import {ComPoolIndex, ComType, EntityIndex} from './Const'
  6. import {ECSComponentPool} from './ECSComponentPool'
  7. export class ECSWorld {
  8. private _systems: ECSSystem[] = [] // world内所有的system
  9. private _entityToComponents: number[][] = [] // entity component 二维表
  10. private _entitiesToDelete: Set<EntityIndex> = new Set() // 统一删除entity
  11. private _componentPools: ECSComponentPool<any>[] = [] // component pools
  12. private _filters = new Map<string, ECSFilter>() // filter
  13. public curFrame: number = 0
  14. /** 获取ComponentPool */
  15. public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
  16. let type = typeof typeOrFunc == 'number' ? typeOrFunc : GetComConstructorType(typeOrFunc)
  17. if (!this._componentPools[type]) {
  18. this._componentPools[type] = new ECSComponentPool<T>(GetComConstructor(type))
  19. }
  20. return this._componentPools[type] as any
  21. }
  22. /** 添加system */
  23. public addSystem(system: ECSSystem) {
  24. this._systems.push(system)
  25. system.onAdd(this)
  26. for (let i = 0; i < this._entityToComponents.length; i++) {
  27. system.onEntityEnter(this, i)
  28. }
  29. }
  30. public getSystem<T extends ECSSystem>(args: new () => T): T | undefined {
  31. return this._systems.find(system => system.constructor == args) as T | undefined
  32. }
  33. /** 移除system */
  34. public removeSystem(system: ECSSystem) {
  35. system.onRemove(this)
  36. for (let i = 0; i < this._entityToComponents.length; i++) {
  37. system.onEntityLeave(this, i)
  38. }
  39. for (let i = this._systems.length - 1; i >= 0; i--) {
  40. if (this._systems[i] == system) {
  41. this._systems.splice(i, 1)
  42. }
  43. }
  44. }
  45. /** 创建实体 */
  46. public createEntity(): number {
  47. let index = this._entityToComponents.length
  48. this._entityToComponents[index] = new Array<ComPoolIndex>(Object.keys(ComType).length / 2).fill(-1)
  49. for (let system of this._systems) {
  50. system.onEntityEnter(this, index)
  51. }
  52. return index
  53. }
  54. /** 移除实体 */
  55. public removeEntity(entityIndex: EntityIndex): boolean {
  56. if (entityIndex <= 0) return false
  57. if (!this._entityToComponents[entityIndex]) {
  58. console.warn(`[ECSWorld] removeEntity entity is removed`)
  59. return false
  60. }
  61. this._filters.forEach((fillter, key) => {
  62. fillter.isContains(entityIndex) && fillter.onEntityLeave(entityIndex)
  63. })
  64. for (let system of this._systems) {
  65. system.onEntityLeave(this, entityIndex)
  66. }
  67. this._entitiesToDelete.add(entityIndex)
  68. return true
  69. }
  70. public getComponentPoolIdx<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType): ComPoolIndex {
  71. let entity = this._entityToComponents[entityIndex]
  72. if (!entity) return -1
  73. let type = typeof com == 'number' ? com : GetComConstructorType(com)
  74. return entity[type]
  75. }
  76. public getComponent<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType) {
  77. let comPoolIdx = this.getComponentPoolIdx(entityIndex, com)
  78. if (comPoolIdx == -1) return null
  79. return this.getComponentPool<T>(com).get(comPoolIdx)
  80. }
  81. public addComponent<T>(entityIndex: EntityIndex, com: {prototype: T}, dirty = true) {
  82. let entity = this._entityToComponents[entityIndex]
  83. if (!entity) return null
  84. let type = GetComConstructorType(com)
  85. let comPoolIdx = entity[type]
  86. if (comPoolIdx == -1) {
  87. comPoolIdx = this.getComponentPool<T>(com).alloc()
  88. }
  89. entity[type] = comPoolIdx
  90. dirty && this.setEntityDirty(entityIndex)
  91. return this.getComponentPool<T>(com).get(comPoolIdx)
  92. }
  93. public removeComponent(entityIndex: EntityIndex, com: ECSComConstructor, dirty = true) {
  94. let entity = this._entityToComponents[entityIndex]
  95. if (!entity) return true
  96. let type = GetComConstructorType(com)
  97. let comPoolIdx = entity[type]
  98. if (comPoolIdx == -1) return true
  99. entity[type] = -1
  100. this.getComponentPool(com).free(comPoolIdx)
  101. dirty && this.setEntityDirty(entityIndex)
  102. return true
  103. }
  104. public removeAllComponents(entityIndex: EntityIndex, dirty = true) {
  105. let entity = this._entityToComponents[entityIndex]
  106. if (!entity) return null
  107. for (let i = 0; i < entity.length; i++) {
  108. if (entity[i] == -1) continue
  109. this.getComponentPool(i).free(entity[i])
  110. entity[i] = -1
  111. }
  112. dirty && this.setEntityDirty(entityIndex)
  113. }
  114. public getSingletonComponent<T>(com: {prototype: T}): T {
  115. let component = this.getComponent(0, com)
  116. if (!component) {
  117. component = this.addComponent(0, com)
  118. }
  119. return component
  120. }
  121. public setEntityDirty(entityIndex: EntityIndex): void {
  122. this._filters.forEach((fillter, key) => {
  123. let accept = !this._entitiesToDelete.has(entityIndex) && fillter.isAccept(entityIndex)
  124. if (accept != fillter.isContains(entityIndex)) {
  125. accept ? fillter.onEntityEnter(entityIndex) : fillter.onEntityLeave(entityIndex)
  126. }
  127. })
  128. }
  129. public getFilter(filterKey: string): ECSFilter {
  130. if (this._filters.has(filterKey)) {
  131. return this._filters.get(filterKey)
  132. }
  133. let [acceptStr, rejectStr] = filterKey.split('-')
  134. let accept = acceptStr && acceptStr.length > 0 ? acceptStr.split(',').map(Number) : null
  135. let reject = rejectStr && rejectStr.length > 0 ? rejectStr.split(',').map(Number) : null
  136. let filter = new ECSFilter(this, accept, reject)
  137. this._filters.set(filterKey, filter)
  138. // 将当期的entity放入filter
  139. for (let i = 1; i < this._entityToComponents.length; i++) {
  140. if (filter.isAccept(i)) {
  141. filter.onEntityEnter(i)
  142. }
  143. }
  144. return filter
  145. }
  146. public update(dt: number) {
  147. for (let system of this._systems) {
  148. system.onUpdate(this, dt)
  149. }
  150. if (this._entitiesToDelete.size > 0) {
  151. this._realRemoveEntity()
  152. }
  153. this.curFrame += 1
  154. }
  155. public clear(isRemoveSystem: boolean = true) {
  156. if (isRemoveSystem) this._systems = []
  157. for (let i = 0; i < this._entityToComponents.length; i++) {
  158. this.putNode(i)
  159. this.removeEntity(i)
  160. }
  161. //不能清楚0号实体
  162. this._entityToComponents.length = 1
  163. if (this._entitiesToDelete.size > 0) {
  164. this._realRemoveEntity()
  165. }
  166. this.curFrame = 0
  167. }
  168. private _realRemoveEntity() {
  169. this._entitiesToDelete.forEach(value => {
  170. this.removeAllComponents(value)
  171. })
  172. this._entitiesToDelete.clear()
  173. }
  174. public putNode(entityIndex: EntityIndex) {}
  175. }