p01 / pico-8-pecs

A PICO-8 Entity Component System (ECS) library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Usage

Everything is part of a World. Create one with createECSWorld():

local world = createECSWorld()

Components describe data containers that can be instantiated:

local Position = world.createComponent()
local Velocity = world.createComponent()

An Entity is a collection of instantiated Components.

local player = world.createEntity()
player += Position({ x=10, y=0 })
player += Velocity({ x=0, y=1 })

All data within an Entity can be accessed as long as you know the Component it belongs to:

print(player[Position].x, 10, 10, 7)

Systems allow specifying game logic (as a function) which applies to Entities that have a certain set of Components (ie; a filter).

The game logic function of a System is executed once per matched Entity, ensuring performance is maintained when there are many entities. The function receives any arguments passed when calling the method. Useful for passing in elapsed time, etc.

local move = world.createSystem({ Position, Velocity }, function(entity, ticks)
  entity[Position].x += entity[Velocity].x * ticks
  entity[Position].y += entity[Velocity].y * ticks
end)

-- Run the system method against all matched entities
-- Any args passed will be available in the system callback function
local ticks = 1
move(ticks)

Example

local world = createECSWorld()

local Position = world.createComponent()
local Velocity = world.createComponent()

local player = world.createEntity({ name="Jess" })

player += Position({ x=10, y=0 })
player += Velocity({ x=0, y=1 })

local move = world.createSystem({ Position, Velocity }, function(entity, ticks)
  entity[Position].x += entity[Velocity].x * ticks
  entity[Position].y += entity[Velocity].y * ticks
end)

local lastTime = time()
function _update()
  move(time() - lastTime)
  lastTime = time()
end

function _draw()
  cls()
  print(player[Position].x.." "..player[Position].y, 10, 10, 7)
end

API

createECSWorld() => World

Everything in PECS happens within a world.

Can be called multiple times to create multiple worlds:

local world1 = createECSWorld()
local world2 = createECSWorld()

Each world has its own Components and Entities.

World#update()

Must be called at the start of each _update() before anything else.

World#createEntity([attr[, Component, ...]]) => Entity

local player = world.createEntity()

local trap = world.createEntity({ type="spikes" })

local enemy = world.createEntity({}, Position({ x=10, y=10 }), Rotation({ angle=45 })
Adding a Component to an Entity
player += Position({ x=100, y=20 })
Removing a Component from an Entity
player -= Position

World#createComponent([defaults]) => Component

local Position = world.createComponent()

local Drawable = world.createComponent({ color: 8 })

World#createSystem(filter, callback) => Function

Where filter is a table of Components, and callback is a function that's passed the entity to operate on.

Returns a function that when called will execute the callback once per Entity that contains all the specified Components.

When executing the function, any parameters are passed through to the callback.

local move = world.createSystem({ Position, Velocity }, function(entity, ticks)
  entity[Position].x += entity[Velocity].x * ticks
  entity[Position].y += entity[Velocity].y * ticks
end)

-- Run the system method against all matched entities
-- Any args passed will be available in the system callback function
local ticks = 1
move(ticks)

Systems efficiently maintain a list of filtered entities that is only updated when needed. It is safe to create many systems that operate over large lists of Entities (within PICO-8's limits).

World#removeEntity(Entity)

Remove the given entity from the world.

Any Systems which previously matched this entity will no longer operate on it.

World#queue(Function)

Useful for delaying actions until the next turn of the update loop. Particularly when the action would modify a list that's currently being iterated on such as removing an item due to collision, or spawning new items.

PECS Lite

pecs.lua includes a Filter & Query system to support Systems. While Systems are a very powerful feature of PECS, it comes at a cost of both tokens and CPU cycles.

pecs-lite.lua is a version of PECS without support for Systems. Components and Entities continue to function identically, but you will have to write your own functions for executing game logic over a sub-set of Entities.

Token Counts:

  • pecs.lua: 576
  • pecs-lite.lua: 245

About

A PICO-8 Entity Component System (ECS) library

License:MIT License


Languages

Language:Lua 100.0%