Hello, dear Unity Developers and dear Community!
I have read several topics related to State Machine in the Bahvior Graph and noticed that the current possible implementation of the State Machine in the Bahvior Graph is limited.
First of all, I understand that in Behavior Trees it’s better to stick to the Tree model instead of State Machine because when it’s more than 5 states, the transitions between state if difficult to handle. But in my project I use combined approach: I use Trees as decision makers of what state should be enabled right now and at the same time I use State Machine for better visual representation.
Also, I use Subgraphs for each state to hide its complexity and reuse the states for other enemies.
Here is how my state machine looks like:
It works well, but it has a huge limitation: it’s possible to simulate OnStart for each state, but it’s impossible to simulate OnExit for them without increasing the complexity of the graph.
Let’s imagine that I have a Player Detector that detects players around the enemy. It’s a performance-consuming operation and I enable it only when the enemy is in Patrol state.
So, as soon as I entered the Patrolling Subgraph, I enable that detector. But when I exit the Patrol state, I need to disable the detector somehow.
As you know, there is an OnStart event in each Graph, but there is no OnEnd/OnExit event.
As a result, I have to disable the detector somewhere else. For instance, I can disable it in each state at the start, but that’s not right because other states must not know about the Player Detector at all (if we follow good architecture and code design).
Except for the bad architecture, we’ll have a complexity issue: every time we need to enable/disable something for states, we must duplicate it in other states which increases complexity of the Graph.
And it’s not only about the detector. The detector is just an example. We can also enable/disable bool parameters of the Animator (e.g. IsPatrolling should be enabled in the Patrol state and disabled when not in the Patrol state).
So, this is why OnEnd/OnExit built-in node would be a cool thing. Is it possible to implement such a node from Unity’s side? I think yes, because they have such thing as Interruptions. If a branch is interrupted, code of Unity developers calls the OnEnd() method in actions that are updating right now. But I’m not sure about the nodes that do not update at runtime: there is a chance that the OnEnd node will not be called if a branch was not interrupted and was just switched. Anyway, I hope Unity devs in this discussion will tell me if it’s possible.
What workarounds I found so far:
- Duplicating of the enable/disable actions in other states (the approach that we discussed above). It’s a bad decision - it violates architecture/design and increases complexity.
- Split each Subgraph state into OnEnter and OnExit Subgraphs (e.g. Subgraph_Idle_OnEnter, Subgraph_Idle_OnExit), compare CurrentState with PreviousState, and duplicate the Switch on the picture above so that we call OnExit for the PreviousState when CurrentState is changed and then OnEnter for the CurrentState. It’s a bad decision - it increases complexity.
- Create OnExit Event and wait for the event to be triggered in each Subgraph. This sounds like a solution, but unfortunately, it increases complexity outside of the Bahvior Graphs. The events that developers provide us are global events based on ScriptableObjects. A long time ago on the Unity YouTube channel developers proposed us EDA architecture using ScriptableObjects. So, the same approach is used here in Behavior Graphs. If you know what is this, you already noticed the problem: the ScriptableObject events should be duplicated for each case in order to avoid collisions between different kind of enemies and even different instances of enemies. But creating different events for different creatures is time-consuming and can confuse other developers. I would like to re-use the same Behavior Tree for different enemies and do not want to create 100+ events.
Dear Unity Developers and dear Community, could you please help me with my problem? I don’t know how to make the OnExit for the State Machine and not increase the complexity of the Graph at the same time.
What approach would you use if you were me?
Platform: Windows 10
Behavior Version: 1.0.7
Unity Version: 6000.0.25f1
Thank you very much for your time!