Welcome back.
Now we have patrolling, but we want our enemies to wait for a few seconds before they start walking
to the next patrol point.
And this is going to involve timers.
So let's first see how timers work before we start to implement this.
In order to have a timer, we need a timer handle.
This is just a struct that the world timer manager uses to keep track of various timers that we set.
So we'll see what the world timer manager is in a second.
Let's create a timer handle.
I'm going to stick one right here in the private section under navigation at the bottom.
So this is going to be a variable of type F timer handle.
And we're going to call this patrol timer.
Now, in order to have a timer do something, we need a callback function.
When we set a timer, we specify the timer handle.
This lets the world timer manager keep track of that timer.
Think of this as, like a little alarm clock with a function attached.
And that function is going to be the function that we create.
It's going to be a void function.
And we're going to call this patrol timer finished.
So whenever the patrol timer has finished, when that time has elapsed, this will be our callback that
will be executed.
So let's go ahead and create a definition for patrol time or finished.
And all that I'd like to do here is move to our patrol target.
Now, that's something that we're doing in various areas here.
One of the places we're doing it in is in begin play.
So we could copy all this code and paste it right here.
But since we're doing this in multiple areas, we might as well just refactor this into its own function.
I'd like an easy to use single function that will allow us to do all this stuff and we can possibly
pass in a target to move to.
So let's do that.
Let's make a little function.
We'll stick it right here in the protected section, just under in target range.
And this will be a void function.
And we're going to call this move to Target.
And this can take an actor called Target.
So now we can simply pass in a target and move to Target will handle the rest.
So I'm going to go ahead and create a definition for this.
And we can basically do what we're doing and begin play.
So we're going to go up to begin play and take these lines of code here, including the if check.
I'm going to copy them and paste them down in our move to target function.
So what are we doing in here?
We're creating a move request setting the goal actor to the patrol target and an acceptance radius.
Now, the patrol target is not something that we're going to hard code.
We're going to use Target that we're going to pass in to this function.
So to make this a little bit more compact without having an if statement, I'm going to place my iff
check up here and say if enemy controller.
Is equal to a null pointer, or if target is equal to a null pointer, then I'll return.
So all on one line, we have our check and we don't need this if statement.
So I'm going to copy the interior of the if statement.
Highlight the whole if statement and delete it and paste those contents.
So after we create a move request, we're setting the goal actor We're going to set that to target now
and we can set the acceptance radius.
We'll keep that at 15, but we don't need the NAV path because that was what we used to draw the navigation
points.
In fact, we don't need the array of path points and we don't need this for loop so we can cut all of
those out and we don't even need to pass in a NAV path to move to.
That's an optional parameter.
So now move to target is nice and compact and we can simply call this instead of doing all the things
we did and begin play.
So back up to begin play, we still want our enemy controller set, but everything after this can be
replaced with our newly refactored function Move to Target and we can simply pass in patrol Target.
And we don't even need to check that pointer because move to target checks it for us.
So now begin play looks more manageable.
Now we refactor this function and our timer callback, which is called patrol timer finished, is simply
going to call that function.
We're going to call move to target.
Passing in patrol target.
So once we set our timer, when the time has elapsed, this is the callback and it will simply call
move to target.
So we need to actually set that timer.
Well, let's test this out by first going back up to begin play.
And let's see how this timer works.
So rather than calling move to Target, I still want to do this, but I'm going to comment it out for
now and I'm going to set the timer.
So in order to set the timer, we need access to the world timer Manager.
This is a class that keeps track of all the timers in the world and runs their time and calls their
callbacks when their time has elapsed so we can get the world timer manager with get world timer manager.
And this returns the f timer manager type, which is a struct.
It's not a pointer, so we can access functions on it with the dot operator and look at the top option
I see here.
Set timer and set timer has a number of function overloads.
We want to use a specific one that takes the f timer handle as the first input, and that's going to
be our patrol timer.
And the overload that I like to use is one that takes a user object.
Next, that's going to be the object on which our callback exists and our next parameter is going to
be the callback itself, which is the address of the a enemy function.
And we call this patrol timer finished.
Now we have one last input parameter for this and that's going to be the time.
And for now I'm just going to set this to 5 seconds.
So on Begin play, instead of moving to the target immediately, we're going to set the timer.
And once this time has elapsed, this 5 seconds, then our callback will be called, which will result
in calling move to Target.
And by the way, we can hover over now that we've filled in this function, we can see the overload
that we used.
We even see that there are two optional input parameters, one for looping, which means the timer will
loop over and over again and a first delay, which is the delay time for the first iteration.
If we did have looping, but we're not, we're going to leave it at its default value of false.
So now we're setting this timer.
And in order to test this out, we want to make sure we're not calling move to Target anywhere else.
We don't want to call the controllers, move to function.
So what I'm going to do is simply comment out all of this stuff here in the tick function where we're
getting our next patrol point and calling move to on the controller.
So I'm going to go ahead and comment all that out and save.
And now we should only move after 5 seconds.
So I'm going to go ahead and kick off live coding.
And we can hit play.
And we're going to see a five second delay before we see that enemy start to move.
And there it goes.
And then it reached its first patrol point and never picked another one because we commented out all
of that code.
So we can get that code back.
So now we know how these timers work.
We call set timer on the world timer manager.
So I'm going to comment that code out for now and uncomment move to Target because that is what I want
to do and begin play.
I want to set the timer.
After we've reached our target for the first time.
So let's go back down to the tick function.
And by the way, I feel like the tick function is getting a little unwieldy and could use a bit of a
refactor.
So a lot of the stuff here is simply picking a new target, right?
Or creating an array of valid targets.
We're picking one of them and we're setting the patrol target.
And this setting of the patrol target is really the key to this if check, right?
Because if we're in target range and then we set the patrol target to something else will no longer
be in target range.
So there's two main things we're doing here.
We're picking a new target and then we're setting the target and then of course we're moving to it.
So I want to make a new function to refactor some of this stuff we're doing.
In particular, I want to make a function for setting the target range, so I'm going to make a function
for picking a new patrol point.
So this will be a protected function.
I'll put it right under move to target and I'm going to have this function return an A actor pointer.
And this can be called Choose Patrol Target.
So this can do all those calculations and return our patrol target.
Let's go ahead and define this function, and I'm going to steal some code out of tick.
So we'll go back up to tick.
And here we're choosing a patrol target.
I'm really just going to copy all of this code and pick and choose what to go into our new function.
So it's called Choose Patrol Target.
I'm going to go ahead and keep that return null pointer at the bottom there and simply paste this in.
So what are we doing here?
Well, first, we're checking to see if we have a patrol target and an enemy controller.
Right.
But really, we don't need to do that.
We don't need to check to see if we're in target range.
That's all stuff that has nothing to do with choosing an actual patrol target.
Choosing a patrol target involves these inner lines here, creating our valid targets array, getting
the number of elements in it, making sure that's greater than zero, and then choosing a target from
the valid targets array.
So what we can do is highlight these inner lines of code, copy them, and we're going to get rid of
both of these outer if statements.
So what I can do is collapse that down, highlight it and delete it and paste in the interior, which
is making the tree, adding elements to the array from patrol targets.
And then if our num patrol targets invalid targets is greater than zero, then we're getting a random
selection and then we're selecting one of those targets.
That's all this function needs to do.
It doesn't need to set the patrol target and it doesn't need to call move to.
We're going to remove those lines of code as well.
So if we reach this part in the code where we get our target, we can simply return that value.
So we don't even need a local variable called target.
We can just return valid target's target selection.
And if we never actually reach the inside of this if check, then we'll hit the end of the function
and simply return a null pointer.
So Choose Patrol Targets is going to make a quick calculation and return at random.
One of the patrol targets that's not already being used.
So now we can use this function and make our tick function a little more manageable.
So let's go back to tick.
So how are we going to make this function more manageable?
Well, where first checking if we're in target range and if we right click and peak this where returning
a boolean here.
But if we wanted to, we could check to make sure our target is not null and return false.
If it is so in in target range, we can say if target equals null pointer return false and then we don't
need to check patrol target up here.
So now in target range is a little bit safer.
It's going to return false if target is null.
So it does a little bit of work for us.
So now we don't need to check patrol target.
Now we're also checking enemy controller.
Well, why are we checking that?
Because we're accessing enemy controller to call move.
To here.
Well, now we have a function called Move to Target, and we can easily check the enemy controller in
that function.
So let's go to move to Target.
And in fact, we are checking if enemy controller is null, then we return and we never actually call
MOVE two.
So those two checks in the tick function are not actually needed.
So we don't need those two.
Now we're checking if we're in range and then we're choosing a patrol target and resetting patrol target
equal to that before actually moving to that target.
So this could be simplified a great deal.
I'm just going to move it down a bit and all we really need to do is check if in target range.
And we're going to check patrol target and patrol radius.
And now in target range will return false if patrol target is null.
So that's all the checking we need to do here.
Then all we want is to choose a new patrol target and set patrol target to that.
And we now have Choose Patrol Target so we can set patrol target now equal to the result from Choose
Patrol Target.
And now all those other lines of code are obsolete.
And finally, after choosing a patrol target, we move to that target and we have a function for that
as well called move to Target.
So we would call move to Target passing in patrol Target.
So now our tech function has been simplified down to this.
And now these lines of code, this entire if statement is obsolete.
So we're going to go ahead and remove it.
So this does everything we did before.
Right.
But as soon as we reset our patrol target, rather than move to it right away, what we should do is
actually set the timer so we can go back up to where we called set timer.
We commented this out, but we can cut this.
I'm going to copy and delete it and come back down to tech where instead of moving to the target, we
can simply set the timer, which will move to the target after 5 seconds so we can go ahead and save
this.
Hop back in the editor, kick off live coding, and now we should see a five second delay after our
enemies have reached the first target.
So begin playing will make them start moving from the start and then they'll hit their first target
and wait 5 seconds.
There's the wait.
And there they go.
So we have the five second delay.
Excellent.
So that's what we wanted.
We have a five second delay between patrolling.
Now, something to take note of in target range is used up here.
Right.
And in target range returns false.
If what we pass into it is a null pointer, which means if combat target was null, then in target range
would actually return false, which means this would succeed and we'd still set combat target to null
and hide the visibility.
So that's okay.
If combat target is null by the time we reach this part.
So we don't really need this outer if check for combat target, I'm going to copy the interior, highlight
the whole thing, control V and replace it so I no longer have that outer if statement there.
But in addition to that, we've done a bunch of refactoring and I feel like the tick function could
be refactored even further.
You see, this is simply checking the combat target and doing what we need to do for that situation.
And this is simply checking the patrol target.
So really each of these could be their own functions.
I could highlight this section right click, go to quick actions and refactor things and extract function
and simply call this check combat.
Target, and that's what it'll be called.
Chuck Combat.
Target if I click okay.
Now it's refactored and it's simply called here.
And I'm going to do the same thing for this.
I'm going to right click quick actions and refactoring extract function and this can be check patrol
target and click okay.
And now that's refactored.
And now TTIC looks a great deal better.
Okay, so we know that this works and we have a five second delay.
But what if we want a random delay, say, between five and 10 seconds?
Well, we know how to make random numbers.
In fact, I'd like you to make this a random value between five and 10 seconds.
So take that as a challenge, pause the video and implement a random wait time now.
So for a random wait time, I'd like a pair of variables.
I'd like a wait time minimum and a wait time maximum.
So I'm going to go back up to the private section just under navigation and make two new floats.
I'm going to make a float called Wait Men, and by default, I'll give it 5 seconds and I'll make a
float called Weight Max.
And by default, that will be 10 seconds.
But I'd like these to be added anywhere, so I'm going to make them you properties edit anywhere and
category can be I navigation so they can be in there with those other variables.
So I'll give that to weight time min and to weight time max.
And now I'll make a random selection using Rand range.
So I'm going to make a cost float called weight time and use F math rand range for the men.
It'll be weight men for the max, it'll be weight max.
And now instead of 5 seconds, I can use my weight time.
Whoops.
There we go.
So let's test out our random wait time.
I saved all.
I'm live coding and I'm going to test this out, so I should see a random wait time between five and
10 seconds.
Let's see.
Okay, so waiting for a while.
10 seconds could be a lot.
So yeah, that was about five or six, maybe seven or 8 seconds.
Let's see how long these two wait here.
And this feels a lot more like a patrolling enemy.
It's more like what I would see in an actual game, right?
They usually wait about 5 to 10 seconds before they move on.
And if you wanted to, you could change that Idol animation.
You could find one where they're looking around.
I know Maximo has Idol animations even for this character, where they're looking around and, you know,
doing what patrolling guards do.
All right.
So that's going to wrap this up.
Great job with this video.
Our code's looking a lot neater.
We've done some refactoring and we have some really cool algorithms in place where our enemies are patrolling
and waiting in between times.
And in the next video we'll remove some of these debug spheres and we'll start thinking about how we're
going to aggro the enemy and have them start chasing after the player and attacking.
Great job.
I'll see you in the next video.