Log In  


Here's a tiny entity-component-system framework for anyone who might need such a thing! It weighs in at only 108 tokens as of v1.0. This framework assumes (but does not technically require) the strictest definition of the concept, that being that entities and components define no behavior internally but rather are acted upon by externally defined systems that function on the data contained in the entity/components themselves.

The implementation of systems is a slightly refined version of @selfsame's earlier implementation, which treated the "components" simply as keys of the entity, rather than modular objects in their own right. It's also been slightly token-optimized, at 38 instead of 47, but assumes at least the table structure implemented by the entity factory function. I highly recommend @selfsame's version if you need something even more lightweight than this, at the cost of a little flexibility.

If you really need to be stingy about tokens, you can even leave out the component factory function to save 16 tokens, at a minimum of 0 extra tokens per component creation. It's mostly included for simplicity and clarity, but is not strictly required to function.

Copy and paste the code below into a new tab of your project to get started - I'd very much appreciate if you leave the credit comment at the top, but I won't be mad if you don't =)

--tiny ecs v1.1
--by katrinakitten

function ent(t)
 local cmpt={}
 t=t or {}
 setmetatable(t,{
  __index=cmpt,
  __add=function(self,cmp)
   assert(cmp._cn)
   self[cmp._cn]=cmp
   return self
  end,
  __sub=function(self,cn)
   self[cn]=nil
   return self
  end
 })
 return t
end

function cmp(cn,t)
 t=t or {}
 t._cn=cn
 return t
end

function sys(cns,f)
 return function(ents,...)
  for e in all(ents) do
   for cn in all(cns) do
    if(not e[cn]) goto _
   end
   f(e,...)
   ::_::
  end
 end
end

From there, you can use the system like so. Keep in mind that the + and - operators on entities are destructive and modify the existing entity, regardless of whether you use += or -=; since they result in the same token count, I highly recommend you still use the assignment variants unless you're really in a performance crunch, for the sake of clarity.

local entity    = ent({ ... })
local component = cmp("name", { ... })
local component = { _cn="name", ... }  --if cmp is not included

entity += component  --add a component
entity -= "name"     --remove a component

if entity.name then
 --executes only if the "name" component exists
 --access component properties via
 entity.name.property
end

local system = sys({ "name", ... }, function(e, ...)
 --will execute for each entity with all listed components
 --varargs will be passed through from system call
end)

system({ entity, ... })
system({ entity, ... }, "some args", ...)

Here's a simple demo of using this system with the following test code (outdated - v1.0):

function _init()
 local e1=ent({ x=0,y=0 })
 local e2=ent({ x=0,y=0 })
 e1+=cmp("test",{state="cmp1"})
 e2+=cmp("test",{state="cmp2"})

 local s=sys({"test"},function(e,s)
  ?s..e.cmp.test.state
 end)

 s({e1,e2},"before: ")
 e2-="test"
 s({e1,e2},"after: ")
end

Cart #gazihisifi-0 | 2020-07-30 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
10

Changelog:

  • v1.1 (BREAKING)
    • Changed access pattern from e.cmp.name to e.name
    • This reduces access cost but may clobber entity properties, so be careful!
  • v1.0
    • Initial release
10


1

A few hours of work under this system yielded this prototype - doesn't look like much, and please excuse my terrible spritework, but given that my last platformer prototype didn't even reach fully functioning map collisions, I'd say 3-4 hours for all of the standard platformer physics, coyote time, a simple animation system implemented for walking/jumping/falling/crouching, and all of the above wrapped up in an ECS system that should make it quite easy to reuse for other elements of the game, weighing in at only 1033 tokens, all constitutes a fairly glowing recommendation (albeit admittedly a pretty biased one).

If there's interest, I'll share the code for this prototype once I've had a day or two to clean it up a bit and make it at least passably presentable.


1

Please do share! I'm interested especially in the collision detection and control related systems.


1

Please, I'm also interested in the prototype. I did make a little shmup game with selfsame ECS implementation https://www.lexaloffle.com/bbs/?tid=38682. It was my first try at using this game programming pattern and I found it very flexible.


1

@apa64 @ragnatic Here's a slightly updated / cleaned up version of the protoype - feel free to dig around and get a feel for the code =)



2

Finally I had the chance to start looking at and learning ECS again - yours is a really compact implementation! I think I'll write a blog post to work through (in my own head) how it works :) So far I've drawn a couple of entities: https://github.com/apa64/road-to-ecs/blob/master/01-draw.p8 Next I'll look how to do controls.

edit: Blog here https://www.lexaloffle.com/bbs/?tid=39315


1

The idea behind this ECS library is fantastic! I love the __add hack 🤯

I've been using it in my own projects, slowly adding to it over time, and have ended up with something I thought worth sharing back. I call it "PECS" (PICO-8 Entity Component System): https://github.com/jesstelford/pico-8-pecs



[Please log in to post a comment]