Welcome back to the second part on Flocking. What you can see on the screen is the program we left off
with last time.
So our fish are flocking and they're flocking according to some settings we've got on our FlockManager.
The minimum and maximum speeds are
the initial speeds of the fish and they do influence but you can't change them once it's running
and we'll work on that a little bit later,
but as far as the Neighbour Distance goes, you can modify that at runtime.
So if I turn the Neighbour Distance down, we should see that our flock will start to separate because there's
no need to flock anymore
but turn that back up again.
It doesn't bring all the fish necessarily back together,
just the ones within distance of each other and you can see in this example here that initially everybody
was in the same flock, but I released them to move out in their own way
and then I brought them back and said "Oh no, you actually are in a flock, you want to be a distance of
10" and because they'd moved away from each other, they found the fish that were in a distance of 10 and now
you've ended up with 2 little flocks within that.
Now the Rotation Speed will also affect it.
Actually, you just saw a nice emergent behavior
there, where both the flocks joined together because they're not just in a stationary position and if you
look over here on my main camera view of the game, this flock is slowly moving across the screen because
they do have a particular heading, even if they don't really look like it here.
If we slow down the Rotation Speed, we might get a better idea of which way they're trying to travel.
So remember they're trying to go in a particular direction with the entire flock but they're also trying
to stay together, so they're going to be circling around each other whilst they're moving along.
Now this isn't the final product.
This is just to play around with for now and it really does show you the effects of flocking from that
little, tiny bit of code that we wrote with those 3 different averaged vectors in it.
Right, so now that we've got this, let's go back and improve it. In the FlockManager, we'll add a 'goal position'.
So at the top of the FlockManager, let's add in a
'public Vector3 goalPos;' then to get that goalPos just to be somewhere to start with,
down in the Start, we will put it where the FlockManager is.
So in this case it will be:
'goalPos = this.transform.position;'. Right, so that is creating a goal position for our fish to head
towards.
Save that. Now we need to modify the ApplyRules behavior to include that goal position.
So go back to your Flock code and you want to find where you're working out where the center is, inside
of this
'if(groupSize'...so this is inside the ApplyRules and we're going to modify this vector towards the center
of the group. We're going to make that center move towards the goalPos as well.
So to the end of calculating the average of the position, we'll add a vector to the goalpos, so the
Vector2, our goal is the goal position minus the current fish's position.
Save that and let's go back into Unity and run and have a look at what we've got. Now when we press Play,
our fish have a goal position but they're not going to go to that position if they can't turn around, so the Rotation
Speed on the FlockManager needs to be increased and you'll want to set the Neighbour Distance as well because
remember if they're not part of a group, then they're not going to go anywhere except straight ahead.
Now you can see that we've lost some fish up in the distance here because we didn't capture them within
the Neighbor Distance in time and so they don't even consider themselves to have neighbours and they're
just off into the distance and that's fine because that's the kind of emergent behavior that you're after and
you can see I've got the FlockManager selected and you can see it's position if you double-click on it and
in the Scene, it's position is shown just there and you can see them flocking around that actual position.
Now what we want to do is make them flock around it as it moves.
Now if I move it at the moment, they're still going to flock around
goalPos.
We're not updating goalPos to be updated with the center of the FlockManager,
therefore you'll have to update that goalPos in the Update on FlockManager.
So let's quickly do that.
Open up the FlockManager code and we can grab this piece of code that sets the goalPos, copy it and
paste it down into the Update. Just save that and go back into Unity and press Play and make sure (I really
do need to set these rotations and distances to something other than 0 straight away).
Ok, so here's our flock and they're moving around that center position
and if I grab hold of it and move it over here, they start to move over to their goal and
if I move it back here, they'll move back again.
Cool.
Ok.
So let's (first of all, I'm going to set my Neighbour Distance and my Rotation Speed, so I don't keep having to change that
every time I press play)
and let's go and make some more modifications.
First of all let's go into the FlockManager
and what I want to do (instead of setting this goalPos here to the position of the FlockManager, which
you can do)
I wanted to randomly pick a new goal location which is inside of this range that we've set up for our
swimLimits here. So we can do the same thing with goalPos as we have for 'pos'.
So let's just grab this piece of code, copy it and just set it down here to our goalPos.
Now, this is going to update goalPos every Update, which is probably not what you want (get rid of that
semi-colon on the end)
so we can do something like this to make it happen randomly...'if (Random.Range(0, 100)
is < 10
gives us a 10% chance that the next line is going to run and update our goal position.
So save that and let's go back into Unity and press Play.
Now we'll be able to see the goalPos changing and the fish moving around to us.
There you go and you can see that there. We can also do a similar thing in the Flock script, where we're not
applying the rules all the time and we're also at random moments resetting the speed. In Flock.cs,
in the Update, add these 2 lines here and you can play around with the percentage chance of the
Random.Range lines executing and you can set speed here, using the same settings that you've got up in Start
so that you can reset the speed of the fish and then you can also only apply the rules every now and
then.
So this is like every 20% (or applying the rules 20 out of 100 times).
What this also does is to take away a lot of the load from constantly calculating the rules over and
over and over again, for every single fish
because as your flocks get much larger,
it will be just way too much processing them to have them do the rules and they don't need to check
all of the time,
so this does it randomly.
You could, of course, have an InvokeRepeating type method that you include in here, that you could apply
the rules every 1 second or 2 seconds. I like random because it gives you unexpected results.
Ok, so if you add that in (above the Translate) and save, go back into Unity and press Play.
You're going to find that with the FlockManager, you can now increase the maximum speed and speed up
the fish.
You may also need to increase your Neighbour Distance because they might just disappear.
Let's just slow them down.
The other thing that will keep them together into a nice tight-knit group is the Rotation Speed
The faster that they can turn around,
then the more compact the flock will be, as you can see there
and then if you wanted them to lose interest in each other, then you could turn the Neighbour Distance down so
that they then start to form little tiny flocks within the bigger flock but they're all going for the
same direction and we could see before, there's a few. There's one fish over there that's heading off
into the distance, so he has fallen outside of our logic...
and there's another one over there that's off as well and you will lose members of your flock because
at some point the rules just won't apply to them.
If you do end up with game objects that swim off into the distance, you will have to have some way of
deleting them once they've gone. So you might have an OnBecameInvisible on the actual model itself
so that it will automatically destroy itself,
otherwise, you can control them by keeping them within a certain region.
Now, we've already created a region on our flock because we've got that structure for the swim limits.
So this vector here at the top is where we're creating our fish but we could also use it to contain them
and that means that the fish have to leave
the logic of the rules and have a little bit of separate logic which will turn them around if they've
gone too far.
So back in Flock.cs, first of all, at the top we'll create a boolean value and call it 'turning' and set
it to 'false'.
Now we will turn this to 'true'
when the fish reaches the swim limits. Before we start modifying the fish's speed or applying the rules
and moving it around, inside of the Update method we're going to turn the fish around if it has reached
that boundary, so just as the first thing inside of Update, we'll add this code here.
We're going to create a new 'Bounds'. So a 'Bounds' is like a rectangular prism that you specify around a certain
center point.
In this case, it's the myManager transform position
and for a certain size. So it's 'myManager.swimLimits * 2' because our swimLimits are essentially
like a radius type (a half-size value) that we've put in there. This will create a nice big box (although it doesn't
create a big box, it just takes a structure that's holding the size of a box that would be around the manager)
and we can then use it down here in this if-statement, we can test if our fish (which is transform.position
in this case)
if our fish's position is inside of the bounds. This is a really nice method, this 'Bounds.contains'
and if it's NOT contained in there, then start turning,
otherwise, we're not turning.
So we're not in turning mode and we can go back and do our rules. We'll then test (before we do anything
else) if we're turning or not. If we ARE turning, we're going to calculate a new direction to turn toward.
So rather than the ApplyRules (which gives our fish another direction) we'll create another one
and in this case, we're just going to turn from our current position to the center of the cube, so we're
working out the direction to get from where we are (which is on the 'out of bounds') back to the center
and then we're using that direction in another slerp.
So again we're slerping through our rotation to look in that particular direction, using our rotational
speed.
Now if we're NOT turning, then we want to do these other things about applying the rules, so we'll just
put an 'else' in here
and open that up. Put these things about speed and applying the rules inside
there, so that they only occur when we're not turning.
Right, so save that
and let's go back and run it.
All right.
So I'm going to go to my FlockManager and I'm going to turn down the Neighbour Distance, so that the fish
will go and do their own thing.
Let's see if we can get them turning around...ok.
So you can see them there.
They're reaching the outer bounds over here and they're turning around and they'll do it whenever they
reach any of the outer bounds...that fish did and that fish did.
So they stay within
what is like a fish tank
and you can make that as big as you like, knowing that your fish are going to stay put and you're not
going to lose any.
Within that environment, you can also have little tiny flocks and so let's increase our Neighbour Distance
and our Rotation Speed and our Max Speed
and so here's a bit of a flock going on but there's other fish who've swum off over here and they'll
hit the edge of the tank and then turn around and come back to the center. While they're on their way
back to the center of the
FlockManager, they may encounter other fish within the correct Neighbour Distance and so they'll start automatically
flocking with them.
Now this works really nicely until you put obstacles inside of your tank,
so in the next lecture, we'll have a look at how to deal with that.