From 11255fd72268036c05b61ba6759ba4f42cebd32b Mon Sep 17 00:00:00 2001 From: Justin van der Leij Date: Tue, 2 Oct 2018 21:52:23 +0200 Subject: [PATCH] Optimized Lists. Added pool.added and .removed. Added entity:ensure --- TODO | 8 ++++++ examples/simpleDrawing/init.lua | 22 ++++++++-------- lib/entity.lua | 28 +++++++++++++++++--- lib/instance.lua | 4 +++ lib/list.lua | 45 ++++++++++++++++++--------------- lib/pool.lua | 9 +++++++ lib/system.lua | 36 ++++++++++++++++---------- 7 files changed, 104 insertions(+), 48 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..4ef844e --- /dev/null +++ b/TODO @@ -0,0 +1,8 @@ +[x] Modify pools and list to be more efficient +[x] Rework Entity:give to remove any previous component and re-add it. +[x] Add Entity:ensure (maybe?) +[ ] Put pools in the Instance and invert dependency. +[ ] Share pools between systems +[ ] Remove System callbacks +[x] Put .added and .removed in pools so they can be iterated over +[ ] Implement assemblages diff --git a/examples/simpleDrawing/init.lua b/examples/simpleDrawing/init.lua index 9879f94..f9a2d9f 100644 --- a/examples/simpleDrawing/init.lua +++ b/examples/simpleDrawing/init.lua @@ -31,10 +31,7 @@ end) local RectangleRenderer = System({Position, Rectangle}) function RectangleRenderer:draw() - local e - for i = 1, self.pool.size do - e = self.pool:get(i) - + for _, e in ipairs(self.pool) do local position = e:get(Position) local rectangle = e:get(Rectangle) local color = e:get(Color) @@ -49,11 +46,16 @@ function RectangleRenderer:draw() end local CircleRenderer = System({Position, Circle}) -function CircleRenderer:draw() - local e - for i = 1, self.pool.size do - e = self.pool:get(i) +function CircleRenderer:flush() + for _, e in ipairs(self.pool.removed) do + print(tostring(e).. " was removed from my pool D:") + end + self:clear() +end + +function CircleRenderer:draw() + for _, e in ipairs(self.pool) do local position = e:get(Position) local circle = e:get(Circle) local color = e:get(Color) @@ -76,7 +78,7 @@ end function RandomRemover:update(dt) self.time = self.time + dt - if self.time >= 0.25 then + if self.time >= 0.5 then self.time = 0 if self.pool.size > 0 then @@ -115,4 +117,4 @@ for i = 1, 100 do end Game:addEntity(e) -end \ No newline at end of file +end diff --git a/lib/entity.lua b/lib/entity.lua index 68fedeb..bfb9a07 100644 --- a/lib/entity.lua +++ b/lib/entity.lua @@ -22,6 +22,12 @@ function Entity.new() return e end +local function give(e, component, ...) + local comp = component:__initialize(...) + e.components[component] = comp + e[component] = comp +end + --- Gives an Entity a component with values. -- @param component The Component to add -- @param ... The values passed to the Component @@ -31,9 +37,25 @@ function Entity:give(component, ...) error("bad argument #1 to 'Entity:give' (Component expected, got "..type(component)..")", 2) end - local comp = component:__initialize(...) - self.components[component] = comp - self[component] = comp + if self[component] then + self:remove(component):apply() + end + + give(self, component, ...) + + return self +end + +function Entity:ensure(component, ...) + if not Type.isComponent(component) then + error("bad argument #1 to 'Entity:ensure' (Component expected, got "..type(component)..")", 2) + end + + if self[component] then + return self + end + + give(self, component, ...) return self end diff --git a/lib/instance.lua b/lib/instance.lua index f2a947e..f4d63a0 100644 --- a/lib/instance.lua +++ b/lib/instance.lua @@ -92,6 +92,10 @@ function Instance:flush() end end + for i = 1, self.systems.size do + self.systems:get(i):flush() + end + return self end diff --git a/lib/list.lua b/lib/list.lua index 33b2c10..a5698c9 100644 --- a/lib/list.lua +++ b/lib/list.lua @@ -7,18 +7,21 @@ local mt = {__index = List} -- @return A new list function List.new() return setmetatable({ - objects = {}, - pointers = {}, - size = 0, + size = 0, }, mt) end --- Clears the List completely. -- @return self function List:clear() - self.objects = {} - self.pointers = {} - self.size = 0 + for i = 1, self.size do + local o = self[i] + + self[o] = nil + self[i] = nil + end + + self.size = 0 return self end @@ -26,12 +29,12 @@ end --- Adds an object to the List. -- @param obj The object to add -- @return self -function List:add(obj) +function List:add(obj) -- obj can not be a number and also not the string "size" local size = self.size + 1 - self.objects[size] = obj - self.pointers[obj] = size - self.size = size + self[size] = obj + self[obj] = size + self.size = size return self end @@ -40,22 +43,22 @@ end -- @param obj The object to remove -- @return self function List:remove(obj) - local index = self.pointers[obj] - if not index then return end + local index = self[obj] + if not index then return end local size = self.size - + if index == size then - self.objects[size] = nil + self[size] = nil else - local other = self.objects[size] + local other = self[size] - self.objects[index] = other - self.pointers[other] = index + self[index] = other + self[other] = index - self.objects[size] = nil + self[size] = nil end - self.pointers[obj] = nil + self[obj] = nil self.size = size - 1 end @@ -63,14 +66,14 @@ end -- @param index The index to look at -- @return The object at the index function List:get(index) - return self.objects[index] + return self[index] end --- Gets if the List has the object. -- @param obj The object to search for -- true if the list has the object, false otherwise function List:has(obj) - return self.pointers[obj] and true + return self[obj] and true end return setmetatable(List, { diff --git a/lib/pool.lua b/lib/pool.lua index c2d1ab4..5a7f44b 100644 --- a/lib/pool.lua +++ b/lib/pool.lua @@ -14,6 +14,9 @@ Pool.__index = Pool function Pool.new(name, filter) local pool = setmetatable(List(), Pool) + pool.added = {} + pool.removed = {} + pool.name = name pool.filter = filter @@ -22,6 +25,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 diff --git a/lib/system.lua b/lib/system.lua index ac769ba..7c7b22a 100644 --- a/lib/system.lua +++ b/lib/system.lua @@ -66,7 +66,7 @@ end -- @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) - local systemHas = self:__has(e) + local systemHas = self.__all[e] for _, pool in ipairs(self.__pools) do local poolHas = pool:has(e) @@ -74,23 +74,28 @@ function System:__check(e) if not poolHas and eligible then pool:add(e) + pool.added[#pool.added + 1] = e + self:entityAddedTo(e, pool) self:__tryAdd(e) elseif poolHas and not eligible then pool:remove(e) + pool.removed[#pool.removed + 1] = e + self:entityRemovedFrom(e, pool) self:__tryRemove(e) end end end ---- Removed an Entity from the System. +--- Remove an Entity from the System. -- @param e The Entity to remove function System:__remove(e) - if self:__has(e) then + 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 self:entityRemovedFrom(e, pool) end end @@ -103,7 +108,7 @@ end --- Tries to add an Entity to the System. -- @param e The Entity to add function System:__tryAdd(e) - if not self:__has(e) then + if not self.__all[e] then self.__all[e] = 0 self:entityAdded(e) end @@ -114,7 +119,7 @@ end --- Tries to remove an Entity from the System. -- @param e The Entity to remove function System:__tryRemove(e) - if self:__has(e) then + if self.__all[e] then self.__all[e] = self.__all[e] - 1 if self.__all[e] == 0 then @@ -124,19 +129,22 @@ function System:__tryRemove(e) end end +function System:flush() + self:clear() +end + +function System:clear() + for i = 1, #self.__pools do + self.__pools[i]:flush() + end +end + --- Returns the Instance the System is in. -- @return The Instance function System:getInstance() return self.__instance end ---- Returns if the System has the Entity. --- @param e The Entity to check for --- @return True if the System has the Entity. False otherwise -function System:__has(e) - return self.__all[e] and true -end - --- Default callback for system initialization. -- @param ... Varags function System:init(...) @@ -170,12 +178,12 @@ function System:addedTo(instance) end -- Default callback for when a System's callback is enabled. --- @param callbackName The name of the callback that was enabled +-- @param callbackName The name of the callback that was enabled function System:enabledCallback(callbackName) end -- Default callback for when a System's callback is disabled. --- @param callbackName The name of the callback that was disabled +-- @param callbackName The name of the callback that was disabled function System:disabledCallback(callbackName) end