A practical guide to understanding and working with StateTree as it relates to AI. It covers key concepts, terminology, and execution flow for StateTree. This is accomplished while building a basic wildlife AI agent using the new StateTreeAIComponent.
https://dev.epicgames.com/community/learning/tutorials/lwnR/unreal-engine-your-first-60-minutes-with-statetree
HiďźI found this project on github to study-(GitHub - Ji-Rath/MassAITesting: A project primarily used to test UE5 Mass AI system). I have a lot of problems.I refactored it with version 5.4. Massbehavior Statetree always only the EnterState,Will not run tick. Even if I return to the running State.Its LastTick state will still change to success or failed after enterstate,Could not get LastTick State to running state. how can i do
This is really great seeing a guide on this stuff. I spent a couple weeks digging through the source and doing experiments and wrote a guide for myself. Iâd like to add to or clarify some points from the guide.
Under StateTree Execution Flow / StateTree State Selection
- When changing states, the tasks and states are exited in order from leaf to root of the previous state, and the enter state events happen from root to leaf.
From my experience this should be:
When changing states, the tasks and states are exited in order from the leaf of the current state branch until the common ancestor of the next stateâs branch, and from the common ancestor states are entered through the next branch to reach the next state.
So if youâre current state is Root.Colors.Green and you go to Root.Colors.Red, only Green is exited before entering Red.
Also to clarify the point on StateTree Transition Selection. I like to think that Tasks can Finish or not Finish, and Tasks finishing trigger a Stateâs Completion (Succeed or Failed).
When a State enters a Completed state, it triggers a check on the Transitions.
If a State has no Transitions it will jump back up the StateTree passing on the Completed status to the ancestors. This could go all the way back up to the Root State which will force reentry of the whole StateTree! In other words, if you Complete a State without Transitions, youâll loop over the StateTree re-entering States which may not be what you intended! To interrupt this, you can add a Transition to the Parent of a Child State like On State Completed
transition to the Parent State.
Edit: Another option to prevent re-entry is, in your tasks, set bShouldStateChangeOnReselect to false. In Blueprints, under Class Defaults itâs by default true which is useful for restarting a sequence of animations, but if you want to avoid re-entry, you want this false. In C++ youâd subclass StateTreeTaskBlueprintBase and set bShouldStateChangeOnReselect to false, and create your BP Tasks from it.
Also it needs to be mentioned that every State on the active branch gets ticked every frame to run Tasks and check for Transitions.
Great guide! Thanks for posting it!
I found an issue in the code for the PossessedBy
function, in the section titled Character Setup. If the user doesnât call
Super::PossessedBy(NewController);
it will break the possession functionality from ACharacter
and APawn
. And that lineâs missing from the function example in the tutorial.
It might take hours for new users to realize whatâs the issue or have them give up on the tutorial or Unreal altogether.
Cheers!
Let me guess⌠STCharacter is whatever my character base C++ class that was automatically created when the project was created using 3rd person template (C++). And STPlayerController I have to create based on APlayerController.
Regarding:
Adding and Implementing the Team Agent Interface
I feel there is something missing here trying to do this in UE 5.4.2
I canât get it to work.
It never assigns the player as an enemy.
? Assuming it somehow requires assigning STPlayerController as the default player controller, but project settings are greyed out.
So I make a bunch of blueprints based on these classes in order to assign them in (new BP) of a game mode. And it still doesnât work.
I assumed TeamId of 2 was somehow supposed to make an enemy of our player, but it doesnât.
The AIPerception component only seems to notice the player when all the affilitations are ticked, but it is still not an enemy, still doesnât flee.
My first encounter with:
IGenericTeamAgentInterface
Which seems to be something arcane, judging by the ancient and unclear topics about it.
So State Tree is supposed to be an alternative to Behaviour Trees.
And it should be, but this is not straight forward at all.
Yeah, the C++ part of that tutorial seems to assume youâll only try to do it if you are already very familiar with Unreal. It doesnât even say you need your Blueprints and GameMode setup to spawn the new types of PlayerController and Character.
On code, besides overriding the functions as described in the tutorial:
ASTCharacter
should haveACharacter
as base class.- Make sure
PosssessedBy
callsSuper::PossessedBy
like I mentioned. ASTPlayerController
should haveAPlayerController
as base class.
On Blueprint:
- Setup
BP_ThirdPersonGameMode
to useSTPlayerController
as thePlayer Controller Class
. - Reparent
BP_ThirdPersonCharacter
to theSTCharacter
class by going to the BPClass Settings
and changing theParent Class
in the details panel.
Now, when you play:
- The PlayerController for you, the human player, will assign itself the team ID
2
, because ofSTPlayerController
âs construction code. - The Character, when possessed by the PlayerController, will execute the
STCharacter
âs version ofPossessedBy
and copy the PlayerControllerâs ID for itself, so itâll be2
as well. - The AI and enemy character will have the default ID of
255
. That will make them enemies because the default attitude solver for theFGenericTeamId
deems different IDs asETeamAttitude::Enemy
. That default solver is theDefaultTeamAttitudeSolver
method inAIInterfaces.cpp
.
OnTargetPerceptionInfoUpdated
It only detects the player as a friendly (when affiliation Friendly is checked)
Sending the âDangerâ State Tree Event, on the Limb state âDangerâ the children are never selected - not even a dummy delay and debug test task.
The tease about EQS is less exciting when this does not work.
Maybe it would work if I simply duplicated the character instead as there may be a problem with this TeamId. Itâs certainly confusing enough with this short cut version of a tutorial. But none of this seems easily exposed - like set the playerâs team or even see the variable, or the AI Perception Componentâs âGet Perceived Hostile Actorsâ array and how to use that other than it only ever returning a blank.
State Tree is constantly running the condition check, which does not seem sensible to have this limb activated at all times.
I can get it to the FLEE state by transitioning to flee from PEACEFUL, but it never enters WATCH from the assess state.
Probably because the âGet Perceived Hostile Actorsâ array is never set to anything other than None - if we set this soemwhere I missed it even after several re readings.
I have a project with Limb states that actually work, but it does not involve the AIPerception Component.
Which I now trust as much as I trust the UPawnSensing Component.
Have you debugged the custom functions in C++ for the custom ST classes? I figured what I was doing wrong when my PossessedBy
breakpoint was not hitting. Also check if the custom PlayerController GetGenericTeamId
is hit and returns the expected value of 2.
Perhaps even add a breakpoint to DefaultTeamAttitudeSolver
, to see whatâs going on when it compares the two teams.
The tutorial is not focused on the C++ part, so itâs lacking a lot there. Itâs definitely intended for those familiar with the engine and C++, so either leave it for later or debug it as much as you can until you figure out whatâs missing. Donât lose hope. Mineâs working, so the feature does work. Itâs just not Blueprint friendly.
I WISH I had only spent an hour on this particualr tutorial/feature.
DefaultTeamAttitudeSolver
this is buried in the engine, why should I be poking around hereâŚ
Not focused on C++ and not blueprint friendly. Kind of stretching the definitions of tutorial and features.
Echoing @PsychotropicDog, @RVillani sentiment regarding the C++ part, Blueprints, the familiarity with the engine and the time Iâve spent so far in the tutorial. It should be updated to make it very clear what the expectations are.
This was fantastic!
I liked that it was practical.
I liked that you assumed some basic knowledge of UE and didnât over explain beginner concepts or hand hold through the simple bits.
I like that all but one task that we created is reusable and can work with any AI controller and pawn, and it was easy to refactor that one into working with any AI Controller.
I liked the little snippets such as EQS is coming in 5.5, and thatâs why weâre not using it.
I liked the pattern of âweâre going add this functionalityâ then we add it, then we test it. I believe itâs important to test as frequently as possible, especially when learning.
I liked the follow up of adding a predator AI challenge.
I liked how we rarely went off track. At one point you said we could have a grazing animation, but we just put in a delay grey box. However, going a little off track is important, bc nothing exist in a vacuum. I think adding ai perception and the Team interface are good examples of this correctly.
I also have some feedback if you want it.
I wished there was some discussing of your thought process when designing a ST. An example being in the Introduction to AI with Blueprints
course thereâs some talk about the Sense->Think->Act mental model of AI.
I wished there were some use cases, or rather problems to solve due to tasks on a state running in parallel.
Perhaps a few tips and tricks or gotchas at the end
It tool me a little longer than 60 min, but Iâm not complaining.
Overall, thanks my man! Iâve bookmarked your other guides for when I need them.