Welcome back.
Now we have an aura player controller.
It has an aura context.
That's the input mapping context that we're going to set.
Once we make a blueprint based on this and then begin play, we access the enhanced input local player
subsystem to call add mapping context.
That's how we add that mapping context so that our player controller can retrieve data.
Now, how do we actually retrieve that data?
Well, in characters it's usually done in setup player input component.
And if you'll recall, that used to be in our or a character base, but we deleted that function as
we plan on doing things here in the player controller and the player controller can handle input.
It has a function called setup input component.
So contrast that with setup player input component.
It's just called setup input component.
Now this is a protected function much like Beginplay and we're going to override this.
So we'll say virtual void setup input component override ID and we can go ahead and generate the definition.
And in this function, of course, we need to call super.
We'll let that happen, but we need to access the input component.
You see, the player controller has an input component variable.
If we simply type input component, we'll see that we can access that variable.
And if we hover over it, we see that it's a T object pointer of type U input component.
Now we created an enhanced input input action and to bind a function to that input action so it can
be called to handle input data, we need to cast our input component to an enhanced input component
as this input component is a pointer of type U input component, but it actually stores the address
of an object of type U enhanced input component.
So if we say U enhanced input component and create a pointer to that and we can call it enhanced input
component, for instance, we can cast the input component to this type now rather than casting and
then checking the pointer or using an assert like we did up here with subsystem, we can do both in
one go using cast checked cast checked needs to know what type we're casting to.
That's this type enhanced input component.
And what we're casting is our input component member variable.
And if the cast fails, then it's the same as hitting an assert here.
In other words, we can crash the program if this cast fails.
Now this is an incomplete type, which means we're going to need an include for this so we can include
that.
And that's going to simply be the include for enhanced input component dot H.
And now this is no longer an incomplete type and we don't need to check the pointer.
We don't need to use an assert.
We'll get a crash if this cast fails, which is what we want because that will really get our attention
and make sure that this is not broken.
So once we have our enhanced input component, we want to bind our move input action to it, which means
just like our input mapping context called aura context, we also need a variable for our input action.
Now the C plus plus type for input actions is U input action, and I'm going to go ahead and forward
declare it right up here along with our input mapping context.
So we'll say class U input action and we'll add a variable down here of that type.
It can be a private variable.
So we'll say T object pointer u input action and we'll call this move action.
We'll make it edit anywhere and stick it in the same category category input.
So we'll give it that u property.
Now we're going to want to set that on the blueprint and we're going to want to bind a function that
we can use to move our character in response to input.
So we need a function for moving the character.
This is going to only be called internally here in the player controller, so it can also be private.
We'll make a void function called Move Now in order to bind move to an input action that provides data,
we have to provide an input parameter for move and that's going to be of type const F input action value.
That will be a const reference and we'll call this input action value.
Now F input action value is not defined here.
We would have to include the header file for it or forward declare it because it's a reference here
we can forward declare it and it's a struct.
So rather than forward declaring with the class keyword we can say struct f input action value and forward
declare it that way.
We could also alternatively forward declare up here with our other forward declarations so we can say
struct f input action value up there.
And then this.
Struct keyword down here now becomes redundant as Ryder has graded out, telling me that I no longer
need it there as we've already forward declared.
Now we can generate a function definition for move.
I'll go ahead and let Ryder generate that for me.
And now we have a callback function and we also have our move action input action variable.
Now we need to link these two together.
Whenever we press Wasd keys, our Move action will be filled in with data according to how we've configured
our input mapping context.
Right.
So Move needs to accept that data in the form of an input action value.
So we'll configure this here in setup input component since we have access to our input component and
the input component has the function bind action designed to do just that, bind a function to one of
our input actions.
So we're going to take enhanced input component and we're going to call bind action, which takes the
input action.
We're going to use our move action and takes an E trigger event.
In other words, do we want move called when our input action starts?
Do we want it when our input action is triggered?
In other words, do we want to continue calling this as long as our input is triggered or held down?
In our case, I do want that, so I'm going to choose triggered.
Next is the user object that's going to be this player controller object.
And finally, the callback function.
That's going to be the address of operator, followed by the fully qualified function name.
We'd like to bind to this input action A or a player controller move.
So after this line move will be bound to move, action and then move can contain the movement functionality
for moving the character.
And that's going to be relatively simple.
First, we have to get our input action value and we need that in a form that we can retrieve the X
and Y axis data from it.
Remember, our move input action is an axis 2D type input action so we can make a const local F vector
2d called input axis vector.
And what we'll do is we'll take our input action value, we'll call get on it, which is a template
function that allows us to get the value in the form that we need it in.
We need it in an F vector 2d form.
So now we have our input action value in the form of a vector 2D.
We can access the X and Y axes of that.
So how do we want to use it?
Well, we'd like to use add movement input to add movement to our controlled pawn in the forward direction
and the right direction based on the X and Y values of our input axis vector.
So the way we do that is first we figure out which direction is forward for us and we want to find out
which direction is forward based on our controller.
As our controller will be pointed basically in the direction from the camera to the character and controllers
have a rotation accessible with get control rotation.
So if we get this control rotation and we zero out its pitch and roll, then we have the yaw value for
our controller's rotation.
And if we convert that to a vector, then that will be what we consider forward As far as w asd keys
are concerned.
So here's what I'll do.
I'll make a const f rotator called rotation and initialize it with get control rotation.
So we have our controllers rotation but I'd like its pitch and roll zeroed out.
So we just have your.
So I'll make another const F rotator called your rotation and I'll initialize it with a zero for the
pitch and I'll use the yaw from rotation.
So rotation yaw for the yaw and zero for the roll.
Now you could be clever and condense these into the same line if you like.
I'm going to leave it like this so it's a bit more obvious what I'm doing.
And now I have a rotation that I can use to get a forward vector from.
The way to do that is to create an f vector.
I'm going to make this const and I'll call this forward direction and we can use an F rotation matrix
to get a forward vector from this rotator value.
We do that with F rotation matrix.
We initialize an F rotation matrix with our rotation, and from that F rotation matrix we call the function
get unit axis, not axes but axis.
And this requires the enum e axis.
And we need to specify the axis.
X will give us the forward axis.
So this gives us the forward vector that corresponds to this, your rotation vector.
And if our controller's rotation is that rotation, as I mentioned, from the camera to the character,
and if your rotation has zeroed out the pitch and roll for that, then forward direction is the vector
pointing from the camera to the character only it's leveled out.
It's parallel to the ground.
That's how we get forward direction.
But we also want the right direction.
So we're going to make a const f vector called right Direction and we'll use this same exact function
call creating an F rotation matrix.
The only difference is for each axis we're going to use Y as that will give us the right axis vector.
And these are normalized because get unit axis returns a unit vector, which is a vector with a length
of one.
Now that we have those directions, we can add movement input to the controlled pawn.
Now, to get the pawn controlled by our player controller, we can call, get pawn and get pawn is a
template.
Function requires a type.
We just want a pawn.
That's fine.
And what we can do is create a local pointer variable of type a pawn.
We'll call this controlled pawn and we'll wrap this in an if statement.
So that way, if controlled pawn is null, well then we won't do anything.
And because Move is potentially called every frame, it might be called a little too early before this
controlled pawn is valid.
So in this case, rather than doing an assert, we're just going to check the pointer and we have forward
and right directions.
All we need to do is take that controlled pawn.
And we can call add movement input on that pawn and add movement input takes a world direction.
We'll add movement input in the forward direction, but we also have a scale value to pass in and our
input axis vector.
This 2D vector from our input action value has an X and a Y component.
And as we already said, as we're pressing W and S to go forward and back, the Y component of this
vector will be positive 1 or -1 depending on whether we're pressing W or S.
If we're pressing S, it'll be negative and we'll be calling add movement input, moving our character
in the forward direction, but scaled by negative one, which means we'll have it moving in the backward
direction.
So we need to scale by the y component of this input axis vector.
So we'll say input axis vector.
Dot y here, and we'll handle moving left and right by taking this line.
We'll copy it.
And instead of forward direction, we'll pass in right direction.
And instead of the input axis, vector y component, we'll use the x component as the x is what we associated
with the A and D keys moving left and right.
So now we have a move function that will handle movement based on our input action.
So now that this is all set up, the only thing left to do is tie this all together.
We need to make an aura player controller blueprint.
We need to set these variables, the aura input mapping context and the move action.
And then we need to make sure that our project is configured to use aura player controller and our Aura
character.
So we'll take this one step at a time.
The first thing we need to do is actually make a blueprint based on this C plus plus class.
So your quest will be to make a player controller blueprint.
So create a blueprint based on aura player controller, call it BP or a player controller.
Make sure you keep a good folder structure in your blueprints folder.
Now, in this blueprint, set up the input action and input mapping context variables that we added
in C plus plus.
Pause the video and conquer this quest.
Okay, so we need a blueprint based on this class.
I'm going to go ahead and launch the editor and here in the Blueprints folder, I'm going to make a
new folder called Player and we'll make that blueprint here.
So I'm going to right click, make a Blueprint class and search for Aura Player controller and choose
that.
And this will be BP ora player controller.
And I can open that up and we can set ora context.
We'll use IMC ora context and our move action will be in a move.
So that's set up and we're all set there and that's it.
So in the next video, we need to make sure that our project is set to use this player controller as
well as our Ora character.
We can configure all that with a game mode.
So we'll be making that next.
And before we wrap up the video, recall that in our player controller we cast our input component to
the U.
Enhanced input component class.
And I mentioned that I know that this pointer, which is a pointer of type U input component, points
to an object of type U enhanced input component.
Now how did I know that?
Well, if you go to edit project settings and input.
Then we can scroll down to the bottom.
And down here, under default classes, we have default input component class and it's set to enhanced
input component.
That's how I knew that our input component pointer points to an object of this type because here in
project settings is where we configure that.
And if we wanted a say, custom enhanced input component class and we went and created one in C plus
plus, then here is where we would set that class to make sure our project uses that as the input component.
So I figured I would just point that out so I can go ahead and close project settings.
And in the next video we'll tie all this together so we can actually start moving our character.
So great job.
I'll see you soon.