In this lecture, you'll follow along as we start to explore Behavior Trees and we'll start with setting
up a very simple Behavior Tree and look at the Sequence node.
Now if you get hold of the starter file that comes with this lecture and open it up, you'll find in
the RobotGuard Scene, this particular scene. We've got a black guard (he will be the artificial intelligence,
the NPC) and we've got a green one which you can drive with the arrow keys.
So as it is, if you press Play, you'll find that you can drive the green robot around.
It's already set up as a NavMesh,
this particular environment and if you hit the spacebar you'll be able to fire. If you hit the collider
that's on the bot itself,
then you'll also notice that the health bar in the Game view (over here) goes down.
It's also programmed to come back up incrementally so that the bot (if it can get away from you) will
be able to heal itself.
Let's have a really quick look at the way this whole project is set up.
The black character is called Droid in the Hierarchy. If you select it, you'll see it has a Sphere Collider
around it
and this is being used to determine when the bullets hit it
and that's the only reason that it's there.
Other than that, the bot is being driven by a NavMesh
and you see I've added a Nav Mesh Agent here. I've also adjusted the Speed as well as the Stopping Distance so I've got the
Stopping Distance as 30 because later on we want the bot to follow us around and we don't want it to
get too close when it does get near the player.
There's also an A.I. script on the bot, which is quite simple at this point and it's already set up with
a spawn point for the bullets, which is going to be sitting here as a little cube attached to it that
I've got here as a turret spawn point and it has the shells which we used in the tank example much
earlier on in this course as well that it can shoot.
It currently won't shoot because we haven't programmed it with any behaviors, so it's just going to sit
there and the health bar will go down when we hit its collider.
So if we have a look at the code that's on there, we'll find all the usual things that we've used
in the past. So we've got a public transform to the player so that the bot knows where the player
is, we've got its spawn point,
we've got its bullet prefab, we've got our Nav Mesh Agent, destinations,
we've got a target that we'll be using a little later for moving the bot around, health, rotation speed,
visible range, shot range
and we've also got this slider, which is our health bar.
So the slider is a UI object that is...back here...
you can see it in the Game view on the screen
and over in the Hierarchy, under the Canvas, you'll find a slider called DroidHealth that has been set
up.
The slider has a value that goes from 0 to 100
and it's this value here (the value right at the bottom) that we set in the code which will make our health
bar go down and up. So just back in that code, if we go down to here there's an UpdateHealth method that
is being called every half-a-second, thanks to an InvokeRepeating sitting up in the Start.
So this is just going to tick over and test if our health has gone down below 100, then it will just
tick it up and repair the bot.
Now the position of that health bar (if you haven't done anything like this before) is in the Update.
It will keep that slider on the screen
(so on the Graphical User Interface) just above where the bot is sitting.
So as the bot moves around, it sticks to it basically
but because the graphical user interface and the bot are in 2 different spaces (one is a 2D plane
and one's a 3D space)
we need to convert the coordinates of the position of the bot itself (which is this part here) into
screen coordinates with a Camera.main.WorldToScreenPoint and then the rest of the code takes
care of making sure that the health bar stays above that bot and you can see that the health bars value
is also set in the Update just here.
Now further down is the code for detecting a bullet hit which is our OnCollisionEnter code, which is
just checking that the bot has been hit by something that is tagged with the name 'bullet'
and then the health is reduced by 10.
So there's really not a lot of code in there because the agent's not doing anything at the moment.
Ok, so that's the A.I. code.
Now the other things to take note of is that the green bot (or our character, the player character) is
driven by a Drive code that's attached to it and we've used that before for just moving an object around with
the arrow keys. Over in the Assets, you'll find a folder called PandaBehavior
and this is the Panda Behavior Trees
plug-in, which you can get from the Asset Store (here it is, here).
There's a free version and there's a paid version with a few extra features but it's nice that we've
got this free version to play around with and that you can see the value of it.
Now while I'm just talking about this, there's a number of assets in the Asset Store for creating
Behavior Trees and they're not free
and they also include Graphical User Interfaces, so they would be a lot more powerful than what we're
going to learn here
because you can use drag-and-drop nodes and create a tree visually for the behavior and then
link that up with the behavior of your particular bots.
However, if we're in here, digging around and actually writing scripting code for the Behavior Tree, it'll give
you a better sense of how things are connected and how the Behavior Trees work.
So this is a really good introduction to Behavior Trees
and then if you want to go ahead and purchase one of those other assets that has the graphical user
interface, then feel free and you'll already understand what Behavior Trees are and then how to
create more complex ones.
Now this is already included and downloaded with the file you would have just opened, so you don't need
to do it again.
Let's start by creating a really simple script that's going to cause the Droid to wander. In programming
the 'wander', if you think back about NavMeshes, the way you would do that is to pick some random destination
on the NavMesh and then get the robot to move towards it.
Now the NavMesh is doing all of that work for us.
The only thing we need to really check is if the bot has finished getting to its destination point and
we can include all of these functionalities into a really simple Behavior Tree.
So first of all, we'll create the Behavior Tree. So under Project, drop down "Create'. Now you won't see
it here because it's off my screen and it's right down at the very bottom when you've got the Panda BT
plug-in in, it'll say 'Panda BT Script'.
So create a new one of those and I will add it into the asset.
Let's call it 'Wander.BT'. It doesn't really matter what you call it, as long as you know what it
is.
So there's your Wander.BT.
Now in this (let's open this up) you're going to get a very simple structure of a very basic tree.
First of all, the top level of the tree that you're going to run has to be called the 'Root' node and you
can see that there
and then underneath, there's a Succeed.
So this is a root node, all by itself.
It's got no children and it's running a success, so it's always going to be true. It's going to
let the tree continue running.
Now, this is called Wander but we'll still call it 'Root' because it is the first node in our tree.
As we work down through the tree, each successive branch and node structure has to be tabbed in one
for it to work.
So if I did that, that would be an error because you can't have 2 root nodes.
So it would look like that, where you've got your initial node and then one branch going straight down
to the Succeed
but we're not going to do this. We're going to get rid of the Succeed and replace it with a 'sequence'.
So these words are words that the Panda BT script compiler knows what they are and it knows that after
we put in a 'sequence' node, that we are going to then give it a series of leaf nodes or we could even
give it a 'sequence' or a 'selector', if you want to go deeper and deeper into the tree.
We're not at this point, so we're going to give it 2 children nodes that will be the actions we want
our bot to take.
So the first one we'll call PickRandomDestination
and the second one we'll call MoveToDestination. The spelling of these has to be perfect
and I mean that in the way that THIS spelling has to match the name of a method that you are now going
to write back in your A.I. file.
If it doesn't, you'll get an error obviously.
So just keep note of how you've spelled both of these 2 things, that you've also tabbed them in.
Right, so that is the end of this Behavior Tree.
So just save that, go back to Unity and we're going to open up the AI script file.
In here is where we'll add 2 methods that correspond to those 2 leaf nodes that we just
added in the Behavior Tree. So down here, we're going to add this.
The first one is called PickRandomDestination, which is spelled exactly the same in the Beahvior Tree here.
Now back in the AI.cs file, we're creating
the PickRandomDestination method and notice that beforehand, it's preceded with this little [Task]
and this is telling the Behavior Tree
(the Panda BT system) to pick this up as a task, which will link it back to the leaf node in your BT file.
It knows that because at the top of the code (if we just go back up here)
we've got our Panda library included.
Right.
So, let's just go back down here.
All we're doing in PickRandomDestination is creating some point on our map that is within a range
of -100 to 100.
If you have a look at the plane that's in the scene, it's actually sitting at 0, 0, 0
and so we're going to stay at 0 in the y-direction but just find a point that's within 100 radius
of the bot itself and then we'll use this point as its destination for the Nav Mesh Agent. At this point, we're
returning a task 'Succeed'.
So you've got to send a succeed message back to the Behavior Tree,
otherwise it won't keep executing its sequence.
Now you can see this down in the next task, which is MoveToDestination
and in this code, I've also included some debug info which is quite useful when you're running a
Behavior Tree, to see where things are working and when they're not working.
So this is saying when the task is being inspected (and that's in the debugger that I'll show you in
a moment for this) then it's going to print (next to this task, in the debugger)
a string, formatted like 't=' and then this here and print out the time and this string format,
you can put anything into here.
So later on when we're turning the bot through certain angles, you could put the angle in here so
that you can easily debug as you're going along, where things might not be working for you.
So that's a nice little feature of this.
Now the other thing we've got under here, which is actually doing all the work in this particular task
is just testing if the agent has made it to its destination.
So we're doing an 'agent.remainingDistance <= agent.stoppingDistance'
and that says I'm at my destination. Now we're also testing that agent.pathPending is false.
If agent.pathPending is true, that means that the Nav Mesh Agent hasn't finished calculating a path
and if you try and run these tasks out of sync with the NavMesh updating itself, then this task
could actually fail, rather than succeed.
So when you set this destination up here, you can't be assured that it has calculated the path and therefore
will start moving to it, before this task down here is run.
So that's why I've got this in here and it will come back and try it again.
So it's always good to have that. If you leave it out, you will find you'll probably get a bit of error in
your NavMesh calculations when you're trying to push this through.
Anyway, if we've reached the destination then we're returning a 'Succeed' to the Behavior Tree which says
that we've finished and that would make both of these things finished, which would make that whole tree
finished.
Right, so now you've got that, save it
and we'll go back into Unity.
We'll go over to the Droid. What you're going to do is add on the Behavior Tree.
So, first of all, go 'Add Component > Panda Behaviour'.
Add that and then it has a 'Count'. This is how many
Behavior Tree scripts you've added on to your bot and you can put more than 1, we're just using 1
at this point.
You'll have a 'BT Script 0' written here. That's where we drag-and-drop our Wander.BT,
so drag that over to there. You will immediately be able to see the little tree that you've written-up
in that file
and as we run it, you'll see these things run and change color.
So this is where the debug happens, over in the Inspector.
So press Play to run this and you'll see that the agent starts to move immediately.
You can see over in the debug that the PickRandomDestination has run and been successful because
it's green
and then after that you see MoveToDestination.
See how it's got a little timer next to it?
That's our debug code showing up, so you know that it's running through doing that. At the moment,
we also have this tree ticked to 'Repeat Root',
so it's going to continue wandering and wandering and wandering
and that's what this agent is doing. It's picking a random destination and then flicking over to move
to the destination.
Now the other thing that's also happening with this Behavior Tree is its Update.
So what happens with all of those nodes is they get processed every update, 1 node at a time (and you
can change this to different types of Updates up here). The way that a Behavior Tree gets updated is called
its 'Tick'. So some Behavior Trees you'll be able to set that by hand and say that you want like a
1 second tick.
In this case, it's linked to the Unity MonoBehaviour so that it will tick over and Update with,
in this case, Update which might be all that you want. We'll leave this exercise here and we'll have a
closer look at Sequences in the next lecture.