WEBVTT

00:07.000 --> 00:13.420
Okay, so we'd like to implement Click to Move, and that's going to involve our player controller.

00:13.510 --> 00:20.860
For now, I'm going to close all other tabs except or a player controller and the CPP.

00:20.890 --> 00:23.170
So header and CPP files here.

00:23.680 --> 00:31.780
Now for our player controller, I'm going to take some inspiration from the top down template, except

00:31.780 --> 00:35.830
we'll be making some changes and doing things a little bit differently.

00:35.860 --> 00:42.250
We're going to need a few internal variables to the player controller so they can be private.

00:42.280 --> 00:44.020
Now what variables do we need?

00:44.020 --> 00:51.130
Well, if we click on a particular location, we're going to want to cache that destination.

00:51.130 --> 00:57.400
So I'm going to make an F vector called cached destination.

00:59.860 --> 01:06.250
Now, I'd also like to keep track of how long we've pressed the mouse button before we release so we

01:06.250 --> 01:08.160
can know if it was a short press.

01:08.170 --> 01:12.190
So we're going to create a float to keep track of that.

01:12.310 --> 01:19.960
And that's going to be the amount of time that we've been sort of following the mouse cursor, right?

01:19.960 --> 01:25.030
Because as long as we're holding the left mouse button down, we're following the cursor, whatever

01:25.030 --> 01:28.070
that location is, under the mouse cursor.

01:28.090 --> 01:34.510
So as we're following, we're going to be incrementing this time and I'm going to be calling it follow

01:34.510 --> 01:35.140
time.

01:35.290 --> 01:37.730
We'll go ahead and make sure these are initialized.

01:37.750 --> 01:42.010
I'll initialize the vector to just the zero vector.

01:44.530 --> 01:47.410
And I'll initialize follow time to zero.

01:48.490 --> 01:52.000
Now we need to know the short press threshold.

01:52.180 --> 01:52.650
Right.

01:52.660 --> 01:57.430
How long do we hold our mouse cursor down before releasing it?

01:57.430 --> 02:03.050
And how much time until we no longer consider that to be a short press?

02:03.070 --> 02:08.710
So we'll make a float called Short Press Threshold.

02:10.060 --> 02:12.280
And we'll initialize that to zero.

02:13.120 --> 02:15.130
Now if we're auto running.

02:15.130 --> 02:22.510
In other words, it was a short press and we like to generate some path points and have our character

02:22.510 --> 02:28.870
moving along some kind of a spline that we're going to create that's going to be when we're auto running.

02:28.870 --> 02:30.850
So I'd like to know when that's the case.

02:30.850 --> 02:36.760
So I'm going to create a Boolean called Be Auto Running and initialize it to False.

02:36.760 --> 02:41.140
And that way we can call add movement input every single frame.

02:41.140 --> 02:45.430
As long as this boolean is true, as long as we should be auto running.

02:46.050 --> 02:52.920
And as long as we're auto running, we're going to be getting closer and closer to our destination,

02:52.920 --> 02:55.310
at which point we should stop auto running.

02:55.320 --> 03:00.720
How close we get to that destination should be a parameter we can change.

03:00.750 --> 03:09.030
I'm going to make it a float called auto run acceptance radius and I'll initialize that to 50 point

03:09.060 --> 03:11.580
F, but we can always change that.

03:11.580 --> 03:21.300
In fact, we can make this one a property with edit defaults only in case we'd like to change this value.

03:21.660 --> 03:24.690
Okay, so we have a number of variables.

03:24.690 --> 03:27.210
We're also going to want a spline.

03:27.240 --> 03:35.310
A spline or a spline component is going to allow us to generate a nice smooth curve out of a series

03:35.310 --> 03:38.480
of f vector world locations.

03:38.490 --> 03:40.830
That's what I'd like to use here.

03:40.830 --> 03:46.900
So I'm going to, first of all, forward declare its type, and that's going to be a spline component.

03:46.900 --> 03:50.530
So we're going to say class and it's a U spline component.

03:50.530 --> 03:51.580
That's the type.

03:51.580 --> 03:55.350
We're going to make a variable to store one of these.

03:55.360 --> 04:01.900
So down here at the bottom, we'll make a T object pointer of type U spline component and this will

04:01.900 --> 04:03.250
be just spline.

04:03.250 --> 04:04.570
I'd like it to be simple.

