diff options
Diffstat (limited to 'honey/ecs.lua')
| -rw-r--r-- | honey/ecs.lua | 277 | 
1 files changed, 6 insertions, 271 deletions
diff --git a/honey/ecs.lua b/honey/ecs.lua index b0409e4..82fd877 100644 --- a/honey/ecs.lua +++ b/honey/ecs.lua @@ -1,274 +1,9 @@ -math.randomseed(os.time()) - -local glm = require 'honey.glm' - -local module = {} -setmetatable(module, {__index=_G}) -setfenv(1, module) - - ---===== EntityDb =====-- - - --- EntityDb is a database of entities and their associated components --- it should be quite efficient to query for all entities with a given component, and reasonably --- efficient to query for all components of a given entity - - -EntityDb = {} -EntityDb.__index = EntityDb - - -function EntityDb.new(_) -	local self = { -		entities = {}, -		components = {}, -	} -	setmetatable(self, EntityDb) -	return self -end -setmetatable(EntityDb, {__call=EntityDb.new}) - - -local function serialize(tbl) -	local tostr = function(x, value) -		if type(x) == "table" then -			if x.__tostring then -				return tostring(x) -			else -				return serialize(x) -			end -		elseif type(x) == "string" then -			if value then -				return string.format("\"%s\"", x) -			else -				return x -			end -		else -			return tostring(x) -		end -	end -	local str = "{" -	for key, value in pairs(tbl) do -		if type(key) == "string" and string.match(key, "^_") then -			-- ignore keys starting with an underscore -		else -			str = str .. string.format("%s=%s,", tostr(key), tostr(value, true)) -		end -	end -	str = string.sub(str, 1, -2) .. "}" -	return str -end - - --- save current database to file -function EntityDb.save(self, filename) -	local file, err = io.open(filename, "w") -	if not file then error(err) end - -	for entity in pairs(self.entities) do -		local components = self:queryEntity(entity) -		file:write(string.format("Entity(\"%s\", %s)\n", entity, serialize(components))) -	end - -	file:close() -end - - --- load database from file -function EntityDb.load(self, filename) -	print(collectgarbage("count")) -	self.entities = {} -	self.components = {} -	collectgarbage() -	print(collectgarbage("count")) -	local env = { -		Entity = function(id, components) -			self:createEntity(id) -			self:addComponents(id, components) -		end, -		Vec3 = glm.Vec3, -		Mat4 = glm.Mat4, -	} -	local f, err = loadfile(filename) -	if not f then error(err) end -	setfenv(f, env) -	f() -end - - --- check if a given entity id is legitimate -function EntityDb.checkIsValid(self, id) -	if not self.entities[id] then -		error(string.format("invalid entity id: %s", tostring(id))) -	end -end - - -local random = math.random -local function uuid() -	local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' -	return string.gsub(template, '[xy]', function (c) -		local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) -		return string.format('%x', v) -	end) -end - - --- create a new entity -function EntityDb.createEntity(self, id) -	local id = id or uuid() -- allow inserting entities at preset ids for loading -	self.entities[id] = true -	return id -end - - --- add a component to an entity -function EntityDb.addComponent(self, id, name, value) -	self:checkIsValid(id) -	 -	-- create the relevant component table if it doesn't exist -	if not self.components[name] then -		self.components[name] = { count=0, data={} } -	end - -	local component = self.components[name] -	component.data[id] = value -	component.count = component.count + 1 -end - - --- add multiple components at once, for convenience -function EntityDb.addComponents(self, id, components) -	for name, value in pairs(components) do -		self:addComponent(id, name, value) -	end -end - - --- create an entity with components -function EntityDb.createEntityWithComponents(self, components) -	local id = self:createEntity() -	self:addComponents(id, components) -	return id -end - - --- get all entities with a given component -function EntityDb.queryComponent(self, name) -	local component = self.components[name] -	if component then  -		return component.data -	else -		return {} -	end -end - - --- get all components associated with an entity -function EntityDb.queryEntity(self, id) -	self:checkIsValid(id) -	local query = {} -	for name, component in pairs(self.components) do -		query[name] = component.data[id] -	end -	return query -end - - --- get a specific component from an entity -function EntityDb.getComponent(self, id, name) -	self:checkIsValid(id) -	return self.components[name].data[id] -end - - --- remove a component from an entity -function EntityDb.removeComponent(self, id, name) -	self:checkIsValid(id) -	local component = self.components[name] -	if component.data[id] ~= nil then -		component.data[id] = nil -		component.count = component.count - 1 -		if component.count == 0 then -			self.components[name] = nil -		end -	end -end - - --- remove an entity from the db -function EntityDb.deleteEntity(self, id) -	self:checkIsValid(id) -	for name in pairs(self.components) do -		self:removeComponent(id, name) -	end -	self.entities[id] = nil -end - - ---===== SystemDb =====-- - -SystemDb = {} -SystemDb.__index = SystemDb - - -function SystemDb.new(_, entityDb) -	local self = { -		systems = {}, -		sorted = {}, -		entityDb = entityDb, -	} -	setmetatable(self, SystemDb) -	return self -end -setmetatable(SystemDb, {__call=SystemDb.new}) - - -local function systemId() -	local template = "xx:xx:xx" -	return string.gsub(template, "x", function(c) -		return string.format("%x", random(0, 0xf)) -	end) -end - - -function SystemDb.addSystem(self, systemFunc, params) -	local system -	if type(systemFunc) == "table" then -		system = systemFunc -	else -		local params = params or {} -		params.db = self.entityDb -		system = systemFunc(params) -	end - -	local id = systemId() -	self.systems[id] = system -	table.insert(self.sorted, id) -	self:sort() -	return id -end - - -function SystemDb.sort(self) -	table.sort(self.sorted, function(a, b) return (self.systems[a].priority or 100) < (self.systems[b].priority or 100) end) -end - - -function SystemDb.update(self, dt) -	for _, system in ipairs(self.sorted) do -		self.systems[system]:update(dt) -	end -end - - -function SystemDb.removeSystem(self, id) -	self.systems[id] = nil -	for i=#self.sorted,1,-1 do -		if self.sorted[i] == id then table.remove(self.sorted, i) end -	end -end +local module = require 'honey.ecs.ecs' +module.collision = require 'honey.ecs.collision' +module.node      = require 'honey.ecs.node' +module.physics   = require 'honey.ecs.physics' +module.render    = require 'honey.ecs.render' +module.script    = require 'honey.ecs.script'  return module  | 
