Log In  

Hi all, I recently started tinkering with PICO-8 which is amazing, but coming from a Unity background, I'm still wrapping my head around it. I've been trying to put together a little ecs framework for me to use in prototypes which is more Unity-like than some of the ecs snippets I've seen on this forum (I'm sure those are better once you're used to the way PICO-8 does things, I'm just trying to make a stepping stone). I thought for the purposes of devs like me wanting to learn things in a bit more of a familiar way, I might as well share what I've learned. Unlike the ecs frameworks I've seen so far which use pattern matching for running methods, I've tried to make the "components" here self contained, and then adding that functionality to the entity table. With no custom components (which need to be made to actually use this) it comes to 108 tokens

Very rough library code below:

-- all the entities in the game
entities = {}

-- entity "constructor" - returns an entity which is really just a table of components with 
-- a run() and a draw() method
function mk_entity()
    local e = {}
    e.components = {}

    -- basically override the indexer of the entity table to allow for syntax like
    -- 'player.transform' instead of 'player.components.transform'
    setmetatable(e,
    {
        __index = function(entity,component_name)
            if (entity.components[component_name]) then
                return entity.components[component_name]
            else
                return nil
            end
        end
    })

    -- iterates through our components and calls their run() method if they have one
    e.run = function()
        for c_name,c in pairs(e.components) do
            if (c["run"]) then
                c.run(e)
            end
        end
    end

    -- iterates through our components and calls their draw() method if they have one
    e.draw = function()
        for c_name,c in pairs(e.components) do
            if (c["draw"]) then
                c.draw(e)
            end
        end
    end
    add(entities,e)
    return e    
end

-- component "constructor" which is a table with a name (which is a key for this component on the entity)
function mk_component(component_name,entity)
    c = {}
    entity.components[component_name] = c
    return c
end

And here's some example usage

-- an example component with some fields and methods
function add_transform(entity, x, y)
    t = mk_component("transform",entity)
    t.x = x
    t.y = y
    t.w = 10
    t.h = 8

    t.run = function ()
        t.x += 1
    end

    t.draw = function ()
        print(t.x .. ' ' .. t.y .. ' ' .. t.w .. ' ' .. t.h)    
        printh(t.x .. ' ' .. t.y .. ' ' .. t.w .. ' ' .. t.h)    
    end
end

--example usage
function _init()
    player = mk_entity()
    add_transform(player,32,60)  
    printh(player.transform)
end

-- update all entities
function _update()
    for entity in all(entities) do
        entity.run()
    end
end

-- draw all entities
function _draw()
    cls()
    for entity in all(entities) do
        entity.draw()
    end
end

Hope this helps someone!

P#140595 2024-01-25 11:25 ( Edited 2024-01-25 11:27)


[Please log in to post a comment]