04:04.570 --> 04:09.070
We'll call this spline and I'd like it to get a U property.

04:09.070 --> 04:10.930
I'd like it to be visible anywhere.

04:10.930 --> 04:14.050
I'd like to see it in the details panel.

04:14.320 --> 04:18.670
And if we have a spline component variable, we need to construct that.

04:18.670 --> 04:20.350
We do that in the constructor.

04:20.560 --> 04:27.460
So here in the Ora Player controller constructor, we can construct that spline component.

04:27.460 --> 04:35.620
So we'll say spline equals and we'll use create default Subobject with u spline component.

04:36.040 --> 04:38.440
I'm going to let writer include that for me.

04:39.070 --> 04:40.990
And there it is.

04:41.020 --> 04:42.010
It's in components.

04:42.400 --> 04:43.480
Spline component.

04:43.480 --> 04:45.700
And we'll just call it spline.

04:46.120 --> 04:48.350
No need to attach it to anything.

04:48.370 --> 04:53.470
We're going to set its spline points as we generate paths.

04:53.500 --> 04:56.330
Now let's make sure our other variables are initialized.

04:56.350 --> 05:00.940
Our short press threshold actually should be a non zero value, right?

05:00.940 --> 05:02.110
This is in seconds.

05:02.110 --> 05:04.560
We're going to say it's a short press.

05:04.570 --> 05:14.140
If you clicked for less than, let's say 0.5 f seconds, follow time can be initialized to zero.

05:14.140 --> 05:19.390
Auto running should be false and auto run acceptance radius can be 50.

05:19.510 --> 05:25.900
So these are all looking good and we could if we wanted to just initialize those in the constructor

05:25.900 --> 05:28.870
If you wanted to do it that way, that's totally fine.

05:29.050 --> 05:29.530
Okay.

05:29.530 --> 05:32.640
So we have a few variables that we'd like to use.

05:32.650 --> 05:36.730
So let's think about this from the perspective of playing the game.

05:36.730 --> 05:39.200
What happens when we click in the world?

05:39.380 --> 05:45.770
Well, the left mouse button is going to be one of the inputs that's kind of special.

05:45.770 --> 05:52.010
It's different than the others in that we're going to use it for Click to Move, but we're also going

05:52.010 --> 05:56.750
to use it to activate abilities if they're assigned to the left mouse button.

05:56.750 --> 06:02.810
So we need to know if we left click, do we want to run or do we want to activate the ability?

06:02.840 --> 06:07.670
We need some kind of criteria to tell us whether we should do one or the other.

06:07.880 --> 06:15.800
Well, we know if we're clicking whether or not our mouse cursor is on top of an enemy because we're

06:15.800 --> 06:23.930
highlighting that enemy and our cursor trace and any given frame, this actor is a pointer that will

06:23.930 --> 06:31.820
hold either an AI enemy interface if we're hovering over an enemy or anything implementing this interface.

06:31.820 --> 06:34.250
And if we're not, it's going to be null.

06:34.250 --> 06:41.510
So any given frame, as soon as we click with our mouse, we can know whether or not we're targeting

06:41.510 --> 06:43.820
something, if we're targeting something.

06:43.820 --> 06:49.880
In other words, our mouse cursor is hovering over an enemy, then we can go ahead and activate our

06:49.880 --> 06:51.350
ability or try to anyway.

06:51.350 --> 06:57.590
We can get our ability system component and tell it we're trying to activate an ability, but if we're

06:57.590 --> 07:00.260
not targeting something, we should not do that.

07:00.260 --> 07:03.200
So how do we handle this situation?

07:03.200 --> 07:07.700
Well, we can have a Boolean for whether or not we're targeting something.

07:07.700 --> 07:12.290
Let's add that and we'll put this down here with our other associated variables.

07:12.290 --> 07:15.680
It'll be a bool and we're going to call it be targeting.

07:16.010 --> 07:18.320
We'll set it to false by default.

07:18.320 --> 07:25.100
And as soon as we've clicked, as soon as we've pressed, we want to see if we're targeting something.

07:25.100 --> 07:32.090
And that's going to be if this actor is a valid pointer, if it's not a null pointer.

07:32.090 --> 07:40.640
So what we can do is set be targeting here in ability input tag press, we can say be targeting equals

