…or simple stupid AI…
So I’ve noticed that my semi-instructional posts seem to get the best response on here so I figured I’d keep up that trend for a bit at least. I got some positive feedback regarding the AI that controls the monster in MMN, which is great, but feels a little out of place because the logic driving the monster really could not be much more simple. I figured I’d show you the brains behind the monster, so this week I’d like to talk to you a little about….
If you’re familiar with trying to code character AI without a behavior tree you are likely to have had the following problems:
- It gets really messy really quickly
- It constantly needs to be re-factored
- It constantly needs to be balanced and dialed in
Behavior trees help solve these issues by separating your code into a main data structure called the black board and executable snippets of code called behavior tree tasks, whose execution sequence is driven by the data. I’ll go more advanced on this issue in a later post. For now we’ll leave this relatively simple. I think the best way to show this is by example, so lets look at the behavior tree for the monster in MMN.
Note: To create any AI blueprints you now have to click the Add New button and then scroll with the mouse wheel to get down to Artificial Intelligence. It took me way to long to find that…
So here’s the entire behavior tree for the monster. Trees are read from top to bottom with sibling nodes being read from left to right. A tree is made up of primarily two different types of nodes: composites and tasks.
Composite nodes direct the path of execution while task nodes execute a small section of code. Let’s go over the Composite nodes first. I’m only using two types in this example, the Selector node and the Sequence node. The selector picks the first valid child node and executes that one. The sequence node however executes every one of its valid child nodes from left to right (when in doubt about the order Unreal will execute, check the top right corner. It numbers them for you).
This tree is split into two main branches. On the left is the branch for if the monster has detected the player, and on the right is the idle wander tree. To switch between the two trees I’m using a blackboard based condition.
The blackboard based condition is a simple decorator that can be added to any node by right it and selecting add decorator. You’ll notice in the top right of the previous screen that in order for his node to be valid the blackboard value for “Alerted” to be set.
Note: For the case of a bool value, it’s either “set” or “not set”. It pretty much just translates to true or false.
Once the requirements are set for this node to be true, it then executes its child nodes from left to right.
The move to node is right out of the box Unreal engine. If you are curious about it you should read up on the character movement component in Unreal. The custom blueprint tasks used here are very simple.
The first just updates the character’s walk speed
And the second just calls a “Die” method on the player character.
The “Wander Branch” is a little more complex but not much.
As you can see it’s using many of the same nodes. It slows the character down first, because there’s a chance that the monster is still sped up after having been alerted. After that it picks a random destination, moves to it and then rests for 2-3 seconds. The only new node here is set random destination, which is can be seen below.
After that the only thing left is the code to alert the monster. Because that’s external stimuli I call it from the player character class. I set up the monster with a pawn sensing component that throws an event if the player character walks into his line of sight.
The event fires the code bellow.
So there it is, the majority of the AI logic for the monster from MMN. There’s definitely a few areas I could clean up and a lot more I’d eventually like the monster to do but for right now the stupid simple approach works for me. If you have any questions feel free to leave them below and I’ll try to answer them. Hope this helps!