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.