07:40.690 --> 07:43.480
us and let's just use the ternary operator.

07:43.480 --> 07:46.150
We'll say this actor question mark.

07:46.180 --> 07:47.140
True.

07:47.170 --> 07:49.180
Otherwise false.

07:49.210 --> 07:50.740
Whoops, false.

07:50.740 --> 07:57.340
So in other words, if this actor is not a null pointer, then this ternary operator expression returns

07:57.340 --> 07:57.850
true.

07:57.850 --> 08:01.030
If it's a null pointer, then it returns false.

08:01.030 --> 08:06.160
And if we want this to look even more explicit, we can say this actor equals null pointer.

08:06.400 --> 08:13.810
Now if ability input tag pressed is being called, that means we just clicked with our mouse.

08:13.810 --> 08:16.300
So we should not be auto running.

08:16.300 --> 08:23.860
We're going to set be auto running to false because we don't know yet if it's a short press.

08:23.890 --> 08:26.320
If it's a short press, we're going to auto run.

08:26.320 --> 08:30.070
But we don't know that yet until we've released the mouse button.

08:30.400 --> 08:30.790
Okay.

08:30.790 --> 08:34.930
So that's going to be all we need to do in ability input tag pressed.

08:35.170 --> 08:37.810
Now, what about for when we're holding it down?

08:37.810 --> 08:39.960
An ability input tag held?

08:39.970 --> 08:44.540
Well, it kind of matters what the input tag is if it's the left mouse button.

08:44.540 --> 08:45.200
Right.

08:45.200 --> 08:51.530
In fact, it kind of matters here in ability input tag pressed whether we're pressing the left mouse

08:51.530 --> 08:53.690
button, we should probably check that.

08:53.690 --> 08:54.830
Let's check it here.

08:54.830 --> 09:00.980
We'll say if input tag and we can use dot matches tag if we want to do that.

09:00.980 --> 09:04.370
But we do have to match tag exact if we're going to do that.

09:04.610 --> 09:06.890
And what are we checking to see if we match?

09:06.890 --> 09:10.340
Well, we need to get our gameplay tags, don't we?

09:10.370 --> 09:17.270
So we can get F or a gameplay tags double colon get now.

09:17.270 --> 09:17.540
Right.

09:17.540 --> 09:19.460
Is going to include that header for me.

09:19.460 --> 09:22.040
So make sure you have that included.

09:22.040 --> 09:28.520
And from this we can get the input tags and we need input tag LMB for left mouse button.

09:28.850 --> 09:35.690
So really if we're matching this tag, then we are concerned with whether or not we're targeting and

09:35.690 --> 09:36.140
so on.

09:36.140 --> 09:38.750
So we're going to place those in an If check.

09:38.760 --> 09:44.100
And we're going to use this same if check here in ability input tag held.

09:44.100 --> 09:49.560
So I'm going to go ahead and just place that if check here removing the inner contents of it.

09:49.560 --> 09:57.210
And we want to try to activate the ability if the input tag is not the left mouse button.

09:57.210 --> 10:06.870
So really we could say if not input tag matches, tag exact input tag and be then we can attempt to

10:06.870 --> 10:08.220
activate the ability.

10:08.220 --> 10:13.680
And if we're trying to activate the ability, we're not trying to auto run or move our character at

10:13.680 --> 10:14.100
all.

10:14.100 --> 10:15.930
We just want to activate the ability.

10:16.050 --> 10:24.330
So in this first if statement, I'm just going to check if get ask if we have a valid ability system

10:24.330 --> 10:32.190
component, then we'll try to activate the ability or at least tell it that we're holding an input with

10:32.190 --> 10:35.490
this input tag and I can remove that part down there.

10:35.760 --> 10:42.750
So while we're holding this down, if it's not the left mouse button, say it's the one key or the right

10:42.750 --> 10:47.040
mouse button, we're just going to tell the ability system component, hey, inputs being pressed.

10:47.040 --> 10:48.660
So do your thing.

10:48.660 --> 10:50.100
Check to see if it's active.

10:50.100 --> 10:52.530
If it's not, activate it and so on.

10:52.530 --> 10:59.580
Now, otherwise, if this is the left mouse button, well, now we're concerned about running, right?

10:59.580 --> 11:06.900
And if we're holding the mouse button down, I want to know if we're targeting and this right here is

11:06.900 --> 11:12.690
only for if we're not pressing the left mouse button down, but if we are pressing the left mouse button

11:12.690 --> 11:18.690
down and we're targeting in other words, we're hovering over an enemy, well, we want to do this as

11:18.690 --> 11:19.020
well.

11:19.020 --> 11:22.410
So we're going to say if be targeting.

11:24.450 --> 11:26.060
Then we want to do this too.

11:26.070 --> 11:28.680
We want to activate the ability.

11:29.010 --> 11:32.580
Now, if we've activated it already up here, we should return.

11:32.580 --> 11:34.950
So we'll return right here.

11:35.430 --> 11:38.380
Whether the ability system component is valid or not.

11:38.400 --> 11:45.210
But here, if we're targeting and we've made it this far, well, then we are pressing the left mouse

11:45.210 --> 11:48.740
button and we want to activate the ability.

11:48.750 --> 11:51.600
But if be targeting is false.

11:51.630 --> 11:56.010
Now we're concerned with actually our click to move behavior.

11:56.310 --> 12:01.680
So while we're holding it down, if we made it all the way this far, this is where our click to move

12:01.680 --> 12:03.600
behavior belongs.

12:03.630 --> 12:07.400
Otherwise, up here, we're concerned with activating abilities, right?

12:07.410 --> 12:13.290
So here in the else case here, we're going to first of all, increment our follow time.

12:13.290 --> 12:16.290
So we're holding our left mouse button down.

12:16.320 --> 12:22.080
We're going to be adding get world get delta seconds.

12:23.040 --> 12:24.480
To our follow time.

12:24.480 --> 12:29.760
As long as we're pressing that left mouse button and as we're pressing the left mouse button, we're

12:29.760 --> 12:35.670
going to get the world location, the destination that we want to move towards.

12:35.670 --> 12:38.820
So that requires us to have a hit result.

12:38.870 --> 12:39.810
F hit results.

12:39.810 --> 12:45.030
We're going to call it hit and we're going to get the hit result under the mouse cursor.

12:45.210 --> 12:49.110
Now we can say if and call get hit result.

12:49.950 --> 12:51.410
Under mouse cursor.

12:51.450 --> 12:53.870
And what are we going to trace against?

12:53.880 --> 12:58.170
Well, for now, let's just trace against each collision channel visibility.

12:59.590 --> 13:02.550
Not physics body, but EQ visibility.

13:02.560 --> 13:03.340
There it is.

13:03.550 --> 13:05.590
Do we want to trace complex?

13:05.710 --> 13:11.530
I'm going to pass in false so we don't trace over complex collision and then we pass in the hit result

13:11.530 --> 13:12.070
there.

13:12.640 --> 13:19.450
So if we make it inside this if statement because get hit result under cursor returns a boolean if it's

13:19.450 --> 13:27.850
successful then inside this hit result we're going to cache that destination by setting our cached destination

13:27.850 --> 13:31.420
equal to hit dot location.

13:31.450 --> 13:38.110
We can also use hit dot impact point in the case of a line trace their the same.

13:38.110 --> 13:40.990
If it were a sphere trace they'd be different.

13:40.990 --> 13:46.060
It would be the point at which the surface of the sphere hits versus the center of the sphere.

13:46.060 --> 13:49.570
But we can use impact point or location here.

13:50.200 --> 13:56.380
Now, after we've gotten our cached destination, we need to call add movement input.

13:56.380 --> 14:01.700
As we're holding the mouse down, we're getting a destination to move towards.

14:01.700 --> 14:03.590
We're going to want to move towards it.

14:03.620 --> 14:07.730
Now to call add movement input, we need our controlled pawn.

14:07.730 --> 14:17.030
So what we're going to do is we're going to make an if statement and say a pawn controlled pawn equals

14:17.060 --> 14:18.140
get pawn.

14:20.050 --> 14:23.680
That way, if it returns null, we won't do anything.

14:23.680 --> 14:29.080
If it doesn't return null, we have a valid controlled pawn and we need to call add movement input and

14:29.080 --> 14:32.800
pass in a direction which means we need a world direction.

14:32.800 --> 14:36.670
Let's say const F vector world direction.

14:37.150 --> 14:45.100
And what we can do is we can take our cached destination and subtract our controlled pawns location.

14:45.100 --> 14:49.570
So controlled pawn get actor location.

