Coming from Godot: How to setup a centralized state machine for a Player Character

Hello Everyone! I am proud to say that I made the jump from Godot to Unreal Engine 5 (mainly from Godot’s current 3D limitations)! But I will say that there has been a harsh transition stage since Godot is an “Inheritance” based engine, while Unreal is a “Component” based engine. I am trying my best to get used to it, and getting there, but I need a little help.

In Godot, my Player Class (inherits CharacterBody3D Class) would be a child in the SceneTree of the Player_Manager Class (inherits Node Class) which acted as the “Centralized State-Machine” of the Player Class. This meant that the Player_Manager was not present in the physical world (because it inherits the Node Class), but still existed in the SceneTree during runtime. More importantly, it still had a _process(float delta) function, which you would call a Tick(float deltaTime) function. So every frame it could see what state the Player instance (child) was currently in, and then call the appropriate function in the Player instance corresponding to that state.

SKIP BELOW PARAGRAPH IF YOU DO NOT NEED AN EXAMPLE OF MY STATE MACHINE:
For example, if the Player instance was currently in the movement state, then the Player_Manager would call the movementState(float delta) function on the reference (pointer) of the Player instance that it had. And if the Player instance changed states to the jump state, then Player_Manager would first call the movementStateExit() function on the Player instance and then jumpStateEnter() function on the Player instance, before swapping the state to be called every frame.

The problem with having this setup in Unreal, is I cannot seem to find anything comparative to the Node Class in Godot. Where an ACharacter can be the child of it in the SceneTree, but its not physically there in the world (but it still maintains the ability to run logic every frame).

This is important to me because the Player_Manager Class also takes care of other things besides just being a state-machine, like loading and saving the Player instance and much more. And it was very nice to abstract away that logic from being inside of the Player instance.

TLDR:
So, my question boils down to:
1.) How would you make a centralized state-machine in Unreal?
2.) What is the equivalence to the Node Class, in Unreal? Such that it can:

  • Have an ACharacter as its child that it oversees.
  • Not be physically present in the game world, but present in the SceneTree.
  • Still have a Tick(float deltaTime) function that it can use to run logic every frame.

Would you instead just make the Player_Manager and Player instance siblings in the SceneTree, and just let the Player_Manager have a reference (pointer) to the Player instance. And then stop trying to think of the Unreal runtime as a SceneTree, but of components being connected via references (pointers)?

P.S.: What is the proper word to call all of the different Node like things in Unreal, like the AActor or UObject?

1 Like

Think about it this way.

In Godot you are writing scripts and attaching them to nodes. The nodes themselves do not have any logic.

In Unreal you are programming the node itself. Node equivalent is Actor. Optionally you can decide to move logic into components that can be attached to actors.

2 Likes

Hello, I have read your description. Although I haven’t used the Godot engine, I can tell you in Unreal Engine (UE) that UObject types do not exist in the physical world, meaning they have no coordinate position, and UObject itself does not have a Tick function. If you are using C++, you can inherit from AInfo, as AGameState and APlayerState both inherit from this class. Actually, if you understand UE’s Gameplay Framework, you will know that GameState is equivalent to a class that manages game states. GameState stores references to multiple players in the PlayerArray variable. If you want to manage the states of multiple players, you can write the logic in GameState. PlayerState generally stores player data information, while PlayerController typically writes logic related to player actions (keyboard input).

In summary, I think you should first get familiar with UE’s Gameplay Framework to better decide where to write your logic.

1 Like

If you want to delve deeper and need to manage something, you can use UE’s SubSystem framework to do it (which requires C++). Of course, you can also write your own Manager to handle it, but if it’s about managing player states, I believe writing it in GameState is the best approach.

1 Like

That is so amazing to hear! Because I was using what is called “GDExtension” in Godot, which basically allows me to use C++ to create my own nodes that would compile and link with engine. Then I could place the nodes I created into the SceneTree.

I guess what I am more confused on is this. In Godot, you would rely very heavily on the SceneTree to get things done. Need to spawn an enemy? Spawn it in the “EnemySpawnPoint” Node3D Node position. Need to have a state machine that manages your Player instance? Make the Player instance a child of the Player_Manager state machine. This hierarchy is the standard, and “proper” way to set up your Scenes (Levels) in Godot.

