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.