Thoughts on this ECS setup?
Posted: Sun Mar 06, 2016 12:49 am
Here's what I've been doing for ECS lately. I wanted to get your feedback on it.
In this setup entities are tables, and components are properties of those tables. I have a system.lua that looks something like this:
Individual systems look like this:
In-play gamestates look something like this:
That's pretty much it. I realize the select(i, ...) stuff won't JIT and I'll replace it with some code generation at some point. I also realize there's no caching, but I don't care. In almost every situation I've tested, caching actually gave poorer performance than not caching. This has to do with the number of entities and systems; if you don't have many entities (maybe < 10k) and most of your systems apply to most of your entities, you probably won't benefit much from caching (because of the overhead from creating tables and storing results there). If the cache is getting invalidated a lot from stuff getting created or destroyed, caching can slow things down. Other than that, do you guys see any problems with this approach?
In this setup entities are tables, and components are properties of those tables. I have a system.lua that looks something like this:
Code: Select all
--- Run `process` if all varargs are not nil.
local function invoke (process, ...)
for i = 1, select('#', ...) do
if select(i, ...) == nil then return end
end
process(...)
end
--- Create a System.
--- @tparam function (entity, ...) extract
--- Extracts components from an entity, and returns all components
--- and any other arguments passed the `process` function.
--- @tparam function (...) process
--- Process components and other data returned by `extract`.
return function (extract, process)
return function (entities, ...)
for _, entity in ipairs(entities) do
invoke(process, extract(entity, ...))
end
end
end
Code: Select all
-- system/update/move.lua
return require 'system' (
function (entity, dt)
return entity.position, entity.velocity, dt
end,
function (p, v, dt)
p.x = p.x + v.x * dt
p.y = p.y + v.y * dt
end
)
Code: Select all
local game = {}
local updateSystems = {
require 'system.update.attack',
require 'system.update.fall',
require 'system.update.move',
require 'system.update.sleep',
require 'system.update.think',
DEBUG and require 'system.update.log',
-- more stuff here
}
local drawSystems = {
require 'system.draw.sprite',
DEBUG and require 'system.draw.hitbox',
}
function game:update (dt)
for _, update in ipairs(updateSystems) do
update(entities, dt)
end
end
function game:draw ()
for _, draw in ipairs(drawSystems) do
draw(entities)
end
end
return game