In UE it seems there is much less attention given to the actual structure of nested Components and Actors in the Outliner. At least it seems that way from what I have gathered so far! So, is there a “proper” or standard way I should be structuring Actors and Components in the Outliner?

In a finished game, the player is not present in the Outliner from the start, instead they would be instanced into the world, right? So, would it be “proper” to just make the Player_Manager exist at all times and have it spawn in the Player instance, but not make it a child, instead just let it sit wherever it is in the Outliner and keep a reference (pointer) to the Player instance for the Player_Manager to use to dereference the instance. Since order and structure in the Outliner is not imperative?

Or would it be better that something like a Level_Manager is what creates the Player instance, and inside of the Player instance is a state machine component called Player_Manager? I would like to know how you would do it!

1 Like

I should have read all the comments first before asking this question! I am looking into Subsystems right now, and this looks EXACTLY like what I was looking for!

1 Like

Amazing answer! Exactly what I was looking for! I was using what is called “GDExtension” in Godot, which basically allows me to use C++ to create my own nodes that would compile and link with engine. Then I could place the nodes I created into the SceneTree. So I was making my own Manager Abstract Class, that all of the individual manager classes would inherit from.

Subsystems were EXACTLY what I was looking for! Thank you so much! I will look into the GameState Class as that is what you believe is the best approach, but Subsystems seem like the key I was missing, and Im excited to get to know them haha!

1 Like

What you describe is fairly common. We have a similar “player state” system in our projects. Going on 5+ projects over a decade so it is fairly battle hardened.

  • the thing that manages the player states is the PlayerController
  • the “PlayerStates” are UObjects and we use a TArray for the state stack / container
  • make sure to UPROPERTY() both your states and their container so you can see them in the Editor details panel
  • we use regular Push() Pop() terminology for the state stack
  • example would be “Walking” state is at the bottom of the stack, the player enters a menu pushing a “Pause” state with some other sub-state info.

AFAIK there isn’t a built-in system in Unreal.

Also: what you are describing as “Scene Tree” in Godot sounds like GetWorld() in Unreal. GetWorld() give you access to spawning things, getting the player controller, getting the HUD, etc. and similar stuff.

2 Likes

In Unreal Engine (UE), the concept of composition is emphasized. For example, if you want an Actor to have interactive logic, you can create an interactive component, add this component to the Actor, and it will gain the ability to interact. If another Actor also needs to interact, simply add the interactive component to it. Components are more like abilities that can be granted or revoked, and they are implemented through component composition.

Suppose you now want to generate enemies at random positions in the scene. You can either write the logic directly in the level blueprint to generate them, or you can create a Monster Manager. You create this Manager at the beginning in the GameMode and save a reference to it. After that, you can use the Monster Manager to generate monsters. There are various ways to implement this, and the design depends on the specific logic. If your only goal is to generate monsters, I don’t think a Manager is necessary. However, if you have more complex logic and need finer control over the generated Monsters, I believe a Manager is essential.

2 Likes

Although UE does not have a state machine system specifically for managing various player states, it does have GameplayTags, which can be used to implement state management. In my understanding, the so-called “states” are essentially transitions between various conditions. When a specific “condition” is met, the state machine pattern can make these transitions clear. However, maintaining a state machine can also be costly.

1 Like

Ah, I see! I like the analogy of components as abilities that can be granted or revoked. However, as someone who prefers coding everything directly rather than using the editor to manipulate properties, I’m curious about the benefits of breaking functionality into granular components versus embedding them directly within the Actor class.

I typically avoid using the editor to drag components onto different NPC Actors or the Player Character. Instead, I leverage polymorphism to determine what functions an NPC gets. For instance:

  • The Ally class and the Enemy class inherit from the NPC super-class.
  • The Bandit class would inherit from the Enemy class.
  • The Guard class would inherit from the Ally class.

This hierarchy properly abstracts away functions specific to a Bandit from those used by a Guard, which inherits from the Ally class. I feel this is a more programmatic way to achieve what adding different components in the editor would do. And this all is modular, it is just that it is not modular from the editors point of view. Is that a bad thing?

I am trying to get a good reading on when I best can forgo making extra components, and instead encapsulate the logic directly within the Actor Class itself.

