Skip to content

Instantly share code, notes, and snippets.

@CarlLee
Created June 17, 2019 09:47
Show Gist options
  • Save CarlLee/e08c7d94c51d5fa986ae366ddcd20cf2 to your computer and use it in GitHub Desktop.
Save CarlLee/e08c7d94c51d5fa986ae366ddcd20cf2 to your computer and use it in GitHub Desktop.
Simple ecs implementation
local Entity = {
}
local EntityMeta = {
__index = function(entity, key)
local o = rawget(Entity, key)
if(o ~= nil) then
return o
end
local component_id = key
if(type(component_id) == "string") then
component_id = entity:lookup_component_id(key)
if(component_id == nil) then
return nil
end
end
local component_index = entity.component_indices[component_id]
if(component_index ~= nil) then
local components = entity.world.components[component_id]
if(components ~= nil) then
return components[component_index]
end
end
return nil
end
}
function Entity:new(world)
local o = {}
o.world = world
o.component_indices = {}
setmetatable(o, EntityMeta)
return o
end
function Entity:add_component(key, c)
local component_id = key
if(type(component_id) == "string") then
component_id = self:lookup_component_id(component_id)
end
if(component_id == nil) then
return
end
local world = self.world
local components = world.components[component_id]
if(components == nil) then
components = {}
world.components[component_id] = components
end
table.insert(components, c)
local idx = #components
self.component_indices[component_id] = idx
self.mask = self.mask or 0
self.mask = self.mask | (1 << component_id)
end
function Entity:lookup_component_id(name)
return self.world.component_map[name]
end
local World = {
}
function World:new(o)
local o = o or {
entities = {},
components = {},
systems = {},
component_map = {}
}
setmetatable(o, {__index = World})
return o
end
function World:new_entity()
local e = Entity:new(self)
table.insert(self.entities, e)
return e
end
function World:add_system(s)
table.insert(self.systems, s)
s.mask = self:generate_mask(s.components)
end
function World:register_components(m)
self.component_map = m
end
function World:generate_mask(components)
local mask = 0
for i, v in ipairs(components) do
local component_id = self.component_map[v]
if(component_id ~= nil) then
mask = mask | (1 << component_id)
end
end
return mask
end
function World:tick(dT)
for system_idx, system in ipairs(self.systems) do
local entities = {}
for entity_idx, entity in ipairs(self.entities) do
if(system.mask & ~entity.mask == 0) then
table.insert(entities, entity)
end
end
system.tick(entities, dT)
end
end
return {
World = World
}
local World = require("ecs").World
local w = World:new()
w:register_components({
transform = 0,
rotation = 1
})
local e1 = w:new_entity()
local e2 = w:new_entity()
e1:add_component("transform", {x = 0, y = 0, z = 9})
e2:add_component("transform", {x = 0, y = 0, z = 9})
e2:add_component("rotation", {angle = 0})
function tick(entities, dT)
for i, e in ipairs(entities) do
e.transform.x = e.transform.x + dT
end
end
local s = {
tick = tick,
components = {"transform", "rotation"}
}
w:add_system(s)
w:tick(0.5)
print(e1.transform.x)
print(e2.transform.x)
w:tick(0.56)
print(e1.transform.x)
print(e2.transform.x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment