RivalTheory Rain AI in Unity
By Joy Horvath
What is Rain?
Rival Theory's Rain is a powerful behavior tree system for designing artificial intelligence systems. The package is incredibly robust--AIs created with Rain can follow patrol routes specified by you, create their own, or just freely wander your levels. You can give them the ability to see and hear (or create any other senses you'd wish them to have), and they can act on what they sense. With enough patience, you can create a deeply complex AI that truly seems to think.
It's important to understand that Rain also has an extremely steep learning curve. It seems the only way to get a good understanding of the system is by simply building. This means that in the beginning you might not understand why you're doing something, but the reasons behind these actions will become clear over time. I'll do my best to explain the what's and why's as we go along.
What is a behavior tree?
A behavior tree is essentially a list of actions that the AI can do based on certain situations that we define. With Rain, the behavior tree runs from a top to bottom format. As the game is played, the AI cycles through the tree, starting at the top, checking to see if any current circumstances meet the parameters that we set up. If so, it will run through all of the actions on that branch of the tree, and then return to cycling, waiting for another parameter to be met.
The nice part about Rain is that if you plan things correctly, very little actual proper programming is required to use the system. To prove this point, we won't be creating a single external script to handle our AI behavior.
Other resources worth checking out:
CodersExpo's series of Rain tutorials Clearest and easiest to follow series of tutorials on Rain.
Rival Theory Official Website You can get the most current plugin here, as well as visit the forums and look at the wiki (warning: It’s super sparse.)
When working with Rain, it helps immensely to have a clear understanding of exactly what you want your AI to be doing before you start building the behaviors. While it certainly isn’t impossible to rework the behaviors as you go, your life will be significantly easier if you know what you’re doing going in.
Also worth noting is that the most successful way to approach building behaviors is from an “inside to out” methodology. In other words, rather than trying to build a bunch of different behaviors all at once, start with one core behavior, and build everything out from there. In other words, if your enemy is going to have five different behaviors (let’s say, wander, patrol, relax, sleep, search), decide which behavior is the “most important”, or at least the one they would naturally want to do the most, and build it out completely. Only after that core behavior is finished should you move out to the next one, and approach it from the standpoint of how all other behaviors relate to the core behavior. There are a lot of benefits to following this methodology, not the least of which being that if something breaks, it’s much easier to identify where the break is occurring. If that doesn’t make sense yet, don’t worry. This overview will follow this method.
In the upcoming tutorial, we’re going to build a simple behavior tree for a ghoul character. His core behaviors will be: Patrol a set path while keeping his eyes open for the player, chasing after the player if they have been sighted, and attacking the player if they are in range. Secondary “automatic” behaviors will include returning to the path if he loses sight of the player.
To help visualize the process we're about to build, I created a simple flowchart that will encompass all of the AI behavior. Notice that the enemy will only be asking three questions of itself: Can I see the player? Is the player in attack range? Did I kill the player?
From these three questions the entire behavior tree will be born.
Getting Rain
Rain is available on the Unity asset store, however I've noticed that the developers are somewhat slow to update the versions there, so I highly recommend picking up the Rain package from the Rival Theory website itself. While you're there, you can also pick up the example project they created, which is actually pretty helpful to look at once you have an idea of how the system works.
Once you've downloaded the package, simply import it like any normal Unity package (right click in your project and go to Import Package => Custom package). Once the import is complete, you'll see a new dropdown option to the right of Window titled RAIN.
Character Setup
Before we get into Rain itself, we need to prep the character that we'll be using for the AI. The character we'll be using for this tutorial is a ghoul created by Bumstrum on the Unity Asset Store. Their full store can be found here.
The first thing we need to do is establish all of the possible actions our AI can perform and set up the associated animations. We can do this easily by referring to our flowchart-- we know the character will be patrolling, presumably at a relaxed pace, so he'll need a walk, if he sees the character he'll have to give chase, so he'll need a run, and if he catches up to the character he's going to attack, so he'll need an attack animation as well. There's plenty of room for extra animations and states here (a reaction when the player is sighted, for example), but again, we're trying to keep this simple so we'll only add one more animation to the list: an idle. While it isn't explicitly stated in our flowchart, the first question that our AI asks--"Can I see the player?"--is a passive thought, and it would look very natural if we had him sit around and think every now and again.
Now that we know what animations we're going to need, let's set up the mecanim system.
If you haven't already, open up the animator window, and then dive into the ghoul file folder in your project. The animations can be found in the objects folder, nested under the ghoul mesh.
The ghoul already has a animator controller set up with idle as the default animation, so all we need to drag in is the run, walk, and one of the attack animations.
In the interest of keeping this tutorial as simplistic as possible, we're going to have all of our transitions occur based on triggers from the Any State node. While there isn't anything inherently wrong with this, it isn't the best use of the mecanim system. Again, once you get a better feel for how Rain works, you can definitely integrate any mecanim system you have into it. One of the nice things about Rain is how easily it works with mecanim, so we've got that going for us, which is nice.
Create four trigger parameters, and name them the following: walk, run, attack, idle. Pay special attention to keep all of the names lowercase and spelled correctly. We're going to have to manually type these in later down the road, so it's important to keep things uniform.
Create a transition from the Any State node to each one of the parameters. For each transition condition, set the corresponding trigger (i.e. the transition to the walk state would have walk as a condition).
The last thing that we want to do is create a transition from attack to idle. We don't need to do anything to this transition, merely set it. The reason for this is that since the attack is a very fast animation, odds are extremely good that it would finish before the AI had the chance to decide what it would do next, meaning that the AI would seem to "freeze in place" for a second or two. By transitioning to our idle animation when the attack is done, it will look like the ghoul is observing the player's reaction for a second, which looks much better.
Here's our completed mecanim setup. Playtest your game and click on each of the triggers in turn to see how the system looks. Pay close attention to the attack and see how it transitions into the idle.
Now that our mecanim system is set, we can prep the ghoul so it will be ready to become an AI. Select the ghoul and go to Rain => Create New => AI.
This will create an object in the ghoul hierarchy called AI.
We only need to do one small thing with our AI for now. Select it, and in the inspector, click on the icon of the running figure. Set the Animator to mecanimAnimator. This will tell Rain that our ghoul has a mecanim system.
You can ignore the animation state dropdown--we'll be calling all of our animation states through the behavior tree itself.
Select the top level of the ghoul and add a capsule collider (Add Component => Physics => Capsule collider). Adjust the collider so it fits the ghoul better.
Also add a rigidbody to the ghoul (Add Component => Phyisics => Rigidbody). This will allow our AI to actually climb the bridge. Without it, he'd just pass right through it! We don't want our AI to accidentally tip over while moving around, so under the Rigidbody constraints, check the boxes for freeze rotations X and Z. This will mean that the character can only rotate around his axis.
Our character is ready to go!
Environment Setup
The last bit of prep we have left to do is to set up the environment so our AI can "see" it while it's traveling. Although our flowchart shows us that the AI will be patrolling a set area, if the player is spotted it will leave that path and navigate on its own through the level in pursuit.
Here's the simple scene I've set up--a simple cube ground plane, a cube wall, and a bridge mesh that I quickly made in Maya and imported in. NOTE: Make sure any mesh you imported in has a collider. Without it, the Navmesh we set up next won't be able to recognize the object.
To map out the environment for the AI, we need to create a Navigation mesh. This will inform the AI as to what can be walked on, and what can't. From the Rain dropdown, go to Create New => Navigation Mesh.
A Navigation Mesh object will be added to your hierarchy. The Navmesh object is a wireframe cube, and will highlight all of the objects around it in a wireframe of the same color.
Scale the Navmesh cube until it fully encapsulates the level. Make sure you also make the cube tall enough to clear the top of the wall and the bridge.
Once you've done this, click on the Generate Navigation Mesh button in the Inspector.
Rain will generate a navmesh for you. Be aware that this mesh may very well be a different color than you see here. Rain allows you to customize colors on many of their objects, and if you don't select one by hand it will be chosen at random. This doesn't actually have any bearing on the game itself, just know as you follow the tutorial that your colors might not be the same as what you see in the pictures.
Rain allows you to freely customize your Navmesh and rebake with new values, so feel free to experiement with the sliders in the Navmesh inspector to see what they do.
Let's take a look at the generated Navmesh. Everywhere that's marked in blue (or whatever color!) is walkable for the AI.
Notice that there's a cut out buffer around the wall. This means that the AI will know it can't walk through the wall itself, but must navigate around it. The AI will only come as close to the wall as where the Navmesh ends, so if you want them to be able to hug the wall more, adjust the Walkable Radius in the inspector:
By knocking the Walkable Radius down to .25, we end up with a much tighter fitting mesh.
Let's take a look at the bridge.
Notice that there's a thin strip of Navmesh that goes underneath it. That's because the apex of the bridge is tall enough for our character to fit under based on the default number in the Navmesh's inspector.
While not ideally named, the Walkable height value defines how tall an object must be in order for the character to pass under it. A better way to think of this value is AI height. However tall the AI is should be what the walkable height value is, unless you want to add some kind of buffer (for example, if your character is two units tall, but you don't want them to go under something unless it's at least three units tall out of fear, then your Walkable Height would be 3).
Let's experiment and see what our Navmesh would look like if our character only needed a height clearance of one unit.
A significantly higher percentage of the bridge would be available for the AI to walk under! I'm going to change it back to two though, since the ghoul really is two units tall…
The other thing to notice about the bridge is the fact that while there is a navigation mesh on the top of it, there's a gap on either side. The reason for this is that the bridge is currently too steep for the character to climb up. We can adjust that with the Max Slope value in the inspector.
By upping the Max Slope to 70 and regenerating the Navmesh, we now have something the AI will be able to climb.
(Side note: This bridge is actually badly designed. People can't really easily climb more than a 60 degree angle, so try to avoid building meshes like I did here!)
The last two values in the Navmesh inspector are step height and cell size.
Step height determines how high the AI will be able to climb (for example, on a set of stairs), and the cell size is how accurate the navmesh is. Generally speaking you won't really have to mess with this last value much unless your environment is extremely complex. The smaller the number, the more accurate the mesh. 0.1 is perfect about 99% of the time.
Building the patrol route
The last step before we get to the heavy lifting is to define the route we want the AI to patrol when it isn't pursuing the character.
From the Rain dropdown, choose Create New => Waypoint Route.
This will add a Waypoint Route object to your hierarchy. In the inspector, click the Add button.
A route marker will be added to your scene. We will be defining our path with several of these markers. Move this first marker to wherever you'd like the AI's patrol to begin, then click the Add button again to create a second marker.
Note that there is a double set of arrows between these points, indicating that the AI will be able to pass between the two in either direction. Place as many markers as you need to create your desired route. Each one of these markers will represent a point where our AI can potentially "stop and think", so place them only where this action would make sense. Don't worry about the distance between the two markers. So long as they're connected, the AI will know how to get between them.
Don't worry about connecting your start and end points. We will be able to have our AI either navigate back to the first point on its own, or just turn around and go back the way it came.
In the inspector, rename the Waypoint route to ghoulRoute.
Building the Behavior Tree: Patrolling
The prep is finally complete and now we can start building our AI's behavors!
Here's where we start implementing that inside to out methodology I mentioned before. We're going to start by building the ghoul's core functionality first, and then add in the other behaviors on top of it. But how do we determine what that core functionality is?
As a reminder, our AI will be continually asking himself three questions as he goes through life in the game. Each one of these questions is a yes or no answer. By looking at our flowchart, we can see that the entire AI is essentially built off of the first question he asks, which is "Can I see the player?". If the answer is yes, then our AI proceeds to ask its next question, and potentially the final question. However, if the answer to the first question is no, then the AI has an action it can do: It can move to the next patrol point. In other words, if all else fails, our AI can patrol. This is the core functionality.
Select the AI node in your ghoul hierarchy, and then click the Open Behavior Editor button in the inspector.
This will open the behavior tree editor.
The first thing we need to do is actually create a new tree. In the upper right hand corner of the editor where it says Behavior Tree, click on the dropdown and choose Create New Behavior Tree. When prompted, name the behavior tree GhoulAI.
This will create the tree. Notice that at the top of the tree is a BT node with the title of our AI. BT stands for behavior tree, and this node is merely a label.
The next node down is the tree's root, or the starting point of our system. It's important to understand that Rain's behavior trees flow down. So…Imagine the tree is in Australia. :D
We're first going to build out our patrol functionality as if it was the only thing our AI will ever do. Once we have it working, we'll add another behavior, and so on, until the entire tree is complete.
[SEQ]: Sequencer Node. This is a decision node. Anything placed as a child of this node will be played in the order in which it appears. For example, if two animations were placed as children of a sequencer node, animation A would play in its entirety, then animation B would play in its entirety. This process can't be readily interrupted. |
Step one: Getting our AI to move.
Right click over the root node and choose Create to reveal the other nodes that we can add to our tree. We want our AI to decide to patrol his route, so go to Decisions => Waypoint Patrol.
[WAY]: Waypoint Patrol Node. A decision node. Based on the information you give this node, it will direct the AI along the points of a waypoint route. NOTE: A move node is needed to actually physically move the AI. This node merely tells the AI where it needs to go. |
With the waypoint patrol node selected, look in the mini-inspector section of the editor. Let's change the name of this node so it reads waypointpatrol: ghoulRoute. It's always good practice to add more info to your names so its quicker to read your behavior tree.
Next, in the Waypoint Route section, type in ghoulRoute, precisely as it is named in your hierarchy.
The loop type will determine how the AI traverses the path. Let's set it to Loop just so we can see the AI navigate on its down back to the first point.
The final thing we need to look at is the Move Target Variable. This is a variable that we are going to create and reference in another node in a moment. This variable will hold the current waypoint node that the AI is heading to. Let's keep this simple and call it moveTarget.
The finalized waypoint patrol node info.
The waypoint patrol node needs a child move node in order to work, so let's add that right away.
Right click over the waypoint patrol node and click Create => Actions => Move.
(=>): Move. An action node. Moves the AI to a target location. Also gives the AI additional information such as how quickly it should move. Necessary for the waypoint patrol node to work, but can be used on its own as well. |
The first thing we need to input is the Move Target. This is the variable that we declared in the Waypoint Patrol Node, so input moveTarget.
Next, type in 2 in Move Speed. We can adjust this later as necessary, but it'll do to get us started.
Select the AI component in our ghoul object. You'll notice that the slot for the Behavior Tree Asset is blank. That means that the behavior tree we just created hasn't been loaded on our character yet.
Click on the circular button to the right of the slot, and click over to the Assets tab. Select your GhoulAI tree.
With the behavior tree loaded, press play to test your game. You should see your AI patrol along your route!
…Of course, he's just patrolling in his idle state! Let's fix this. Right click over the waypoint patrol node and choose Create => Actions => Mecanim => Set parameter.
(=): Set Parameter. Action node. Accesses the mecanim controller attached to the AI and changes the state to whatever you define. Be sure to type the names of the parameters exactly as they appear in mecanim, otherwise they won't work. |
Select the mecparam node and change its name to "Set walk parameter'
In the parameter section, type in walk, precisely as you typed it in the mecanim setup. Set the parameter type to trigger, and in value, type True, making sure to capitalize the T.
Drag the mecanim parameter so it sits above the move node.
What this node does is accesses the mecanim controller on our AI and sets the walk state as soon as the game starts. Press play to test your game again.
Your AI should now be walking while patrolling!
Our patrolling behavior is essentially done, but the AI is continuously moving without a moment's rest. Let's build in the occasional idle to make the AI seem more natural.
Right click over the waypoint node and choose Create => Decisions => Parallel.
[PAR]: Parallel node. A decision node. Will play any children nodes at the same time. |
The parallel node is going to allow us to create a timer that will let our AI wait at each waypoint for a random amount of time, and go into the idle mecanim state for that time. Once the timer is up, the AI will switch back to walking and moving.
Right click over the parallel node and choose Create => Actions => Timer. For testing purposes, set the Seconds section to 1. Once we see that our timer is working, we'll add in the random element.
(Q): Timer. Action node. Sets a countdown as soon as it becomes active. Rain will hold in this state until the countdown is complete. You can type specific seconds to countdown to, or generate random numbers with the random command. In the Seconds textbox, type random(numA, numB), with numA and B being the numbers you want to generate between. Pay special attention to the fact that 'random' is lowercase, and there is no space between it and the opening parenthesis. Unless these two things are followed exactly, the random won't work! |
Right click over the parallel again and choose Create => Actions => Mecanim => Set parameter.
Rename this node to include 'set idle state'.
Set the parameter to idle, the type to Trigger, and the value to True.
Here's our tree so far. To recap how it's going to work: When the game start, our tree will wake up. It knows that since its root is a sequence, it needs to play everything in order from top to bottom. Its first job is to start the AI on the ghoulRoute waypoints. It sets the mecanim controller to the walk state, and moves the AI to the first waypoint. Once it's gotten to the first waypoint, it encounters a parallel node, so it knows it has to play whatever is in this node at the same time for however long whatever is in the node commands. Inside the node it sets a timer to one second, and sets the mecanim controller to idle. Once the one second has passed, it checks to see if there's anything else in the tree. There isn't, so it goes back to the top and starts over!
Playtest your game to watch the AI idle at each waypoint.
Now let's add in the random element. Select your timer, and in the seconds section, type random(0,5). Note that random is lowercase, and there's no space between the word and the parenthesis. This will cause our timer to choose a random time between 0 and 5 seconds to idle at each waypoint. It will be different every time!
With that, our patrol is complete!
Viewing our behavior tree in action
In play mode, it's possible to watch the active states of the behavior tree in real time. Select the ghoul's AI in the hierarchy, and in the inspector section of the Behavior Tree editor, click on the Behavior Tree dropdown and choose Current AI. Now, when you press play you will see a green bar highlighting the current action the AI is taking.
Giving our AI sight
We've handled what our AI does when it can't see the player, but now it's time to address what to do when it can. First, however, we need to give it the ability to actually see!
Select the AI node in the ghoul hierarchy, and in the inspector, click on the eye icon in the Rain section.
In this section we can add senses to our AI. We'll just be sticking to sight for now, but hearing follows these same basic principles!
In the Add Sensor area, click the dropdown and choose Visual Sensor. This will create a visual sensor property section, as well as a large sensor around the AI itself.
This circle is a visual representation of the AI's sensory range. Anything inside the circle it can see, anything outside it can't!
Before we start editing the sensor, we need to reveal a few extra properties in the inspector. Click on the gear in the upper right hand corner of the Rain section, and choose 'Show Advanced Settings'
This will increase the number of properties in the visual sensor settings.
Rename the sensor to eyes. Set the range to however far out you want your AI to see. I'm going to leave it at the default 10 units.
As it stands right now, our AI can see 360° around itself, which is pretty excessive. Adjust the vertical and horizontal angle sliders to give it a more appropriate cone of vision.
I set my horizontal angle to 145 and my vertical angle to 50, which resulted in a cone like this:
As you can probably tell though, the cone of vision starts around the AI's ankles, which for this particular creature, is not where the eyes are. Move the visual sensor up until it's at the appropriate eye level for our AI.
Finally, in the eyes sensor, make sure that the Line of Sight checkbox is ticked. This will prevent the AI from having x-ray vision if there happens to be an obstacle, like the wall, between it and the character.
Asking the first question: Can I see the player?
Up until this point with our behavior tree, we haven't been having our AI ask itself any questions. It's just been mindlessly wandering. Now we're going to have it pose the first question from its flowchart.
Because we're asking a yes or no question, we need a node that can hold both of these answers for us, and direct our AI down the right path. Right click over the root node and choose Create => Decisions => Selector.
[SEL]: Selector. Decision node. Generally used as an if/then or yes/no node. Can be thought of as a question asking node. Two branches of potential behaviors are set as children of the selector, and when it becomes active, it pushes the AI down the path that applies to the situation. |
Drag the selector up until it's directly underneath the root, and edit the name so it includes 'Can we see the player?'
Now that we've posed the question, we need to add the two possible responses as children to our selector. Right click over the selector and choose Create => Decisions => Constraint.
[CON]: Constraint. Decision node. Often associated with the Selector node. These nodes are essentially true/false conditions that are used to test the current state of the world that the AI is in. |
For right now, we're only going to change the title of this constraint to include "Can't see player".
Right click over the selector and create another constraint. Edit this constraint's title to include "Can see player"
We now have the first question posed, and now it's just a matter of sorting everything out. We already have the functionality of what we want to have happen if we can't see the player--the patrolling. Let's drag and drop the waypoint node into the 'can't see the player' constraint.
We're going to be checking against whether or not our AI can see anything with the eye visual sensor that we created. However, we need to have the behavior tree actually use the sensor before we can collect data from it! Right click over the root node and go to Create => Actions => Detect. Drag this node up so its directly underneath the root.
(i): Detect. Action node. Activates the visual sensor you reference and gathers data from it. In order for the detect node to work, you must provide it with what sensor to use, and what aspect it's looking for. Both of these names must be surrounded in quotation marks. For example, "eyes". |
Edit the detect node's name so it includes 'eyes' in the title. Click on the repeat dropdown and choose Forever (we never want our AI to stop looking for the player). Under the sensor, type "eyes", being sure to spell and case the name exactly as how you named the visual sensor, and surrounding it in quotation marks. In the aspect slot, type "player". We'll talk about aspects a little later. In the aspect variable slot, type isSeen. There are no quotes required here.
Now we've arrived at a little bit of a problem. We want our behavior tree to be constantly checking to see if the AI can see our player, but at the same time, we want our selector to be choosing yes or no to our question. Currently our root, which is the parent of both of these nodes, is set to a Sequence node. However, we know that if we want two things to be running at once, we need a parallel node. Fortunately, we can convert nodes!
Right click over the root node and choose Switch To => Parallel. Now our detect and select nodes will run together!
Let's revisit the selector node quickly and make a small change to it. By default, a selector node will run only once. Since we're using this node to answer yes or no to a question that's constantly changing, we want to make it constantly run. Select the selector node, and set the repeat to forever.
Finally, let's revisit the constraints. We created a variable on our detect node called isSeen. If the player becomes visible to our visual sensor, it will be loaded in this variable. By checking the contents of this variable with our constraints, we can determine whether or not the player is visible to the AI.
Select the Can't See Player constraint. In the constraint area, type isSeen == null. What this means is that if there's nothing (null) in the variable, then the player must not be currently visible, and the actions for what the AI should do if the player isn't around should be followed.
Next, select the Can See Player constraint. In its constraint slot, type isSeen != null. The != translates to 'is not equal', therefore, if isSeen does not equal nothing, then that means it equals something, and that something has to be our player.
Test your game. Since the player currently doesn't exist in our level, there's no choice for the AI but to choose the Can't See Player route.
Answering 'Yes' to the first question
In order to answer yes to whether or not the AI can see the player, we actually need a player in our scene. Go to Assets => Import Package => Characters to import Unity's default characters.
Drag the rigidbodyFPSController into the scene (Standard Assets folder, First person Character, prefabs).
Now we're going to talk about that 'aspects' element we touched on briefly before. In order for a Rain sensor to work, we need to give it something to look for. Rather than just explicitly naming that thing, we assign a target, which is referred to as an entity. This entity can be applied to multiple things in the level (for example, in a game where the AI is meant to collect treasure, all treasure items would be marked with the same entity). A sensor can also detect multiple entities--it just needs to have a representative detect node for each entity to look for.
In our case though, we're just looking for the player, so we need to assign an entity to it.
Select the rigidbodyFPScontroller in the hierarchy, and go to Rain => Create New => Entity.
In the inspector, click on the dropdown for Add Aspect, and choose Visual Aspect. What we're doing here is marking our entity as something that should be visible to the AI. We've actually already named this aspect in the behavior tree, so let's just echo the name we created and rename Aspect Name to player.
Notice that objects marked with an Entity have a dot in their center mass:
Move your player so it will be in the line of sight of the AI, and playtest your game. As soon as the AI sees the player, it will stop moving (though still be walking because we haven't told it to stop). If you look in your behavior tree, you'll see that the Can See Player condition is active!
Now we just need to have the AI do something in this state. If we refer to our flowchart, we'll see that if the answer to our first question is yes, the ghoul should chase the player, so let's have him do just that!
We know that we want the AI to move toward the player and enter its mecanim run state, so we're going to have to use a Parallel node to run those two actions at the same time. Right click over the Can See Player constraint and choose Create => Decisions => Parallel.
Right click over the parallel and choose Create => Actions => Move
This time, our move target needs to be set to the player. Fortunately, the aspect variable already has the player, so we'll just direct our move node to that.
In the Move Target slot, type isSeen.
Let's up the move speed since our AI is going to be running. Set it to 4.
Right click over the parallel node again, and go to Create => Actions => Mecanim => Set Parameter.
We're going to change the AI's animation to run.
Rename the parameter to include 'set run state'
In the parameter slot, type run. Set the type to Trigger, and the value to True.
Playtest your game. As soon as the AI sees the player, it will run over to it!
Asking the second question: Can I attack the player?
Now that the AI can see the player, we can have it ask itself whether or not it's in a close enough range to attack. Normally, this is where we would have to script in something that would detect distance between the player and the AI, but instead, we're going to do something a little sneaky.
We're going to create a secondary visual sensor, make it much smaller than the eyes, and repurpose it for a range finder!
Select the AI node in the ghoul's hierarchy, and go back to the sensor section in the inspector (the eye icon).
Click on the dropdown for Add Sensor, and add a new visual sensor. Rename this new sensor to attack, and lower the range to 1.5, which is about the length of reach for the ghoul's arms.
Raise this sensor so it's about at the center mass level of the ghoul.
This is now the ghoul's attack zone. If the AI sees the player and manages to run up to them fast enough to get them in this zone, it's attack time! We're only going to have this sensor active if the AI can see the player, so we don't need to worry about setting the horizontal and vertical angle: If we sneak up behind the ghoul and it hasn't seen us, it won't matter if we're in the attack zone.
We now have the elements needed to ask our second question, which means that it's time for another selector! We're actually going to be very closely repeating the process we went through for setting up our first question, so hopefully some of this starts to look familiar.
Right click over the Can See Player constraint, and choose Create => Decisions => Selector. Drag this node up so it's directly underneath the constraint. Edit the name so it includes 'Can we attack the player?'
We need to add a yes and no path to this selector, so add two constraints as children (Create => Decisions => Constraint). Name one Can attack, and the other Can't attack.
We already know that the AI needs to run at the player if it can't attack yet, so let's drag and drop our parallel node into the can't attack constraint.
Now we want to add in our detector for our attack range. We're going to be essentially copying the setup of the top of the behavior tree in the Can See Player constraint. To that end, we know that we want to run our new detector at the same time as the 'can we attack the player?' selector, so we're going to need a parallel node for this.
Right click over the Can See Player constraint, and choose Create => Decision => Parallel.
Drag the selector into this new parallel node.
Right click over the parallel node and go to Create => Actions => Detect. Drag the new detect node up so it's directly below the parallel.
Rename this detect node to include 'check attack range'.
Set its repeat to Until Success (we don't want this detector constantly running as we discussed before!).
Set the Sensor to "attack", and the aspect to "player".
In the Aspect Variable slot, type attackTarget.
Now that we have the aspect variable set up, let's finish off our attack constraints.
In the Can Attack constraint, type attackTarget != null. Just like in our first constraint set, if there's something loaded in this variable, it means that this constraint is true.
In the Can't Attack constraint, type attackTarget == null. If the target variable isn't holding anything, it means that the player isn't in range!
Playtest your game. You'll see the AI move to the character and then stop when it's within attack range. If you run away, the AI will follow, and if you manage to get out of its visual sensor, it will go back to patrolling!
Answering yes to the second question: Can I attack the player?
We're closing in on the end of our behavior tree! This is actually the last question that we'll be asking directly in the tree itself. While we could control the enemy's attack points and restarting the level from the behavior tree, it's far easier to have that handled in a separate script, and so we won't touch on that in this tutorial. However, it plays out just as it would for any hazard in the game.
If the player is in attack range, we want the AI to switch over to its attack behavior. We know at this point that's simply a mecanim parameter, so right click over the Can Attack constraint, and choose Create => Actions => Mecanim => Set Parameter.
Adjust the name so it includes 'set attack state'. In the parameter slot, type attack, and set the parameter type to trigger. Finally, set the value to True.
Playtest your game. The AI will run over to the character, however as soon as it begins to attack, it will begin to stutter! This is because the attack state is constantly being called. We can alleviate this issue by adding a timer.
Right click over your Can Attack constraint, and choose Create => Actions => Timer.
Set the Seconds slot to 1.
This will give the animation enough time to play through before the behavior tree calls it again.
Playtest your game! The AI should properly attack now. Run around and try to avoid the AI. You'll notice that everything now behaves according to our flowchart, save for the 'yes' of the last question. Again, this is something that would be handled by a separate script.
With that, our behavior tree is finally complete!