Intro
This is my take on using Legion ECS with Godot and Rust.
The core premise of this is one Godot node that holds the schedules,
and executes them in _process
and _physics_process
respectively.
For information on how to use GDNative with Rust and Godot see the previous post: Up and running with Rust and Godot: A basic setup.
Setup the GameWorld
Start by adding a Godot node, and name it “GameWorld”, and attach a
NativeScript
called “GameWorld”.
This is all that has to be done in Godot for now (additional nodes are added later).
Create a new file: src/gameworld.rs
and add the following code.
|
|
(and don’t forget to add the struct to the init
function)
|
|
Adding a world
Without a World
it’s not possible to execute the systems.
I have opted to place the world in a Mutex
so it can be accessed from other
threads if needed. For this post I ignore the Universe
but the same method of
adding the World
could be applied to the Universe
:
A utility function for easily accessing the world is added as well.
This way it’s easy to work with the world with_world(|world| /* use world
*/);
.
|
|
Adding a resource first
Before creating the schedules, create the Delta
resource. This is one way of
passing the delta time value from _process
to all the systems.
|
|
Creating schedules
With access to a World
it is now possible to add resources and components,
however to run systems a Schedule
is recommended.
There are two types of schedules in this setup:
Process
and Physics
(ignoring physics for now).
The Process
will handle all systems that run on _process
and Physics
will
run all systems that will execute on _physics_process
.
Create a new struct in src/gameworld.rs
and call it Process
.
|
|
The Process
struct holds all the resources that will be made available to the
systems that are registered with schedule
.
Finally the execute
function is called on _process
, providing the delta
resource with a new value and executing all the systems.
|
|
Note that it’s safe to touch the scene tree when adding a thread local system.
Therefore all systems that manipulate Godot nodes should be added with
add_thread_local
. Components that are wrapping Godot nodes requires unsafe
impl of Send
and Sync
.
Add schedules to the world
Attach the Process
struct to the GameWorld
|
|
Then instantiate Process
on _init
:
|
|
Finally it’s possible to call the execute
function on the process in
_process
. Update the GameWorld
’s _process
function:
|
|
&self
changed to &mut self
in the above code snippet.
At this point all the systems in Process
will execute every time _process
is
called.
Adding a system
There are two types of systems that can be added in Legion (three if you
consider thread_local_fn
).
A Runnable
(thread local) and a Schedulable
(not thread local).
Runnable
and everything that is just plain data to be Schedulable
.
Create a system that moves a node across the screen:
|
|
Finally update the new
function inside Process
, to add the new system:
|
|
Adding a component
Open up Godot, load the GameWorld.tscn scene and add a Node2D
with the name:
“TheNode”.
To be able to see anything, add either a Sprite
(or in my case I added a
ColorRect
) to the node.
Finally add the component to the world in the _ready
function of the
GameWorld
:
|
|
Compile (and copy the lib into Godot) and run the Godot project. The node should now move across the screen from left to right.
Final notes
An example with this code is available on Github: rust-godot-legion-setup
The code in the project has been run and tested on Linux only, for Windows and
MacOS remember to update the .gdnlib
file
I have opted to keep my physics
and process
schedules separate, however they are very much identical, which is why the physics struct is omitted from this post. This means
that resources aren’t shared between them.
This can be solved by having two schedules in Process
instead (one additional
for physics) with an additional execute_physics
function for _physics_process
.