| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- --[[
- ECS World class
- @author : Eiyeron Fulmincendii
- Contains entities, components and system and orchestrates them.
- ]]--
- local class = require("class")
- local object = require("object")
- local SystemFilter = require("SystemFilter")
- local Entity = require("Entity")
- local utils = require("utils")
- ECSWorld = class(object)
- function ECSWorld:init( )
- self.entities = {}
- self.components = {}
- self.system_filters = {}
- end
- --[[
- Search a filter that matches the required components.
- ]]--
- function ECSWorld:searchFilter(required_components)
- -- TODO : inquire why it doesn't call a composant's metamethod.
- local component_list = table.sort(required_components)
- for i,l in ipairs(self.system_filters) do
- if l:compareComponentList(required_components) then
- return l
- end
- end
- return nil
- end
- --[[
- - system : system to register
- - ... : array of components to require
- ]]--
- function ECSWorld:registerSystem(system_type, ...)
- local required_components = {...}
- local found_filter = self:searchFilter(required_components)
- if found_filter then
- found_filter:registerSystem(system_type)
- else
- local new_filter = SystemFilter:new(required_components)
- self.system_filters[#self.system_filters + 1] = new_filter
- self:searchAndRegisterEntitiesInNewSystemFilter(new_filter)
- new_filter:registerSystem(system_type)
- end
- end
- --[[
- On component attachment, register the holder entity to
- every filter that can handle it now.
- ]]
- function ECSWorld:searchAndRegisterEntityInSystemFilter(entity)
- for i,system_filter in ipairs(self.system_filters) do
- if system_filter:checkEntityCompatibility(entity) and not system_filter:hasEntity(entity) then
- system_filter:registerEntry(entity)
- end
- end
- end
- --[[
- On SystemFilter creation, register every compatible entity.
- ]]
- function ECSWorld:searchAndRegisterEntitiesInNewSystemFilter(new_filter)
- for i,entity in ipairs(self.entities) do
- if new_filter:checkEntityCompatibility(entity) and not new_filter:hasEntity(entity) then
- new_filter:registerEntry(entity)
- end
- end
- end
- --[[
- On Component detachment, prune the filters from the now-incompatible holder entity.
- ]]--
- function ECSWorld:searchAndPruneEntityFromSystemFilter(entity)
- for i,system_filter in ipairs(self.system_filters) do
- if system_filter:hasEntity(entity) and not system_filter:checkEntityCompatibility(entity) then
- system_filter:unregisterEntry(entity)
- end
- end
- end
- --[[
- - Copies the entity into the ECSWorld's entities
- - Registers it in every SystemFilter already registered
- ]]
- function ECSWorld:createEntity()
- local index = #self.entities + 1
- for i,entity_entry in ipairs(self.entities) do
- if entity_entry.__destroyed then
- index = i
- break
- end
- end
- local e = Entity:new(index, self)
- self.entities[index] = e
- return e
- end
- --[[
- Called by World itself to mark an entity as destroyed (to override it later if needed)
- ]]--
- function ECSWorld:deleteEntity(entity)
- self:searchAndUnregisterEntitiesInSystemFilter(entity)
- entity.__destroyed = true
- end
- --[[
- Called by Systems via their Entity. Creates and attach a component to the holder
- entity.
- ]]--
- function ECSWorld:attachComponentToEntity(entity, component_type, ...)
- -- Create on the fly the component list if the world doesn't have it for this component class.
- if not self.components[component_type] then self.components[component_type] = {} end
- self.components[component_type][entity.__eid] = component_type:new(...)
- self:searchAndRegisterEntityInSystemFilter(entity)
- end
- --[[
- Called by Systems via their Entity. Deletes and detaches the component from this entity.
- ]]--
- function ECSWorld:detachComponentFromEntity(entity, component_type)
- -- TODO : better way to remove component
- self.components[component_type][entity.__eid] = nil
- self:searchAndPruneEntityFromSystemFilter(entity)
- end
- --[[
- Called by Systems via their Entity.
- ]]
- function ECSWorld:entityGetComponent(entity, component_type)
- if not self.components[component_type] then return nil end
- return self.components[component_type][entity.__eid]
- end
- --[[
- Called by Systems via their Entity.
- ]]
- function ECSWorld:entityHasComponent(entity, component_type)
- return self:entityGetComponent(entity, component_type) ~= nil
- end
- --[[
- Supposed to be called by the world owner. Calls every system and prunes marked for deletion entities
- ]]
- function ECSWorld:update(dt)
- for i,system_filter in ipairs(self.system_filters) do
- system_filter:update(dt, self.entities)
- end
- -- Entity release. Done post-update.
- for i,entity in ipairs(self.entities) do
- if entity.__destroy_required == true then
- self:deleteEntity(entity)
- end
- end
- end
- return ECSWorld
|