An Agnostic Scheduler, inspired by Bevy Schedules and Flecs Pipelines and Phases.
You can install Planck with Wally
[dependencies]
Planck = "yetanotherclown/planck@0.2.0-rc.1"
Planck is a standalone scheduler, which allows you to execute code on specific events, with certain conditions, and in a particular order.
This scheduler is library agnostic, which means that it doesn't matter which ECS library your using or if you're even using an ECS. You can use this with Jecs, Matter, ECR, and other Luau ECS Libraries.
Yes, and no. Your ECS code should be able to run in any order, without any conditions, and without concern for which event it's running on, as long as it is running.
The order of execution, and conditions both serve to optimize your code. Some systems don't need to run every frame, which is why we have conditions. And the actual order of execution is to reduce latency between changes and effects in your ECS world.
Let's say we have systemA
and systemB
. systemA
modifies data in our world which systemB
depends on.
If systemA
runs after systemB
, then systemB
will have to wait a whole frame for the modifications to be made.
This is called being off-by-a-frame, and this is why we care about the order of execution.
You may not completely understand what's written above. That's fine.
For now, you should read the Official Documentation on how to get started with Planck. These concepts will be explained more in depth as you read.
While it's highly suggested you read the documentation, here is a quick overview of Planck's API.
This is the core of Planck, this is where you add your Systems and set your Phases, Pipelines, and Run Conditions.
local Planck = require("@packages/Planck")
local Scheduler = Planck.Scheduler
local Jecs = require("@packages/Jecs")
local World = Jecs.World
local world = World.new()
local state = {}
local scheduler = Scheduler.new(world, state)
Systems are really simple, they are just functions which run on an event or in a loop.
local function systemA(world, state)
-- ...
end
return systemA
And to add it to our Scheduler,
-- ...
local systemA = require("@shared/systems/systemA")
local scheduler = Scheduler.new(world, state)
:addSystem(systemA)
Phases are used to split up your frame into different sections, this allows us to schedule our systems to run at different moments of a given frame.
local Planck = require("@packages/Planck")
local Scheduler = Planck.Scheduler
local Phase = Planck.Phase
-- ...
local systemA = require("@shared/systems/systemA")
local myPhase = Phase.new("myPhase")
local scheduler = Scheduler.new(world, state)
:insert(myPhase)
:addSystem(systemA, myPhase)
Planck has lots of built-in Phases that should work for most cases, → Built-in Phases
Pipelines are ordered groups of Phases, they make working with larger collections of Phases (which all run on the same event) easier.
local Phase = Planck.Phase
local Pipeline = Planck.Pipeline
local Scheduler = Planck.Scheduler
local PreUpdate = Phase.new()
local Update = Phase.new()
local PostUpdate = Phase.new()
local UpdatePipeline = Pipeline.new()
:insert(PreUpdate)
:insert(Update)
:insert(PostUpdate)
local scheduler = scheduler.new(world)
:insert(UpdatePipeline, RunService, "Heartbeat")
Tip
The UpdatePipeline
seen here, already exists in Planck! It's a built-in Pipeline that you can use without any setup.
See all Built-in Phases.
When we run all our systems every frame, there are a lot of systems that may not actually need to run. Run Conditions allow us to run our Systems, Phases and Pipelines only sometimes.
local function condition(world)
if someCondition then
return true
else
return false
end
end
local scheduler = Scheduler.new(world)
:addRunCondition(systemA, condition)
:addRunCondition(somePhase, condition)
:addRunCondition(somePipeline, condition)
Conditions can be useful, but you should use them carefully. It's suggested that you read our page on Conditions to see some useful examples and learn when you should use them.
Planck's API design is heavily influenced by the Bevy Engine, with Schedules, RunConditions, and more. Planck also draws inspiration from Flecs for Pipelines and Phases.
We're combining the simple, and beloved API of Bevy with the concept of Pipelines and Phases.