mirror of
https://github.com/Keyslam-Group/Concord.git
synced 2025-09-02 12:24:11 -04:00
Streamline entity lifetime
This commit is contained in:
parent
bc47eaa651
commit
038111d558
7 changed files with 117 additions and 163 deletions
37
main.lua
37
main.lua
|
@ -22,20 +22,49 @@ local test_comp_3 = Concord.component("test_comp_3", function(e, b)
|
|||
end)
|
||||
|
||||
local test_system = Concord.system({Component.test_comp_1})
|
||||
function test_system:update(dt)
|
||||
print(#self.pool)
|
||||
|
||||
function onEntityAdded(e)
|
||||
print("Added")
|
||||
end
|
||||
|
||||
function onEntityRemoved(e)
|
||||
print("Removed")
|
||||
end
|
||||
|
||||
function test_system:init()
|
||||
self.pool.onEntityAdded = onEntityAdded
|
||||
self.pool.onEntityRemoved = onEntityRemoved
|
||||
end
|
||||
|
||||
function test_system:update(dt)
|
||||
--print(#self.pool)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local world = Concord.world()
|
||||
|
||||
local entity = Concord.entity()
|
||||
entity:give(Component.test_comp_2, 100, 100)
|
||||
entity:apply()
|
||||
entity:give(Component.test_comp_1, 100, 100)
|
||||
|
||||
world:addEntity(entity)
|
||||
|
||||
world:addSystem(test_system(), "update")
|
||||
|
||||
function love.update(dt)
|
||||
world:flush()
|
||||
|
||||
world:emit("update", dt)
|
||||
end
|
||||
|
||||
function love.keypressed(key)
|
||||
if key == "q" then
|
||||
entity:remove(Component.test_comp_1)
|
||||
end
|
||||
if key == "w" then
|
||||
entity:give(Component.test_comp_1)
|
||||
end
|
||||
if key == "e" then
|
||||
world:removeEntity(entity)
|
||||
end
|
||||
end
|
|
@ -51,4 +51,4 @@ return setmetatable(Component, {
|
|||
__call = function(_, ...)
|
||||
return Component.new(...)
|
||||
end,
|
||||
})
|
||||
})
|
|
@ -3,7 +3,6 @@
|
|||
local PATH = (...):gsub('%.[^%.]+$', '')
|
||||
|
||||
local Type = require(PATH..".type")
|
||||
local List = require(PATH..".list")
|
||||
|
||||
local Entity = {}
|
||||
Entity.__index = Entity
|
||||
|
@ -12,8 +11,11 @@ Entity.__index = Entity
|
|||
-- @return A new Entity
|
||||
function Entity.new()
|
||||
local e = setmetatable({
|
||||
removed = {},
|
||||
worlds = List(),
|
||||
world = nil,
|
||||
|
||||
__isDirty = true,
|
||||
__wasAdded = false,
|
||||
__wasRemoved = false,
|
||||
|
||||
__isEntity = true,
|
||||
}, Entity)
|
||||
|
@ -25,7 +27,13 @@ local function give(e, component, ...)
|
|||
local comp = component:__initialize(...)
|
||||
e[component] = comp
|
||||
|
||||
e:mark()
|
||||
e.__isDirty = true
|
||||
end
|
||||
|
||||
local function remove(e, component)
|
||||
e[component] = nil
|
||||
|
||||
e.__isDirty = true
|
||||
end
|
||||
|
||||
--- Gives an Entity a component with values.
|
||||
|
@ -37,10 +45,6 @@ function Entity:give(component, ...)
|
|||
error("bad argument #1 to 'Entity:give' (Component expected, got "..type(component)..")", 2)
|
||||
end
|
||||
|
||||
if self[component] then
|
||||
self:remove(component):apply()
|
||||
end
|
||||
|
||||
give(self, component, ...)
|
||||
|
||||
return self
|
||||
|
@ -68,9 +72,7 @@ function Entity:remove(component)
|
|||
error("bad argument #1 to 'Entity:remove' (Component expected, got "..type(component)..")")
|
||||
end
|
||||
|
||||
self.removed[#self.removed + 1] = component
|
||||
|
||||
self:mark()
|
||||
remove(self, component)
|
||||
|
||||
return self
|
||||
end
|
||||
|
@ -85,28 +87,11 @@ function Entity:assemble(assemblage, ...)
|
|||
return self
|
||||
end
|
||||
|
||||
function Entity:mark()
|
||||
for i = 1, self.worlds.size do
|
||||
self.worlds:get(i):markEntity(self)
|
||||
end
|
||||
end
|
||||
|
||||
function Entity:apply()
|
||||
for i = 1, #self.removed do
|
||||
local component = self.removed[i]
|
||||
|
||||
self[component] = nil
|
||||
self.removed[i] = nil
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Destroys the Entity.
|
||||
-- @return self
|
||||
function Entity:destroy()
|
||||
for i = 1, self.worlds.size do
|
||||
self.worlds:get(i):removeEntity(self)
|
||||
if self.world then
|
||||
self.world:removeEntity(self)
|
||||
end
|
||||
|
||||
return self
|
||||
|
|
|
@ -73,7 +73,7 @@ end
|
|||
-- @param obj The object to search for
|
||||
-- true if the list has the object, false otherwise
|
||||
function List:has(obj)
|
||||
return self[obj] and true
|
||||
return self[obj] and true or false
|
||||
end
|
||||
|
||||
return setmetatable(List, {
|
||||
|
|
27
src/pool.lua
27
src/pool.lua
|
@ -14,9 +14,6 @@ Pool.__index = Pool
|
|||
function Pool.new(name, filter)
|
||||
local pool = setmetatable(List(), Pool)
|
||||
|
||||
pool.added = {}
|
||||
pool.removed = {}
|
||||
|
||||
pool.name = name
|
||||
pool.filter = filter
|
||||
|
||||
|
@ -25,18 +22,12 @@ function Pool.new(name, filter)
|
|||
return pool
|
||||
end
|
||||
|
||||
function Pool:flush()
|
||||
for i = 1, math.max(#self.added, #self.removed) do
|
||||
self.added[i], self.removed[i] = nil, nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks if an Entity is eligible for the Pool.
|
||||
-- @param e The Entity to check
|
||||
-- @return True if the entity is eligible, false otherwise
|
||||
function Pool:eligible(e)
|
||||
for _, component in ipairs(self.filter) do
|
||||
if not e[component] or e.removed[component] then
|
||||
if not e[component] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
@ -44,6 +35,22 @@ function Pool:eligible(e)
|
|||
return true
|
||||
end
|
||||
|
||||
function Pool:add(e)
|
||||
List.add(self, e)
|
||||
self:onEntityAdded(e)
|
||||
end
|
||||
|
||||
function Pool:remove(e)
|
||||
List.remove(self, e)
|
||||
self:onEntityRemoved(e)
|
||||
end
|
||||
|
||||
function Pool:onEntityAdded(e)
|
||||
end
|
||||
|
||||
function Pool:onEntityRemoved(e)
|
||||
end
|
||||
|
||||
return setmetatable(Pool, {
|
||||
__index = List,
|
||||
__call = function(_, ...)
|
||||
|
|
|
@ -9,7 +9,6 @@ System.mt = {
|
|||
__index = System,
|
||||
__call = function(systemProto, ...)
|
||||
local system = setmetatable({
|
||||
__all = {},
|
||||
__pools = {},
|
||||
__world = nil,
|
||||
|
||||
|
@ -63,22 +62,15 @@ end
|
|||
|
||||
--- Checks and applies an Entity to the System's pools.
|
||||
-- @param e The Entity to check
|
||||
-- @return True if the Entity was added, false if it was removed. Nil if nothing happend
|
||||
function System:__check(e)
|
||||
function System:__evaluate(e)
|
||||
for _, pool in ipairs(self.__pools) do
|
||||
local poolHas = pool:has(e)
|
||||
local has = pool:has(e)
|
||||
local eligible = pool:eligible(e)
|
||||
|
||||
if not poolHas and eligible then
|
||||
if not has and eligible then
|
||||
pool:add(e)
|
||||
pool.added[#pool.added + 1] = e
|
||||
|
||||
self:__tryAdd(e)
|
||||
elseif poolHas and not eligible then
|
||||
elseif has and not eligible then
|
||||
pool:remove(e)
|
||||
pool.removed[#pool.removed + 1] = e
|
||||
|
||||
self:__tryRemove(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -86,46 +78,16 @@ end
|
|||
--- Remove an Entity from the System.
|
||||
-- @param e The Entity to remove
|
||||
function System:__remove(e)
|
||||
if self.__all[e] then
|
||||
for _, pool in ipairs(self.__pools) do
|
||||
if pool:has(e) then
|
||||
pool:remove(e)
|
||||
pool.removed[#pool.removed + 1] = e
|
||||
end
|
||||
end
|
||||
|
||||
self.__all[e] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Tries to add an Entity to the System.
|
||||
-- @param e The Entity to add
|
||||
function System:__tryAdd(e)
|
||||
if not self.__all[e] then
|
||||
self.__all[e] = 0
|
||||
end
|
||||
|
||||
self.__all[e] = self.__all[e] + 1
|
||||
end
|
||||
|
||||
--- Tries to remove an Entity from the System.
|
||||
-- @param e The Entity to remove
|
||||
function System:__tryRemove(e)
|
||||
if self.__all[e] then
|
||||
self.__all[e] = self.__all[e] - 1
|
||||
|
||||
if self.__all[e] == 0 then
|
||||
self.__all[e] = nil
|
||||
for _, pool in ipairs(self.__pools) do
|
||||
if pool:has(e) then
|
||||
pool:remove(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function System:flush() -- luacheck: ignore
|
||||
end
|
||||
|
||||
function System:clear()
|
||||
for i = 1, #self.__pools do
|
||||
self.__pools[i]:flush()
|
||||
self.__pools[i]:clear()
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -142,7 +104,7 @@ end
|
|||
|
||||
-- Default callback for when the System is added to an World.
|
||||
-- @param world The World the System was added to
|
||||
function System:addedTo(World) -- luacheck: ignore
|
||||
function System:addedTo(world) -- luacheck: ignore
|
||||
end
|
||||
|
||||
-- Default callback for when a System's callback is enabled.
|
||||
|
|
111
src/world.lua
111
src/world.lua
|
@ -16,8 +16,8 @@ function World.new()
|
|||
systems = List(),
|
||||
events = {},
|
||||
|
||||
marked = {},
|
||||
removed = {},
|
||||
__added = {},
|
||||
__removed = {},
|
||||
|
||||
__isWorld = true,
|
||||
}, World)
|
||||
|
@ -33,16 +33,19 @@ function World:addEntity(e)
|
|||
error("bad argument #1 to 'World:addEntity' (Entity expected, got "..type(e)..")", 2)
|
||||
end
|
||||
|
||||
self:onEntityAdded(e)
|
||||
if e.world then
|
||||
error("bad argument #1 to 'World:addEntity' (Entity was already added to a world)", 2)
|
||||
end
|
||||
|
||||
e.world = self
|
||||
e.__wasAdded = true
|
||||
|
||||
e.worlds:add(self)
|
||||
self.entities:add(e)
|
||||
self:checkEntity(e)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Marks an Entity as removed from the World.
|
||||
--- Removes an entity from the World.
|
||||
-- @param e The Entity to mark
|
||||
-- @return self
|
||||
function World:removeEntity(e)
|
||||
|
@ -50,73 +53,46 @@ function World:removeEntity(e)
|
|||
error("bad argument #1 to 'World:removeEntity' (Entity expected, got "..type(e)..")", 2)
|
||||
end
|
||||
|
||||
self.removed[#self.removed + 1] = e
|
||||
e.__wasRemoved = true
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function World:markEntity(e)
|
||||
if not Type.isEntity(e) then
|
||||
error("bad argument #1 to 'World:markEntity' (Entity expected, got "..type(e)..")", 2)
|
||||
end
|
||||
|
||||
self.marked[#self.marked + 1] = e
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Checks an Entity against all the systems in the World.
|
||||
-- @param e The Entity to check
|
||||
-- @return self
|
||||
function World:checkEntity(e)
|
||||
if not Type.isEntity(e) then
|
||||
error("bad argument #1 to 'World:checkEntity' (Entity expected, got "..type(e)..")", 2)
|
||||
end
|
||||
|
||||
for i = 1, self.systems.size do
|
||||
self.systems:get(i):__check(e)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Completely removes all marked Entities in the World.
|
||||
-- @return self
|
||||
function World:flush()
|
||||
while #self.marked > 0 do
|
||||
local marked = self.removed
|
||||
self.removed = {}
|
||||
local e
|
||||
for i = 1, self.entities.size do
|
||||
e = self.entities:get(i)
|
||||
|
||||
for i = 1, #marked do
|
||||
local e = marked[i]
|
||||
if e.__wasAdded then
|
||||
e.__wasAdded = false
|
||||
e.__isDirty = false
|
||||
|
||||
e.Worlds:apply()
|
||||
e.Worlds:checkEntity(e)
|
||||
end
|
||||
end
|
||||
|
||||
while #self.removed > 0 do
|
||||
local removed = self.removed
|
||||
self.removed = {}
|
||||
|
||||
for i = 1, #removed do
|
||||
local e = removed[i]
|
||||
|
||||
e.worlds:remove(self)
|
||||
self.entities:remove(e)
|
||||
|
||||
for j = 1, self.systems.size do
|
||||
self.systems:get(j):__remove(e)
|
||||
for i = 1, self.systems.size do
|
||||
self.systems:get(i):__evaluate(e)
|
||||
end
|
||||
|
||||
self:onEntityRemoved(e)
|
||||
self:onEntityAdded(e)
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, self.systems.size do
|
||||
local system = self.systems:get(i)
|
||||
system:flush()
|
||||
system:clear()
|
||||
if e.__wasRemoved then
|
||||
e.world = nil
|
||||
self.entities:remove(e)
|
||||
|
||||
for i = 1, self.systems.size do
|
||||
self.systems:get(i):__remove(e)
|
||||
end
|
||||
|
||||
e.__wasRemoved = false
|
||||
end
|
||||
|
||||
if e.__isDirty then
|
||||
for i = 1, self.systems.size do
|
||||
self.systems:get(i):__evaluate(e)
|
||||
end
|
||||
|
||||
e.__isDirty = false
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
|
@ -142,6 +118,10 @@ function World:addSystem(system, eventName, callback, enabled)
|
|||
system.__World = self
|
||||
|
||||
system:addedTo(self)
|
||||
|
||||
for i = 1, self.entities.size do
|
||||
system:__evaluate(self.entities:get(i))
|
||||
end
|
||||
end
|
||||
|
||||
if eventName then
|
||||
|
@ -159,13 +139,6 @@ function World:addSystem(system, eventName, callback, enabled)
|
|||
end
|
||||
end
|
||||
|
||||
local e
|
||||
for i = 1, self.entities.size do
|
||||
e = self.entities:get(i)
|
||||
|
||||
self:checkEntity(e)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -242,8 +215,6 @@ function World:emit(eventName, ...)
|
|||
error("bad argument #1 to 'World:emit' (String expected, got "..type(eventName)..")")
|
||||
end
|
||||
|
||||
self:flush()
|
||||
|
||||
local listeners = self.events[eventName]
|
||||
|
||||
if listeners then
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue