Welcome back.
Now we have our gameplay ability firebolt.
And so far it's pretty simple.
If we're hovering over an enemy and we left click, we spawn a Firebolt, which is great, but obviously
we have some things that we need to do.
Now in this section we're concerned with talking about ability, tasks and ability.
Tasks are sort of like the workers that a gameplay ability employs to do tasks and things that can be
done either instantaneously or they may span across some period of time.
And there are a number of tasks that already exist in the gameplay ability system.
And of course we have the ability to create our own.
Now the easiest way to learn how tasks work is to just use one of the pre-made tasks.
So if we right click, let's type play montage.
Now if we select play montage under animation montage, this is what we refer to as a latent node.
Latent means a synchronous or a node that will be executed.
And then depending on what happens later, we have a number of output execution pins that can be executed.
Notice that it has an input execution pin and it also has a regular output execution pin.
The regular output execution pin at the very top right is executed immediately after we reach the node.
But then that allows us to continue calling other functions and things right after we've reached the
node.
But then we have a number of circumstances that can trigger these other output execution wires to flow
such as completed.
That's when the montage has finished playing on blend out.
This is executed when the montage begins, blending out and is not interrupted and depending on blend
settings, this might be earlier than completed and usually is on interrupted is self-explanatory.
On notify Begin.
This is executed when using a play montage, notify or a play montage notify window in the montage as
we can put notifies in the montage and then of course notify end is for when a montage notify window
has ended.
As you can see, there are a number of things that can cause any of these situations to trigger.
Now this is just a blueprint latent node, also known as an async task.
Now gas has more specialized forms of these latent nodes and these are more ingrained in the ability
system itself.
For example, if we type play montage, notice that there's another blueprint function under ability
tasks.
This is an ability task and if we click on this one, it looks a lot like the other one.
It just has more options, right?
And if you had browsed through the gameplay ability header file, you may have noticed that there were
some things in there related to montages.
A given ability knows which montage is currently playing.
If we're using the gameplay ability system version of play montage and wait now play montage in wait
is going to do what it says.
It's going to play a montage and then it's going to wait for one of these things to happen for the montage
to complete or blend out or be interrupted or cancelled.
And then of course, we have the topmost execution pin that we can execute things immediately after
reaching the node with.
Now let's see how this works.
I'm going to delete that play montage latent node and leave my play montage in wait ability task node.
And what this can do is it can play a montage.
We can hardcode one in by selecting one here, but that means we need a montage to play, don't we?
So why don't we create a montage real quick?
We can go to content assets, characters, aura animations, abilities and we have this cast Firebolt
animation.
I'd like to use this.
I'm going to right click on it, go to create and create anim montage and I'm going to call this a m
underscore cast underscore Firebolt.
I'm going to double click on it.
And now I have a montage.
Now it's set to the default slot.
All montages are set to use the default slot by default.
Right.
But we do need to be using that default slot and it's a good idea to just double check in our animation
blueprint.
So in Blueprints Character Aura, here's our animation blueprint app Aura.
And yes, we created the default slot node here and we're running our pose through it.
So if we play this montage, we'll actually successfully see it played.
So we have a montage called Arm Cast Firebolt.
So if we go back to our gameplay ability and open our dropdown, we now see the montage, we can select
that and play montage and weight is going to play the montage and we can just see that this topmost
execution wire is executed right away by printing a string that says Casting Firebolt.
And if we compile and press play and click on an enemy, we see that we're playing that montage and
of course we're spawning the projectile immediately, which doesn't look right, but we're playing the
montage.
Now let's open that montage back up and make sure that we're okay with our blend options.
Our blend in under blend option is set to 0.25.
I'd like this to be zero so we have no blending and for blend out, I'm okay with a little blending,
but less than that.
I want 0.1 and then we can test this out.
That looks better.
I want to just start playing the montage with no blending at all so it's a lot faster, more responsive.
You can have some blending here if you want.
If you prefer to have it less snappy, you can have a blend in time.
I like them very low, so like 0.05 is a good blend time.
So as we can see, we play the montage and immediately we get that print string node because that print
string node is reached immediately after play montage and wait.
However we can do things later.
That's what async tasks are good for.
We can do something when Oncompleted is executed so we can just drag off of this, use a print string
and say Oncompleted.
We can also do something on blend out.
So we'll do a print string in this case that says on Blend out
and then we'll do a print string for the other two here we're going to say on Interrupted.
And then on cancelled.
We'll say on Canceled.
So that way we can see which of these gets called.
So we'll go ahead and activate our ability.
And then we see that on blend out and on completed happened, right?
They get executed.
Why?
Because we start blending out first and that's why we get that message first and then on completed happens
because shortly after we began blending out, the montage completes and we're not interrupting or canceling
the montage.
So those print strings don't get called.
But we saw that a short period of time elapsed before on Blend out and on completed were executed.
This allows us to do things later in time without needing to go through the trouble of using timers
and things like that.
We can base things on the length of a montage, so this is great.
Now we know how to use the blueprint node, but how does this work under the hood?
How does a blueprint node become async and how does it wait until something happens and then execute
these wires conditionally based on what's going on in the game?
Well, I'm going to close and save all and I'm going to hit double shift so I can search my solution
and I'm going to search for play montage and wait.
And we see this U ability task play montage and wait and it's in the header file with that name.
I'm going to click on that and we see that this is a class based on U ability task.
The comment says ability task to simply play a montage.
Many games will want to make a modified version of this task that looks for game specific events.
Now let's take a look at this class.
Here in the class, we have a number of delegates.
We have an F montage weight, simple delegate, and there are four of them on completed on blend out
on interrupted and on canceled.
Those were the names of those output execution pins.
So when you create an ability task and you add some blueprint assignable delegates to it, then those
become output execution pins for the ability task node.
So we have some comment here.
And this big comment is right above this right here.
And what we have is a static function called create play montage and wait proxy that returns a pointer
of type U ability task play montage and wait.
Now this is a blueprint callable, it has a category, it has a meta with display name, play, montage
and wait, which means that the blueprint node for this function is going to say play montage and wait.
It doesn't have the u ability task in front of it.
It also has hide pin owning ability so this means that the blueprint node is not going to show this
input parameter for this function called owning ability.
It also has default to self owning ability, which means that not only are we hiding this input parameter
as a pin from the blueprint node, we're saying to default this owning ability to self in C plus plus
that would be this.
And we see blueprint internal use only set to true, which if we hover over it says this function is
an internal implementation detail used to implement another function or node.
It is never directly exposed in a graph.
When we create this static function that returns the type of the class that we're in like this with
these specific U function specifiers, this creates our latent node that we saw in Blueprint.
Now, if we go to the CPP file and take a look at the definition of that static function, we can scroll
down and find it.
Here it is.
We can see what it's doing.
Ultimately, it's creating a new ability task with this function, new ability, task, specifying this
particular task, and then it's setting a number of parameters on that new task and returning it.
So these ability tasks have this static function that creates an instance of themselves and returns
it after setting a number of input parameters that can be exposed to the blueprint.
So this is made to be created in blueprint, although the function itself could be called in C plus
plus of course.
And then we know that this particular class has a number of delegates right now.
As soon as we've created this ability, task ability tasks have an activate function and when they're
activated, whatever we have in this activate.
Function is what happens now.
Play montage and wait, as we would probably imagine, is going to play a montage.
We can see that right here.
It's calling play montage on guess what an ability system component.
How does it know which ability system component to play the montage on?
Well, ability tasks have an owning ability system component.
They have a variable called ability system component.
And this particular ability task is just calling play montage on it.
Notice that it's also binding some function callbacks to some delegates.
These are those delegates we looked at in the header file.
It's binding its own on montage blending out function.
And what does on montage blending out do?
Well, here it is.
We see what it's doing.
It calls clear animating ability on the ability system component.
It gets the character.
How does it get it?
It gets it from the avatar actor.
So it has a function.
Get Avatar actor.
It's checking for authority and then calling set and root motion translation scale.
We don't have to get too deep in what all these do.
This function is self-explanatory.
If you're using root motion, that root motion can be scaled for its translation.
This function checks to see if it's being interrupted.
If so, it broadcasts on interrupted.
Same thing for on blend out.
So as you can see, the class has a number of callbacks bound to the delegates that it has.
So the takeaway here is that an ability task is basically this C plus plus class that has a static function,
a sort of factory of sorts that constructs an instance of itself that's blueprint callable exposed to
blueprint.
And the class has a number of delegates that are broadcast based on things that are happening.
And it has an activate function usually in which those delegates have some callbacks bound to them.
And these delegates can be broadcast based on whatever logic we implement here.
Play montage and wait.
Just happens to play a montage and broadcast delegates when the montage is finished or in any number
of related cases to that, you'll see that our ability task is getting the anim instance from the actor
info associated with this ability tasks, ability and owning ability system component and getting a
montage set blending out delegate and then that results in this delegate having its callback executed
which is on montage blending out.
So as you can see, there are lots of delegates and this will make a lot more sense when we create an
ability task of our own.
But this deep dive is just to show what's going on behind the scenes with this play montage and wait.
So now that we've seen what play montage and wait is sort of doing behind the scenes, we can use play
montage and wait in our gameplay ability and that's going to make things easier for us when we need
to play a montage in a given gameplay ability and wait for something to happen.
Now, what if we want to wait for something that's not one of these cases?
What if we want to wait until a certain point in our montage before we do the next thing, such as spawn
our projectile?
For example, here in our montage, we don't want to spawn our projectile here.
We want to wait until a certain point in the animation, maybe right here to spawn that projectile.
In other words, we might want to create some kind of anim notify.
So how do we know once we've reached a certain point inside of our anim montage so that we can do the
next step in our gameplay ability, such as spawning the projectile?
That's going to be the topic of our next discussion.
So we'll take care of that next.
Great job.
I'll see you soon.