As I mentioned in the previous lecture, developing the A.I. for a crowd of NPCs is far simpler than most
people think. This is because from simple rules, complex behavior can develop
and although we aren't programming the so-called brains of the NPCs, they still appear to move with some
level of intelligence.
In this lecture, we will explore crowds further with a group of animated characters. To follow along, download
the 'StreetSceneStarter' that comes with this lecture. As you'll see when you open up the scene (which
is called Crowd)
there's a group of people in there and they're standing on a plane.
If you go to your Navigation window, you'll find that there's a navmesh that's already being baked in
there.
So we're not after a complex environment at this point,
we're just after something where people can walk around.
Now each character has been downloaded from Mixamo and they've got an animation on them already.
So if you select, for example, this girl here (Girl_3) you'll find that they have an Animator Controller on
them
and I set that controller up for you.
So if you just double-click to open it up and have a look what is in there, you'll find
they have an idle animation, a walking animation and a running animation and these animations are set
up to trigger between each other.
So I've created transitions from Idle to Walking and then back again
and the same for all the other states.
And then for each one, for the transitions, we've got triggers.
So we've got an 'isRunning' trigger, an 'isWalking' trigger and an 'isIdle' trigger
and we'll be controlling these and when they trigger from some code. The characters themselves also have
a navmesh agent attached that you'll find in the Inspector and their speed is set to 2.
So, in this case, they've only got animations that I'm having them walk and to stand idle. There's also a
run as well, so they're forward moving animations.
There's no 'strafe set' set up because this movement isn't particularly complex as far as it's quite
simple
and they're moving in a straight line when they do animate forward
and if you can coordinate the speed of your Nav Mesh Agent with the speed that's in the animation
itself, then it's fairly believable and it's a lot simpler set up for us.
I guess I wanted to show you a different way of doing this as well if you don't want to go to the
effort of the complexity of setting up a 'strafe set', or you don't have the skills to create all of those
different animations.
So the speed is set to 2 for all of them.
Now if we press Play they'll go straight into their Idle animation and they're all synchronized, so
they look like they're a flash mob at the moment!
To begin with, we're going to get them walking towards a goal.
We will determine the goal by placing a cube into the scene.
So go to the Hierarchy and right-click and create a new cube and then we'll just move that somewhere
on the navmesh.
So let's just put it over here.
While we're at it, we'll create another one as well so they can move between locations, so Ctrl-D and
then move another cube back to there.
They'll kind of move between these two goals. I might rename these 'Goal' (so that we know what they
are)
and you can delete the renderers on those as well
if you don't want to see them. I'll also get rid of their collision because we don't want that interfering
with anything.
Now in order to find the goals, we will tag them.
So go over to the Inspector and with the goals selected, in the Tag dropdown, tag
them as goal.
If you don't have 'goal' as a tag, you'll have to add that and then set it to 'goal'.
Now make sure you note the spelling...this is lower-case 'goal', which is what we will reference in our code.
We're now going to add some code to control the movement of the characters. Go to the Assets folder and
in there you'll find an 'AIControl' script that I've included with this starter file. Just open that up and
have a look.
Now it's should be pretty familiar because we've done all these things before.
We're first of all setting up an array of goal locations (which will be those cubes) and then we're also
grabbing hold of the NavMeshAgent that is on our characters.
At that point, in the Start function, we're going to get all of the locations that are in the scene that
have the tag 'goal' and that's why it's important
you've got 'goal' tagged with exactly the same spelling/case as this on those cubes and you can add as many as you
like into the scene.
Then the agent is grabbing hold of its navmesh
and then the agent is having its destination set to a random location in that array.
So we're using a Random.Range on the length of the goalLocations array just to pluck one out and then getting
hold of its position, which will then be the agent's destination.
So save that and we're going to attach that to each of our characters. So select them all and
then drag-and-drop the 'AIControl' script onto them in the Inspector.
Now press Play and you'll be able to see the characters picking a location to go to.
So they're randomly picking their location and moving to it.
What you'll also notice at this point is that they are staying in the idle animation.
So if you want to synchronize your animation with your character's movement or whatever they're doing,
you need to trigger one of those transitions that I showed you before. To do that,
let's go back into the code and we'll need to grab the animator component that's on our character,
just like we had to grab the agent for the navmesh. So...'Animator anim;' then in the Start, you'll
also have to set it up so 'anim = this.GetComponent' with Animator
and then at the start because they're walking straight away, we can trigger. So to do that we go
'anim.SetTrigger("isWalking");' and save that. This here has to be exactly
the same spelling and capitalization as the animator.
...these values here.
So 'is' with a little 'i' and 'W' with a capital. Now if you press Play, you'll find that they go straight
into the walking animation and they'll choose a goal at random to go to and walk over to it and then walk
around it because they're not told to stop walking once they get there.
So, stop playing that. Now if you want another goal, you can just select your goal from the Hierarchy,
Ctrl-D to duplicate it and then you can add another one...
and they're already coded to pick them at random.
So you'll find that they've randomly not picked the new one.
Let's just press Play again.
There we go, some people have now.
What we're going to do is when they get to their random location, we want them to pick another random
location and go to that. Figuring out when you're at a location and then picking another location to go
to is very much the same steps that we took when we were moving the tank around and patrolling between
different waypoints, so it's the same kind of logic.
Open up your code. In the Update,
what we'll do is test whether we've reached the destination (or if we're in a certain distance
of the destination, our goal) and then we'll pick another one.
So, the code, I'll just paste in here and then go through it.
It says 'if the agent remaining distance', so the Nav Mesh Agent has this value called 'Remaining Distance'
which is keeping track of how close the agent is to the destination goal.
Now if the agent becomes < 1 distance away from the goal cube, then it's going to set another
random location
and the setting of the random location (this code here) is exactly the same code that we picked the first
random location with, up here.
So that's all the lines that you need
and if you save that and switch back to Unity and press Play, you'll now find that the agents will get
to a location and then they'll turn around and move somewhere else.
The turning of the actual agent...if we select one of them that's moving, you'll be able to see if we go
to the Scene view that the Nav Mesh Agent code itself does all of the turning for you.
Previously, when we were working with the tank and turning it we would have to perform a slerp and then
push the tank forward.
So this is the navmesh doing all that for us. We just keep the animation in forward walking and it's
going to react really nicely for us, without us doing any extra effort.
Now if you want a larger crowd, then you just have to shift-select all of the characters and just
Ctrl-D to duplicate them and then you might just want to move them away from each other a little
bit,
just like that and then if you press Play, they're still going to behave
in the same way, because they've got the same code...they're on the same navmesh and they have the same
set of goals to select from. With what we've got
(and before we move on to the next lecture) what I want is to set this street scene up so that the people are
moving up and down the sidewalk, like you would find in a city. First of all,
I'm just going to remove this goal (because we don't need that) and I'll grab this goal and put it up one
end of the street
and this goal and put it at the other end. So they're just going to walk up and down this part of the
sidewalk. To prevent them going in here (which is where you might have buildings or something) we can
just simulate those buildings with a cube.
So let's create a cube and I'll bring that over here
and resize it...
and when you've got something that you're happy with, you can select it, go over to the Navigation window
and we want to make this a 'not walkable' area.
So under the Object tab, you can make it a Navigation Static, but in the Navigation Area, you can drop
that down and say that it's 'Not Walkable'.
Then when you go back to Bake, it's going to exclude this, so that when the people start to walk (if we
press Play) then they will be going up and down the sidewalk...
and avoiding this area here.
Some of them actually escaped, we might say, around the edge so you could just grab hold of this cube
and make it a lot wider
so it fills up that entire block and that will dissuade them from taking the shortcut and getting them
all over
here. Of course, if you started all your characters over here then they're not going to go all the way around
there.
So with that resized, if I just go [Bake] again and press Play. There they are, coming back over to that side
and we want them walking up and down here for the next lecture, in which we will add some obstacle avoidance.