I love this reply! And I really like your setup! I do have a question though, you say: " * make sure to UPROPERTY() both your states and their container so you can see them in the Editor details panel". But from a programmers perspective, I would never be changing properties from within the editor. For me, is there any benefit to using the UPROPERTY() Macro on the states, other than it being easier for non-programming developers to manipulate them?

I am curious because I want to know how much I am doing for other people working on the game with me, versus for myself, and streamlining the backend.

(Also if you look at the reply above this one, you may get a better sense of why I am asking this question!)

P.S.: I REALLY like the way you put states on a stack! I didn’t think about doing it that way! I did it in a more rudimentary way I feel! Do you mind if I ask you more questions on it? Or would that be breaking your TOS of some sort haha!

1 Like

I can understand your use of inheritance to differentiate functionalities, but consider this example, again using interaction as an illustration. Suppose your characters and NPCs need interaction capabilities. You might extract a layer from Character to write the interaction functionality. For instance, you might create a class called AInteraction that inherits from Character , and you implement this functionality within this class. This means only classes inheriting from AInteraction possess interaction capabilities. However, if later on, a completely different class, inheriting from Actor (which could be any class), also requires interaction capabilities, you would have to rearrange the inheritance relationships, involving numerous changes. But if you place this interaction functionality within a component, you can add it freely to any class. We need to weigh the options based on different functionalities to decide whether to differentiate this functionality through inheritance or through components.

We make our StateStack in the player controller URPROPERTY but ReadOnly. The main reason for wanting to see the state stack is for debugging.

I.E. While running the game in editor, hit Eject, then click on the player controller to see the state stack.

But you are correct nobody should ever touch the state stack except the state machine logic. :sweat_smile:

I don’t mind answering any other questions. :+1:

Ahhh! That makes so much sense! And super good to know that, I would love to implement something like that!

What was your guys’ reasoning for making a StateStack? Is it for the ability to quickly clear the entire stack if needed or something like that? Or just a very seamless way to set it up?

Also, do you by chance have a business email or something I could talk to you on! If you don’t want to share it that’s fine, just thought it’d be a better spot to talk than in here.

The stack is a natural way to represent doing something, doing something else, then going back to what you were previously doing. For example, the bottom of the state stack is Walking. That state can never be popped. The stack would be:

WALKING

Then, supposed the player starts interacting with an HMI screen. The stack would be like:

HMI
WALKING

Then, while interacting with the HMI, suppose the player pulls up the game Pause menu. The stack would be like:

PAUSE MENU
HMI
WALKING

Then, when the Pause menu gets closed, that gets popped off the stack. When the player is done with HMI, that gets popped off the stack. Now they are back to Walking.

There’s a lot more to it, like enter state and exit state events, state specific data, and filtering inputs through states, but that’s the basic idea.

1 Like

Quick follow up question! You said, “We make our StateStack in the player controller…”, do you mean the Class the inherits from the APlayerController Unreal Engine Class, or do you mean the Class that inherits from the APlayerCharacter Unreal Engine Class?

I’m curious to know specifically because everywhere I’ve read, they say to put the state machine in the APlayerCharacter inheriting Class. But it seems to make more sense to put the state machine in the APlayerController inheriting Class since that is what will receive player input, and can dictate what state the player should be in!

This is slightly confusing to me because in Godot, the PlayerController and PlayerCharacter would be combined into just one Actor (Node). So, you would be able to see player input, and move the player all from the same Class.

The player controller manages the state stack. You could package the state stack into its own class or just have it be container in the PlayerController.

As for PlayerController vs Character … the PlayerController is the “will of the player” and a character is controlled by the PlayerController.

In Unreal they are default separate classes which makes sense because, among other things, you could switch control between any number of characters.

1 Like

“the PlayerController is the “will of the player””, I see I see! That makes a lot of sense. But for a game where the PlayerController will not swap out between another PlayerCharacter, would you still advise to keep the two classes separate? I’m looking to make sure that I am not fighting the engine carving out my own path, when I could work with it, doing it its way.

What would you do (or have personally done)?

I did notice in the “Third Person Template”, the PlayerCharacter overrides the ACharacter function: virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;. Effectively making the PlayerCharacter also a PlayerController, right?

1 Like

AFAIK you will always have separate player controller and character classes. Not sure its possible or if you’d really want to merge them.

1 Like