Hello again.
Where I last left off in the previous video,
I implemented the steering behavior "seek."
This little triangle is seeking this red circle.
And I am on a quest.
I would like to implement every single one of these behaviors
that Craig Reynolds outlines in the 1999 paper "Steering
Behaviors for Autonomous Characters."
So I haven't gotten very far.
I've just done seek.
I don't know that this round of videos
that I'm making in this year or this moment
right now, 2021, if I will get to all these.
I'm going to get to a bunch.
But hopefully sometime in the future
when you're watching this, you will write a comment
saying, "Congratulations!
You finally have a video on every single one of these."
For now, all I have is seek.
Good news-- in this video, I'm going
to knock out "flee," "pursue," "evade," and "arrival"
all at once.
Let's make a list.
As a reminder, the seek behavior is
defined as "steer towards the target at maximum speed."
This is the desired velocity, and the length of that velocity
is max speed.
We're going to be done with flee in about 30 seconds.
You start the clock!
"Flee" is defined as "steer away from the target
at maximum speed."
So this would be the desired velocity for flee.
Going back to the code, it's as easy as finding
the seek function, looking for the force,
and multiplying it by negative 1.
If I hit Run, there it goes.
It's going to flee that target.
And I think that I did this in the 30 seconds allotted.
But I actually want to pause and take a little bit of a moment
to breathe here.
Because really I have a goal.
I don't want to build examples that only do one thing.
I eventually want to be able to mix and match
all of these different behaviors within one sketch,
but I'm getting ahead of myself.
Let's live where we are for the moment, in the present,
with this example.
And how could I take this force-multiply-negative-1,
write a function called "flee," and then not have to copy-paste
all this code into there.
So there's any number of clever ways
I could do this with different arguments and overloading,
but I think it would be advisable for me
to actually, in these steering functions,
never directly call applyForce.
The goal of a steering function should
be to return the steering force, and then whatever
is calling that steering function can figure out
whether or not to apply it or not.
So I want it to look like this.
Call the function seek, get a vector back, apply that force.
So remove applyForce here and replace it with "return force."
Let's make sure this is the same.
It is.
Now, guess what?
Fleeing a target is what?
Return the result of seeking the target
multiplied by negative 1.
And I'm just going to rename this to "steering"
here so it's more generic.
And there we go.
Fleeing the target makes use of the seek function
and just adjusts the direction of the vector
in the opposite direction.
We're moving along here.
Flee is done.
Next up, pursuit.
The key difference between seeking a target
and pursuing a target really has nothing
to do with the steering behavior itself
and more has to do with what is the target doing.
Pursuit refers to seeking a moving target.
So now I'm going to draw this as a triangle as well.
I could give it a different color.
Does that help?
And the target also has a velocity.
Now on the one hand, I could say, hey, this vehicle,
it wants to reach this target.
Even though it's moving, just go in the direction of the target.
This desired velocity would work fairly well.
But the idea of an autonomous agent
is having this limited perception in the environment.
So maybe this target has been kind of moving along this path.
This vehicle is-- it has this intelligence to it.
It's able to perceive the way the target is
moving kind of out of the corner of its eye, you can think of.
And it understands that in a few moments,
it's actually going to be over here.
So its perception in the environment
involves making a prediction about the future location
of this moving target, so that its desired velocity
should then be--
move at maximum speed towards its predicted future target.
And it will recalibrate that future target every frame.
So if this vehicle were to suddenly turn and go over here,
a couple frames later, it's going
to be looking at its future target as being here.
Its future target might also be further away or closer based
on how fast the vehicle is moving.
In order to demonstrate this, what I'd like to do
is make both the vehicle and the target vehicles.
I'm going to call one the "pursuer,"
the other the "target," and make them both vehicles.
Now the vehicle should be seeking the target's position.
And that's without this new pursuit algorithm.
And I've got to change that to "pursuer."
I'd like to make these vehicles a little bit more
visually distinctive, which one is the pursuer, which
one is the target.
So I'm going to go back to my inheritance lesson
from chapter 4, and just override the show function,
and make it a simple circle, and also give it a color,
and change this from a vehicle to a target.
So interestingly enough, if I'm going
to write a class that extends another class,
I've got to put this one after it.
Great.
Now we just need to put this target into motion.
So I can hard code in a velocity,
and make sure that I call "update" on the target.
And now, there we go!
That target's in motion.
I have this "edges" function from before that I
can also just call, just to have the target wrap around--
wrap the edges.
So the pursuer is not wrapping around,
and actually you get this sort of fun behavior
because the target keeps disappearing and reappearing
somewhere else.
And it kind of just can't catch it.
So, you know, I could probably let the steering force
be larger, let the maximum speed be higher,
and get it to catch the target.
But let's just see now what happens
if I add this idea of pursuing its future predicted location.
So I'm going to add a function called "pursue," give it
the argument "target," and then-- hmm, I've
just realized something.
I don't want to give it a vector.
The position of what I need to pursue
is not enough information.
I need to look at this whole vehicle,
know where its position is and its velocity,
to predict its future location.
So this should actually be another vehicle.
And the target is the vehicle's position.
Make a copy of it.
Then add to it the vehicle's velocity.
Now this isn't everything, because I'm just
adding its velocity.
So I'm just looking at where it will be the next frame.
And I probably want to look like 10 frames ahead
or 20 frames ahead, but let's just see what this gets us.
So now I'm going to call pursue that target,
and it looks kind of the same.
Let's draw some debugging information
so I can see where that target is.
And then let's look a certain number of frames ahead.
How about 10.
So now what it's actually seeking
is that position in front of that target vehicle itself.
Oh, I've actually made a terrible mistake here.
I was about to explain how I didn't make the mistake,
and I made the mistake.
I was assuming I was OK because I copied the vehicle's position
before I started messing with it,
but I didn't copy the vehicle's velocity.
And it's not actually causing a problem
because I've got a limit on the vehicle's velocity.
So I'm multiplying it by 10 and then it ends up getting limit--
but this is bad.
And so to be safe, let me just have a separate variable called
"velocity," which is a copy of the vehicle's velocity.
I can then multiply that by 10, and I can chain those to have
that at ".copy.mult", but-- and then I can say "target.add"
that velocity.
And I'm going to call this "prediction."
Just to-- it's no longer really a velocity.
It's helping us with our prediction
about its future location.
And this should look the same, but I'm now less prone to error
here.
Now, I've got pursue done.
Let me quickly add evade, which is exactly
the same as pursuit but just in the opposite direction.
So now I call the pursue function, multiply the result
by negative 1, and then return that.
I can change this to "evade" and run it.
Oh.
Oh, I made a spelling error.
"Pursuit."
Oh my God!
How do you spell "pursuit"?
It's with a "u."
There we go.
Now, the vehicle is just going to leave and never come back.
I could add-- let's see--
just out of curiosity, let's add the edges to the pursuer.
I also am going to take out the sort of debugging the circle.
And now we can see this triangle is always
going to try to evade that other moving circle.
I'm actually kind of curious, and maybe I'm
going off on too many tangents here, but what
if I add a second vehicle target and have it pursue one
and evade the other.
So two targets-- call evade on one, pursue on the other.
Apply both of those forces.
I don't know.
Let's see what happens.
Which one is it pursuing?
Which one is it evading?
I don't know!
And of course, I should probably be
thinking about using an array and designing things
that it wants to pursue versus things
it wants to evade in a more intentional way,
but hopefully you're seeing the beginning steps
of how you might start to take multiple steering behaviors
and apply them into one sketch.
Putting this back to just a single pursuit
vehicle and one target.
Getting rid of the idea of edges.
I think another effective demonstration here
would be, when the pursuer reaches the target,
the target disappears and reappears
in a new location with a new velocity.
So I can look at the distance between the pursuer's position
and the target's position.
If that distance is less than the sum of their radii,
then recreate the target at a random location.
Let's give ourselves more space to work with.
Let's also let the pursuer have a higher top speed.
And I'll also set the pursuer back
to the center of the canvas.
Let me add the edges to the target.
And finally, let me also give the target a random velocity.
And this is a nice demonstration of a moving
target and a vehicle pursuing that target.
This would probably be a much more compelling demonstration
if the target itself had its own rules for motion
beyond just a constant velocity.
Maybe it bounces off the edges, maybe it's its own--
has its own set of steering behaviors
that governs how it moves around the window.
I'm going to look at a behavior called
"wander" in a future video.
What if it were wandering and then this thing
was pursuing it?
So many possibilities there.
I'd also be curious to see what kinds of ways
can you annotate this to make all
the parameters of the system more clear,
beyond just drawing like one green dot ahead of it
where it's actually seeking.
And in fact, how far ahead you look
could be a parameter that you tune up and down.
So many possibilities!
I'm going to stop here.
You know, I have now successfully gone
through seek, flee, pursue, and evade.
And I really was going to do arrive in this video,
but I think it actually makes sense
to pause here, let you play around
with that particular example, try your own version of it.
And I will come back-- this time I really will--
come back in the next video and look
at what it means for a vehicle to seek a target
and slow down as it's getting closer.
The arrival behavior.
[THEME MUSIC]