ECSWorld.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. --[[
  2. ECS World class
  3. @author : Eiyeron Fulmincendii
  4. Contains entities, components and system and orchestrates them.
  5. ]]--
  6. local class = require("class")
  7. local object = require("object")
  8. local SystemFilter = require("SystemFilter")
  9. local Entity = require("Entity")
  10. local utils = require("utils")
  11. ECSWorld = class(object)
  12. function ECSWorld:init( )
  13. self.entities = {}
  14. self.components = {}
  15. self.system_filters = {}
  16. end
  17. --[[
  18. Search a filter that matches the required components.
  19. ]]--
  20. function ECSWorld:searchFilter(required_components)
  21. -- TODO : inquire why it doesn't call a composant's metamethod.
  22. local component_list = table.sort(required_components)
  23. for i,l in ipairs(self.system_filters) do
  24. if l:compareComponentList(required_components) then
  25. return l
  26. end
  27. end
  28. return nil
  29. end
  30. --[[
  31. - system : system to register
  32. - ... : array of components to require
  33. ]]--
  34. function ECSWorld:registerSystem(system_type, ...)
  35. local required_components = {...}
  36. local found_filter = self:searchFilter(required_components)
  37. if found_filter then
  38. found_filter:registerSystem(system_type)
  39. else
  40. local new_filter = SystemFilter:new(required_components)
  41. self.system_filters[#self.system_filters + 1] = new_filter
  42. self:searchAndRegisterEntitiesInNewSystemFilter(new_filter)
  43. new_filter:registerSystem(system_type)
  44. end
  45. end
  46. --[[
  47. On component attachment, register the holder entity to
  48. every filter that can handle it now.
  49. ]]
  50. function ECSWorld:searchAndRegisterEntityInSystemFilter(entity)
  51. for i,system_filter in ipairs(self.system_filters) do
  52. if system_filter:checkEntityCompatibility(entity) and not system_filter:hasEntity(entity) then
  53. system_filter:registerEntry(entity)
  54. end
  55. end
  56. end
  57. --[[
  58. On SystemFilter creation, register every compatible entity.
  59. ]]
  60. function ECSWorld:searchAndRegisterEntitiesInNewSystemFilter(new_filter)
  61. for i,entity in ipairs(self.entities) do
  62. if new_filter:checkEntityCompatibility(entity) and not new_filter:hasEntity(entity) then
  63. new_filter:registerEntry(entity)
  64. end
  65. end
  66. end
  67. --[[
  68. On Component detachment, prune the filters from the now-incompatible holder entity.
  69. ]]--
  70. function ECSWorld:searchAndPruneEntityFromSystemFilter(entity)
  71. for i,system_filter in ipairs(self.system_filters) do
  72. if system_filter:hasEntity(entity) and not system_filter:checkEntityCompatibility(entity) then
  73. system_filter:unregisterEntry(entity)
  74. end
  75. end
  76. end
  77. --[[
  78. - Copies the entity into the ECSWorld's entities
  79. - Registers it in every SystemFilter already registered
  80. ]]
  81. function ECSWorld:createEntity()
  82. local index = #self.entities + 1
  83. for i,entity_entry in ipairs(self.entities) do
  84. if entity_entry.__destroyed then
  85. index = i
  86. break
  87. end
  88. end
  89. local e = Entity:new(index, self)
  90. self.entities[index] = e
  91. return e
  92. end
  93. --[[
  94. Called by World itself to mark an entity as destroyed (to override it later if needed)
  95. ]]--
  96. function ECSWorld:deleteEntity(entity)
  97. self:searchAndUnregisterEntitiesInSystemFilter(entity)
  98. entity.__destroyed = true
  99. end
  100. --[[
  101. Called by Systems via their Entity. Creates and attach a component to the holder
  102. entity.
  103. ]]--
  104. function ECSWorld:attachComponentToEntity(entity, component_type, ...)
  105. -- Create on the fly the component list if the world doesn't have it for this component class.
  106. if not self.components[component_type] then self.components[component_type] = {} end
  107. self.components[component_type][entity.__eid] = component_type:new(...)
  108. self:searchAndRegisterEntityInSystemFilter(entity)
  109. end
  110. --[[
  111. Called by Systems via their Entity. Deletes and detaches the component from this entity.
  112. ]]--
  113. function ECSWorld:detachComponentFromEntity(entity, component_type)
  114. -- TODO : better way to remove component
  115. self.components[component_type][entity.__eid] = nil
  116. self:searchAndPruneEntityFromSystemFilter(entity)
  117. end
  118. --[[
  119. Called by Systems via their Entity.
  120. ]]
  121. function ECSWorld:entityGetComponent(entity, component_type)
  122. if not self.components[component_type] then return nil end
  123. return self.components[component_type][entity.__eid]
  124. end
  125. --[[
  126. Called by Systems via their Entity.
  127. ]]
  128. function ECSWorld:entityHasComponent(entity, component_type)
  129. return self:entityGetComponent(entity, component_type) ~= nil
  130. end
  131. --[[
  132. Supposed to be called by the world owner. Calls every system and prunes marked for deletion entities
  133. ]]
  134. function ECSWorld:update(dt)
  135. for i,system_filter in ipairs(self.system_filters) do
  136. system_filter:update(dt, self.entities)
  137. end
  138. -- Entity release. Done post-update.
  139. for i,entity in ipairs(self.entities) do
  140. if entity.__destroy_required == true then
  141. self:deleteEntity(entity)
  142. end
  143. end
  144. end
  145. return ECSWorld