[SOUND] So welcome to Creating an Out Parameter Method.
In this video,
you're actually gonna create a method that uses out parameters yourself.
It's gonna return a boolean but actually,
it's gonna mutate the status on the called HitLocation.
So it's gonna use out parameters and that will give you a much deeper understanding.
So please take the time to do the challenge in this one and
spend a good hour on it if you're a beginner.
But if you get stuck after that, then do just keep watching.
Okay, let's take a look at this AimTowardsCrosshair
a little bit more closely.
I don't think I explained in the last video that the reason we are checking
that we have a control tank is it doesn't make any sense to start
aiming towards the crosshair on the screen unless we're controlling a tank.
So what we need to do now is what it says in the pseudo code, and I wanna use
an out parameter for this, because the engine uses out parameters a lot.
And I want you to get used to not only using them but actually creating methods
without parameters yourself, and that's gonna be your challenge for this video.
But for now, let me explain how I plan on building it up.
So we're gonna make ourselves an FVector.
And you may as well follow me along with this for the moment and
it's called HitLocation.
And it's gonna be an out parameter.
Now I'm gonna stop doing the whole hash define out at the top,
because that's not common in the engine code.
And you need to start getting your IN as it were.
Start getting used to seeing out parameters when they exist.
So we're gonna have this Fvector location, all right, HitLocation rather.
Now what I'm gonna do, is I want to print this out.
To start with, so let's just go ahead and UE_LOG this and
it should just be zero vector to the LogTemp.
With warning verbosity, using the text sub-macro.
A macro inside a macro.
And we're gonna say.
Now, I'm just gonna say the following.
I'm gonna say HitLocation.
Now you'll see there's a ToString.
Why is it a dot rather than an arrow?
Because it is an actual variable here.
It's an actual member, it's not a pointer.
.ToString, and that's a method.
So check your brackets on match.
So that bracket there, if you select it, is matched with this one which is good.
And let's go ahead and see if we at least on every tick because AimTowardsCrosshair
is called remember from tick.
We should be getting a zero vector logged out.
Now there is a deliberate mistake here by the way.
This will not compile but it would be a very easy and innocent thing for
you to do here, right?
And you might think that it's because we're missing a star, but
let's just see what the error messages are for the learning.
HitLocation undeclared identifier, ToString must have a something or
other unknown type and function doesn't take full argument.
So the first thing you may try is putting a star going, yeah, that old chestnut.
This thing needs to be converted to a TChar*.
So I'm gonna put a * in front of it.
So yeah, you can try that.
Let's see what we get now.
I'll go get rid of same of the errors I think, but
I don't think it will get rid of all of them.
And then we'll look a bit more closely because this is something you may well
come up against and it will frustrate you and I want to help you.
So we have here, the log function does not take four arguments,
okay, and the reason for that is this is interpreting.
Whatever this text macro is doing,
it's interpreting the result as two separate arguments.
So the solution to this type of thing is actually to use the format operator.
It's to do something useful.
Say text, and then say HitLocation:,
and then you %s or whatever.
Right, it needs to be %s for string, close your braces, and
then the comma for the HitLocation.
Now check your bracket matching, and now I think that this will work.
Because actually, this whole thing will be considered just that third parameter.
I know that's really strange with where all the commas are.
You pretty much just have to remember this.
Cuz we don't wanna go and dissect exactly how all these macros work.
But the UE_Log macro expects three parameters, one, two, three.
And this third thing I have highlighted on the screen is itself
just a parameter in aggregate, and let's try that.
I think that would work and it looks to be more useful, because it will log
HitLocation rather than just logging some random thing to the console.
It's always worth labeling what you're logging so
you know that you're looking at.
So that did work and if we play now, we get HitLocation,
some massive number because it was never initialized, and then 0, 0.
So normally, you would initialize your variables,
but as we're gonna use this as an out parameter, I'm actually not gonna bother.
Okay, so so far, we've done pretty much nothing apart from learn a little bit more
about the necessity of using these format operators or the trick in here.
So what we're gonna do is we wanna get the world location of, or not if, but
of the line trace through the crosshair.
What that means is when you're playing the game and the crosshair's up in the sky,
it's probably going to hit nothing.
But if it hits the terrain, we want to know it's hitting the terrain and
then we wanna return the world space location of where it's hit, so
that the aiming system can now aim at that mountain side.
That's what we're aiming to do, excuse the pun there.
Now what I wanna do is I wanna make a method that does all this in one go.
And that method is gonna be called GetSightRayHitLocation.
And I actually want you to write the outline of that method.
To take in an out parameter and the out parameter is this HitLocation.
So you may have to stop and think about this,
or revisit a previous section depending on how advanced you are.
So I want you to write GetSightRayHitLocation.
It's gonna return a bool, and that's gonna be true if it hits anything and
false if it doesn't.
Now listen, I don't want you to fully implement necessarily this method.
I just want you to write the signature of it and get it laid out.
So it's gonna return this bool, and it's gonna be a constant method.
Because it's just gonna return an out parameter.
It's not gonna mutate any of the member functions of this tank player controller.
We wanna return an FVector called HitLocation as an out parameter.
Remember, you need to use an ampersand somewhere.
The reference or is it address operate to depending on whether it's a prefix or
postfix.
Remember towards about two-thirds the way through.
I think building escape, we talk about this in references and pointers,
the lecture.
As a bonus, you could pseudocode the actual functionality of this
GetSightRayHitLocation method.
It's purpose is to ray cast through the dot as far as we're concerned,
into the landscape and determine whether we hit anything.
If we do, we return true and as an out parameter, we return where in the world
we've hit, and if we don't hit anything, we return false.
All right, and as a super bonus, you get it working but that's a bit much.
And if it works, then your log will actually continuously update
with the location of where that crosshair is aiming at.
But, as I said, that's super advanced and really only try it if you want an extra
challenge, it's just for the more advanced people.
So go ahead, pause the video, and have a go at all that now.
Do have a go at this one.
It's gonna take juts a tiny bit of thinking about, but
you've used out parameters before, so go and see where they were used and
see if you can remember how to do it.
Okay, welcome back.
So here in the PlayerController,
we've got to think whether we want public or private for a start.
Well, I'm gonna suggest it's gonna be
private because no other method outside of this needs it.
It's a helper method, so we're gonna return
an out parameter and it's gonna be called true if hit landscape.
All right, now it's bool, I said we wanted it to return bool.
We said it was gonna be called GetSightRayHitLocation.
And we said that it was gonna take in, well, not take in but mutate or
change a FVector.
And that FVector was gonna be called HitLocation.
And the method was gonna be cons but there's one more thing.
Our parameters work by passing references to and in this case,
it's gonna be passing a reference to an FVector.
So this will make a little more sense in a minute when we see an incoming text in
the implementation.
So I'm gonna copy that signature.
Put it straight in here.
Of course, I need the class name, Like so, okay?
Long old method definition, right?
So signature, as you call it, this thing here is the signature.
So what's actually happening when I pass this in?
Well, let's make the call.
We're gonna go.
If GetSightRayHitLocation,
Passing in HitLocation as the thing that's going to be used as the out parameter.
Then all of this lot, like so.
Okay, so the thing about this if GetSightRayHitLocation is it actually
does anything.
It has a side effect.
It doesn't change anything, but it has a sort of side effect,
which is that it's actually going to ray trace.
Later on when we implement that, okay?
And if that's true, then we're gonna log it out.
So this, get world location of linetrace, that's gonna be implemented in here.
If it hits the landscape return true, well, we know that.
I actually better put that in as a comment, I think.
The FVector& reference is saying that we're
gonna create a variable here called HitLocation.
We're gonna pass what looks like HitLocation itself and
to GetSightRayHitlocation, but it's actually a reference to that.
And then somewhere later in our code,
we're gonna change the value of HitLocation.
So I don't like this architecture but you'll see it all over the engine and
you do need to make sure you know how that works.
Leave this as a to do,
because later we're going to tell the control tank to aim at the point.
Or at the moment we wanted to do is get you this far,
that we actually set up an out parameter.
So, in the next video, we're gonna look and
see what actual values we're gonna put into this thing.
But for now, I'm gonna return false to say we haven't hit anything.
And I'm gonna just set HitLocation to something
recognizable FVector 1.0, let's say.
And what's that's gonna do is it's gonna return an FVector to this 1, 1, 1.
And then we'll be able to recognize that.
So we should go through here, this should go to true,
and then we should log the HitLocation, and it should be one, and
that proves that all our code is executing properly.
And then in the next video, we'll talk about how GetSightRayHitLocation's
actually gonna work in practice, and it'll be a good further exercise.
So I hope you got on well with that reference challenge and
you were able to make this out parameter based method.
If this is all sounding gobbledygook to you,
then just stick with it, you'll get used to it, you'll get used to the idea here.
I really want you to better read engine code and
read code written by other people.
So I'm gonna drag you through the mud a little bit.
So let's have a look.
That all looks okay, apart from we're not getting anything come out every hit, so
it's obviously HitLocation.
I have return false, I need to return true.
So what happend there is I was returning false, so this wasn't evaluating.
So it was just jumping straight out.
So we need to return through.
All right, we're pretending we hit something, and
we're pretending that we've hit something at a location of 1, 1, 1.
So I'm playing the game now, it's compiling in the background.
When the heart reload completes, I expect the love to fill up with exactly that,
HitLocation 1, 1, 1.
Great, so
we are a step further through our process of setting up the whole architecture.
Before we go,
let's just remind ourselves of what that whole aiming architecture was.
I'll go through the slides and show you that one.
Remember that what we're trying to do here ultimately is we're trying to have a tank
oops, let me go back.
The tank possessed by either an AI or a player.
The AI was gonna tell it where to aim, or the player's gonna tell it where to aim.
Actually, it's the same AimAt method.
And then, that tank will delegate out the aiming to an aiming component,
which we haven't made yet which will finally tell the blueprint to do some
actual rotations of turret and barrel, respectively.
So it's a long-odd haul getting this working.
This is the second-most complicated thing we're gonna do in this section.
The most complicated will be the actual movement of the tank,
which of course will be gagging to do the moment we can actually aim our tank.
So anyway, that's it.
I hope that's all made sense to you.
I'll leave the code on the screen.
I think that might be helpful to you,
so that you can see what we've actually written here, and that's it.
I shall see you in the next video.
Remember, to commit your work to source control.