Last active
April 18, 2024 07:23
-
-
Save wolf81/d2fcb03c783c52ffa05a3c85be696c82 to your computer and use it in GitHub Desktop.
A simple ECS structure for Lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
-- A very basic ECS implementation, without Components clearly defined. | |
-- | |
-- A component should be a class in order to properly use it with a System. | |
-- A component is a class if the table has a metatable describing it's type. | |
-- | |
-- Suppose we have a component class Visual to show animations, we can then | |
-- add the Visual component to an Entity instance as follows: | |
-- | |
-- local player = Entity() | |
-- player:addComponent(Visual()) | |
-- | |
-- If we now want to easily update all Visual components for all entities, | |
-- we can add the Visual components of all entities to a System as follows: | |
-- | |
-- local visualSystem = System(Visual) | |
-- for _, entity in ipairs(entities) do | |
-- visualSystem:addComponent(entity) | |
-- do | |
-- | |
-- ... then later we can use the visualSystem in the update(dt) method: | |
-- | |
-- visualSystem:update(dt) | |
-- | |
-- ... and all Visual components in the system will be updated. | |
-- | |
-- Using it myself with stringly-typed classes and a factory that adds | |
-- Components to an Entity instance based on class type name. For example | |
-- an entity with type string 'player' will have an Input component added | |
-- to manage keyboard and mouse input. A monster will have a AI component | |
-- added to control movement, attacks, ... | |
--]] | |
--[[ ENTITY ]]-- | |
Entity = {} | |
-- constructor | |
Entity.new = function(...) | |
local components = {} | |
-- add a component by type - if a component for given type is already added, will be replaced | |
local addComponent = function(self, component) | |
components[getmetatable(component)] = component | |
end | |
-- remove a component by type | |
local removeComponent = function(self, T) | |
components[T] = nil | |
end | |
-- get a component by type | |
local getComponent = function(self, T) | |
return components[T] | |
end | |
return setmetatable({ | |
getComponent = getComponent, | |
removeComponent = removeComponent, | |
addComponent = addComponent, | |
}, Entity) | |
end | |
setmetatable(Entity, { | |
__call = function(_, ...) return Entity.new(...) end, | |
}) | |
--[[ SYSTEM ]]-- | |
System = {} | |
System.new = function(T) | |
local components = {} | |
local addComponent = function(self, entity) | |
local component = entity:getComponent(T) | |
if component ~= nil then | |
components[entity] = component | |
end | |
end | |
local removeComponent = function(self, entity) | |
components[entity] = nil | |
end | |
local update = function(self, dt, ...) | |
for entity, component in pairs(components) do | |
component:update(dt, ...) | |
end | |
end | |
return setmetatable({ | |
addComponent = addComponent, | |
removeComponent = removeComponent, | |
update = update, | |
}, System) | |
end | |
setmetatable(System, { | |
__call = function(_, ...) return System.new(...) end, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment