Behavior Trees
This video represents my final programming assignment for my advanced AI class. This project demonstrates the implementation of simple behavior tree functionality and gameplay examples. In it, I use a behavior tree to create AI behavior for enemies in a stealth game scenario, in which the player must sneak around the level and hide from the enemies patrolling it. The player gives off noise while moving, and can hold shift to move slower but make little noise. While the gameplay is fairly simple on the surface, the AI behavior does a good job of showing off potential behavior tree functionality.
A behavior tree in games is a type of AI decision-making that allows many simple actions to be strung together into complex behaviors that can perform a wide variety of tasks. The simplest way to show and explain the behavior trees is with a flow chart. This flowchart represents the behavior tree used in my demo.
Behavior trees work by starting at the topmost node, called the base node. From there it proceeds left to right, going to the lowest child node of the branch to the action nodes. From there, it runs each action, returning SUCCESSFUL or FAILURE depending on the outcome of the action. A Sequence node will then return SUCCESSFUL if all children nodes are successful. A Selector node will return SUCCESSFUL if any of the children nodes are successful.
In the above example, Patrol action was executed successfully, which meant the Patrol Selector was successful. Since that was successful, the sequence then ran the next action over, in this case, Scan. Since both children were successful, the Passive Sequence is successful and the Base Sequence will start evaluating the other side of the branch. If this had returned a FAILURE, the Base would have been a failure and started the evaluation over from the beginning.
To contrast, here is an example of what happens when some actions fail. The Patrol Action fails to start, meaning the selector checks the Wander Action, which is successful. Patrol Selector is then successful, so the parent sequence moves on to the Scan Action. It fails, and since both children nodes need to return SUCCESSFUL for the sequence to pass, it fails, and so does the Base Sequence.
This can be best shown off by breaking down the AI behavior in the video. The AI starts by patrolling between waypoints. It will be a failure until it reaches the destination when it passes a SUCCESSFUL, allowing the scan action to be run. The scan spins the AI around in place and only is successful if it spots the player with a raycast. Unless this happens, the AI will run this loop indefinitely.
If the AI spots the player, the entire left side of the tree will automatically be successful, allowing the tree to move to the right side.
The AI will start by investigating. If the player is in direct line of sight, it will return SUCCESSFUL, allowing it to begin chasing and attacking the player. Otherwise, the AI will run the Investigate Action, moving towards the player's last known location, either the last place they were seen or the point where the AI heard their movement. If the player is not found within this time, the Investigate returns FAILURE, allowing the Alarm Action to be taken, where the AI moves to the alarm, activating it, and summoning backup. After that, the code allows for the first half to be run again, and the process starts over.
CONCLUSION
In conclusion, behavior trees can seem overly complex, with lots of small little parts and logic that all add up to make complex behaviors. However, in practice and with time, it's easy to see how these can successfully be used to implement complex AI into games using simpler code. There is no real limit to the number of nodes and branches that can be added, with endless possibilities for behavior combinations. I used them to create a small stealth game demo, but with time and effort, I could add so much more. The biggest issue for me throughout this project was just making the logic work itself out. Mistakingly returning the wrong value for any node will drastically throw off the evaluation of the entire tree. It's important to be careful with the logic and the planning. Flowcharts were my best friend while making this. I can't wait to see what I can use this concept for in the future.
EXAMPLE OF PLAYER SPOTTED
> Patrol Action: Successful
> Patrol Selector: Successful
> Scan: Successful
> Passive Sequence: Successful
> Base: Successful
- Move on to other side
EXAMPLE OF WANDER BEHAVIOR
> Patrol Action: Failure
> Wander Action: Successful
> Patrol Selector: Successful
> Scan: Failure
> Passive Sequence: Failure
> Base: Failure
- Reevaluate from beginning
EXAMPLE OF FAILED ATTACK
> Investigate Action: Successful
> Investigate Selector: Successful
> Chase Action: Successful
> Attack Action: Failure
> Combat Sequence: Failure
> Active Sequence: Failure
> Base Sequence: Failure
- Reevaluate from beginning