Im quirte new yto the godot engine been playing with it for a few weeks. I want to make a state machine for my character controler i was able to make an enum based one but iv heard many people say multi-node/object is better. Iv tried to build one but there so confusing
Can i stick with enum or will i have to do node and if so pleace can i have some advice on how to make them
State machine is a generalized concept, or a “design pattern” in fancy OO speak. If you have a good understanding of the concept, you should be able to vary the implementation.
The gist is to branch the code depending on the state of one or more flags. This can be done in myriad ways, enums and nodes included.
I like how it split into function with my current code just so many people were telling me nodes is “the best way” im quite new to godot so the node was is just super confusing at the moment
(Google translator)
It depends on the scope of your state machine.
I’m not an expert, but I prefer nodes for the following reasons:
I have a visual representation of my states.
My states have an associated script where I can keep only the code related to that state. Even variables that are only used in that state are only there. This makes it easier for me to clearly understand what I’m doing in that state. This is what I consider most important.
If your state machine is hierarchical, you could even see states within states (although I haven’t implemented that myself).
You initialize states from the parent, traversing through the children.
You can include other child nodes within the states themselves if they require any extra functionality.
I like to put the states in the state machine, which is the parent of the states, as exported variables. This way, to perform a state change, I use the variable “machine.idle_state” to indicate the new state to go to, without having to work anywhere with enumerations of state names or callables that represent the states.
To create a state machine with nodes, you would simply create a machine class that extends Node and a state object that also extends Node.
class_name StateMachine extends Node
…
class_name State extends Node
…
Then the script for the StateIdle node will extend State, or, if you use inheritance, from the StateInFloor node, for example.
Anyway, I recommend you start implementing your state machine as you see fit and only modify it as you see problems with your design.
If you mean you like all your code in one file, then this is going to cause you problems down the road. A Node-based state machine, as @capitanlopez mentioned, is a good way to help you divide your code up.
A good first step might be to split your Enum state machine into another file and see ho to make that work first though.
Also, if you follow the link @capitanlopez posted (which is to a much longer post I made on state machines) there’s a link to my State Machine Plugin.
Assuming C# with the state machine as an actual class with methods with initialising the state, changing the state and so on. And then its just a matter of changing the state with a lambda expression but could be wrong.
Also, you might be interested in this discussion here: Open Source Tool Suite - Released In which @Ryn explains they’re basically making a game in Assembly with Godot taking care of drivers and display.
Thanks for the mention, our next devlog video on YouTube will cover all the HOW’S and WHY we’re using assembly. It’ll also include a little demo play test of some of the mechanics for our new game all running in assembly.
I first liked the Node based one as you can work on each state independently but I had a hard time debugging with it.
For example, I may have flipped a bool somewhere and if it causes problem then I’d have to look for it in all those scripts. Another example is when a certain state script is interfering with a general script and error only shows there’s a problem with a general script.
And this is only when I worked with 4-5 states, I can’t imagine me trying to debug with 10+. How do experienced people do it?
They don’t use state machines like that. The discrete state machine proves to be inadequate for modeling player state as soon as you need to go beyond the textbook idle/walk/run example. Even if you use its hierarchical or concurrent variants.
When processing more complex player state you typically need to branch on configurations of multiple switches while the state machine boxes you into branching on a single switch at a time.
If you force yourself to use discrete state machines in your prototypes, it’ll severely limit your game design options and nudge them towards simplistic well known mechanisms.
Giving each state a class_name will make the errors very clear as to which script it is coming from. It also helps to send the current state to output or logs.
I know exactly what state I’m in and what state I came from if the game crashes or the debugger halts execution.
Well it’s hard to say what you can do, but typically the way to handle this is to make things work, then refactor.
For example, I just decided to add a feature to create an AudioStreamPlayer2D to my states that if I attach a sound file, the player plays the sound. I implemented it for the JumpPlayerState, and then the SlidePlayerState. Then I realized that both were being used when the state was entered. I could see I was going to use it in the HurtCharacterState and DeathCharacterState too. So I added the common functionality to the base CharacterState - from which both inherit - and up until now had only a few lines of code.
So I tested it in the lower states, then moved it up.
That’s a good solution. Especially for simple states. Over time, as you outgrow it, you’ll know what isn’t working for you, and be able to create something that does work for you.
Yea I won’t be doing any 3rd person parkour open world anytime soon so enum for player is good enough but I’m curious..
In term of a simple Godot player control with walk idle run , how’d you implement this technique? I’m assuming “switches” are not just ifs / bools.
“Switches” are your state variables that can be anything, bool flag, continuous values, a range of stepped values… And you branch however you like; ifs, callables, virtual calls…