I picked up a copy of PICO-8 a few months ago on a whim and have been playing around with it, following a tutorial here and there, etc. Really enjoying it and I love seeing the creativity of people in the community.
I have yet to try my hand at an actually complete game and, as I'm basically infinitely distractable, may never actually accomplish it. In the meantime, to learn some of the ins and outs of Lua, with which I was not previously familiar, I've combined two of my favourite software writing pastimes: re-inventing wheels and making tiny utilities.
In that spirit, I give you:
- stream-ecs (267 tokens), a (sort of) reactive stream based entity-component-system with automatic entity queue management, and
- prot-oo (72 tokens), prototype based object-oriented programming (in a separate post)
I'll describe them a bit below and there's more info at the github project page. Each tool has its own README describing it in detail.
stream-ecs
I know there are a few different ECS frameworks floating around the PICO-verse. This one's larger than some and smaller than others but should, I hope, save you tokens in the long run by managing queues of game entities for you.
You start by creating a "world" and then spawning systems off of it:
world = ecs() world :system({'timer'}, increment_timer) world :system({'timer', 'position'}, move_character) |
Each system creates and manages its own queue and when you add entities to the world...
world:insert(character) |
... the world passes it to each system which either stores it in its queue, if it matches the selectors, or discards it.
You can also chain systems together to create a sort of filter. This example is functionally identical to the one above:
world = ecs() world :system({'timer'}, increment_timer) :system({'position'}, move_character) |
Entities with a timer component go into the first system's queue then, of those entities with a timer, those which also have a position component go into the second system's queue.
You define components like so:
position = component('position', {'x', 'y'}) |
Which returns a constructor function:
p = position(1, 2) p.x -- 1 p.y -- 2 |
And you create entities like so:
character = entity() :add(position(1, 2)) :add(timer(0)) |
There's a pre-defined draw component and draw system so you don't have to manage those manually either, you can just do this:
function _draw() cls() world:draw() end |
And updating all your entities is this easy:
function _update() world:run() end |
Here are a couple demos:
Simple particle system
Spawns a new particle at the source each tick. Particles are removed from the system after 200 ticks so there are 200 particles on screen at any given time.
Simple platformer
Collisions are a bit wonky: the character occasionally falls into the floor some reason but that is, presumably, because of how I wrote collisions and not the ECS itself. It should be enough to give you an idea of how it works, anyway.
[Please log in to post a comment]