diff options
Diffstat (limited to 'honey/ecs.lua')
-rw-r--r-- | honey/ecs.lua | 236 |
1 files changed, 28 insertions, 208 deletions
diff --git a/honey/ecs.lua b/honey/ecs.lua index 3632f34..b4def84 100644 --- a/honey/ecs.lua +++ b/honey/ecs.lua @@ -3,226 +3,46 @@ setmetatable(module, {__index=_G}) setfenv(1, module) ---===== filters =====-- +--===== Components =====-- +Component = {} -Filter = {} - --- base filter creation -function Filter.new(_, operation, tbl) - local self = {} - self.keys = {} - self.filters = {} - self.op = operation - - for _, v in ipairs(tbl) do - if type(v) == "function" then - table.insert(self.filters, v) - elseif type(v) == "string" then - table.insert(self.keys, v) +function Component.newFactory(name, params, serialize) + local metatable = {} + metatable.__tostring = serialize or Component.serialize + metatable.__newindex = function(tbl, index, value) + if params[index] ~= nil then + tbl[index] = value + else + error(string.format("%q is not a valid key for a component of type %q", index, name)) end end - - return function(entity, _self) - local entity = _self or entity -- able to call as . or : - return Filter.check(self, entity) - end -end -setmetatable(Filter, {__call=Filter.new}) - - --- base filter checking -function Filter.check(self, entity) - local funcname = "check" .. self.op - return Filter[funcname](self, entity) -end - - --- AND filter (all keys and subfilters must match) -function Filter.AND(tbl) - return Filter("AND", tbl) -end -function Filter.checkAND(self, entity) - for _, subfilter in ipairs(self.filters) do - if not subfilter(entity) then return false end - end - for _, key in ipairs(self.keys) do - if entity[key] == nil then return false end - end - return true -end - - --- OR filter (at least one key or subfilter must match) -function Filter.OR(tbl) - return Filter("OR", tbl) -end -function Filter.checkOR(self, entity) - for _, subfilter in ipairs(self.filters) do - if subfilter(entity) then return true end - end - for _, key in ipairs(self.keys) do - if entity[key] ~= nil then return true end - end - return false -end - - --- NAND filter (at least one key or subfilter must NOT match) -function Filter.NAND(tbl) - return Filter("NAND", tbl) -end -function Filter.checkNAND(self, entity) - for _, subfilter in ipairs(self.filters) do - if not subfilter(entity) then return true end - end - for _, key in ipairs(self.keys) do - if entity[key] == nil then return true end - end - return false -end - - --- NOR filter (no keys or subfilters may match) -function Filter.NOR(tbl) - return Filter("NOR", tbl) -end -function Filter.checkNOR(self, entity) - for _, subfilter in ipairs(self.filters) do - if subfilter(entity) then return false end - end - for _, key in ipairs(self.keys) do - if entity[key] ~= nil then return false end - end - return true -end - - ---===== levels =====-- - -Level = {} -Level.__index = Level - -function Level.new(_) - local self = {} - self.systems = {} - self.entities = {} - self.nextId = 1 - setmetatable(self, Level) - return self -end -setmetatable(Level, {__call=Level.new}) - - -local function systemLt(a, b) - return (a.priority or 50) < (b.priority or 50) -end -function Level.addSystem(self, system) - assert(system.update, "systems must have an 'update' key") - assert(system.filter, "systems must have a 'filter' key") - system.entities = {} - table.insert(self.systems, system) - table.sort(self.systems, systemLt) - if system.setup then - system.setup(system) - end -end - - -local function addEntityToSystem(system, id, entity) - -- check if entity is already present - if system.entities[id] then return end - - if system.onAddEntity then - system:onAddEntity(id, entity) - end - system.entities[id] = true -end - - -local function removeEntityFromSystem(system, id, entity) - -- check if entity is already absent - if not system.entities[id] then return end - - if system.onRemoveEntity then - system:onRemoveEntity(id, entity) - end - system.entities[id] = nil -end - - -function Level.addEntity(self, entity) - local id = self.nextId - self.entities[id] = entity - self.nextId = id + 1 - - for _, system in ipairs(self.systems) do - if system.filter(entity) then - addEntityToSystem(system, id, entity) + return function(tbl) + local tbl = tbl or {} + local self = { __type=name } + for k, v in pairs(params) do + self[k] = v end - end - - return id -end - - -function Level.reconfigureEntity(self, id) - local entity = self.entities[id] - - for _, system in ipairs(self.systems) do - if system.filter(entity) then - addEntityToSystem(system, id, entity) - else - removeEntityFromSystem(system, id, entity) + setmetatable(self, metatable) + for k, v in pairs(tbl) do + self[k] = v end + return self end end -function Level.removeEntity(self, id) - local entity = self.entities[id] - if not entity then error("bad id: "..tostring(id)) end - for _, system in ipairs(self.systems) do - removeEntityFromSystem(system, id, entity) - end - self.entities[id] = nil -end - - -function Level.reconfigureAllEntities(self) - for id in ipairs(self.entities) do - self:reconfigureEntity(id) - end -end - - -function Level.update(self, dt, paused) - local paused = paused or false - for _, system in ipairs(self.systems) do - if (not paused) or (paused and system.nopause) then - if system.preUpdate then - system:preUpdate() - end - if system.prepareEntity then - for id in pairs(system.entities) do - local entity = self.entities[id] - if entity then - system:prepareEntity(entity) - end - end - end - for id in pairs(system.entities) do - local entity = self.entities[id] - if entity then - system:update(entity, dt) - end - end - if system.postUpdate then - system:postUpdate() - end +function Component.serialize(self) + local str = "{" + for k, v in pairs(self) do + if type(v) == "string" then + str = str .. string.format("%s=%q,", k, v) + else + str = str .. string.format("%s=%s,", k, tostring(v)) end end + str = string.sub(str, 1, -2) .. "}" + return str end - return module |