Skip to content

YetAnotherClown/planck

Repository files navigation

Planck, an ECS Scheduler

GitHub License Documentation Wally Package

An Agnostic Scheduler, inspired by Bevy Schedules and Flecs Pipelines and Phases.

Installation

You can install Planck with Wally

[dependencies]
Planck = "yetanotherclown/planck@0.2.0-rc.1"

What is Planck?

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.

Does any of this really matter?

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.

What's Next?

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.

Quick Overview

While it's highly suggested you read the documentation, here is a quick overview of Planck's API.

The Scheduler

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

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

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

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.

Conditions

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.

Inspiration

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.