ECSWorld.lua 4.8 KB

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