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?

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.

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.

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.