14:49.900 --> 14:55.900
But this is the vector from the controlled pawn to the cached destination.

14:55.900 --> 14:58.120
So we want to pass in a normalized vector.

14:58.120 --> 15:02.860
So I'm going to wrap these in parentheses and call dot get safe.

15:02.860 --> 15:03.790
Normal.

15:04.480 --> 15:11.650
So now that we have this world direction, we can take our controlled pawn and call add movement input

15:11.740 --> 15:14.440
and we're going to pass that world direction in.

15:15.520 --> 15:21.950
We don't want to scale it by anything other than one that's a float, so I'll make it one dot f And

15:21.950 --> 15:26.900
in fact, scale value has a default value of one, so we don't even need to pass that in.

15:27.470 --> 15:29.150
So that's all we need to do.

15:29.150 --> 15:33.860
And this is going to handle holding the mouse button down to move.

15:33.860 --> 15:37.490
And it's only going to work if we're not targeting something.

15:37.490 --> 15:40.220
This is something we can test out right away.

15:40.220 --> 15:42.980
So let's go ahead and just make sure this works.

15:42.980 --> 15:47.690
And this should work in multiplayer as we're calling add movement input here.

15:47.690 --> 15:55.040
Now we're not handling path point generation, so we can't just click and release and expect it to run

15:55.040 --> 15:57.320
to its location magically.

15:57.320 --> 15:58.340
We'll do that next.

15:58.340 --> 16:00.980
But for now, let's test out what we've got so far.

16:01.160 --> 16:07.070
So if I press play and if I click and hold, I see nothing happens.

16:07.070 --> 16:09.860
But good thing we're running in debug mode.

16:09.860 --> 16:12.050
We can place some break points.

16:12.170 --> 16:14.570
So let's see the input tag.

16:14.570 --> 16:18.080
I believe it's going to be the left mouse button tag.

16:18.080 --> 16:20.330
So I don't know.

16:20.330 --> 16:26.120
However, if be targeting is going to be true or false, it should be false.

16:26.120 --> 16:30.740
I'm expecting it to be false as as soon as I press this.

16:30.770 --> 16:34.700
If the tag matches the left mouse button, we should make it in here.

16:34.700 --> 16:38.720
I'm going to place a break point here as well, so let's see what happens.

16:38.720 --> 16:41.240
So ability input tag pressed.

16:41.270 --> 16:46.760
The input tag is the left mouse button and we'll make it into here.

16:46.760 --> 16:50.450
And let's actually go one line farther.

16:50.450 --> 16:58.010
It's being set to true and that's because easy mistake to make it's if this actor is null pointer be

16:58.010 --> 17:04.910
targeting is set to true we actually want be targeting set to true if it's not a null pointer right

17:04.910 --> 17:11.870
that would mean we're hovering over something so silly mistake to make but an easy fix and really we

17:11.870 --> 17:15.530
want be targeting to be true if this actor is valid.

17:15.530 --> 17:20.990
In other words we don't need this equals null pointer there that was a mistake.

17:20.990 --> 17:23.690
So removing that we can try this again.

17:25.950 --> 17:27.450
Okay, well, press play.

17:27.450 --> 17:31.110
We'll click and hold and it's working.

17:31.110 --> 17:32.970
And this should work in multiplayer.

17:32.970 --> 17:36.360
I'm going to go ahead and set the number of players to two.

17:36.360 --> 17:38.220
We'll play as a listen server.

17:39.450 --> 17:41.820
And I'll try to move with my client.

17:41.820 --> 17:42.810
And it works.

17:42.810 --> 17:45.210
And our movement is nice and smooth.

17:45.960 --> 17:50.190
I've noticed I'm not getting my messages when picking up pickups on the client.

17:50.220 --> 17:52.080
We'll fix that very soon.

17:52.080 --> 17:55.200
But movement is looking good.

17:56.780 --> 17:57.320
Excellent.

17:57.320 --> 18:00.380
So this is a good stopping point for this video.

18:00.380 --> 18:07.220
And the next video will handle actually making the character move, including moving around obstacles

18:07.220 --> 18:09.950
and things when we click and release quickly.

18:09.950 --> 18:11.420
So we'll have a short press.

18:11.420 --> 18:14.630
So we're going to implement short press behavior next.

18:14.930 --> 18:17.150
Excellent job and I'll see you soon.
