Welcome back.
Our widget controller is now capable of broadcasting initial values.
We know that we can cast our attribute set to an aura, attribute set and access those attribute values
with those attribute accessors.
That's great, but we're going to want to be able to respond to when those attributes change and the
ability system component has a function for doing just that.
It looks like this.
We take the ability system component pointer and we call get gameplay attribute value change delegate.
This function needs to know what attribute we're talking about.
Well, we could always get that from aura attribute set.
If we're talking about the health attribute, we'd take aura, attribute set and call get health attribute
that returns an if gameplay attribute.
That's what this function requires.
So this returns the delegate and if we want we can bind to that delegate.
It returns an on gameplay attribute value change delegate and to bind to it we use the dot operator
and we use the function add you object.
Now, if this were a dynamic multicast delegate, we could use add dynamic, but gameplay attribute
value change if we right click and go to declaration or usages and then right click on this gameplay
attribute value change and go to its declaration or usages.
We see that it's a multicast delegate, it's not a dynamic multicast, so we can't use Add dynamic.
We have to use Add you object and to bind a callback to it, we pass in this followed by the callback
function and the callback function has to have a specific signature to be able to be bound to this delegate.
So we really need to create a function to bind to it.
And so that's one of the next things that we need to do.
But really before we do that, binding callbacks to the dependencies of this widget controller is something
that all widget controllers need to do.
So we're going to make a function that we can use to bind our callbacks to all those dependencies.
Let's add that to our Aura widget controller.
That's the parent class, and that way all widget controllers can implement that function.
So I'm going to make it a virtual void function and I'm going to call it bind callbacks to dependencies.
So this will be a very important step that our widget controllers have to go through.
I'm going to generate the definition, but leave it blank because I want my overlay widget controller
to override it.
So here an overlay widget controller just under broadcast initial values.
I'm going to override virtualvoid, bind callbacks to dependencies and go ahead and generate the definition
here.
And I don't care about calling super in this case.
I'm just going to bind callbacks here and we need a callback that we can bind to that delegate that's
broadcast whenever our attributes change, such as health and max health.
So I'd like a callback function for each of these.
So let's go to our H file and I'm going to make these protected.
They're going to be void functions.
And for health, I'm just going to call it health changed.
Now here's the signature that it has to have to bind to those delegates on the ability system component.
It has to be a const reference to F on attribute change data.
So we have a const reference, we're going to call it data.
So I'll have one for health changed and I'll have one for max health change.
So I'll go ahead copy and paste that and change it to max health changed and we can create definitions
for these.
Now these functions have a signature that qualifies them to bind to the delegate that is broadcast when
an attribute changes.
And so we'll do that here in bind callbacks to dependencies.
So I'm going to take my line here where we're getting our attribute set and casting to our attribute
set as I need that.
And after that I'm going to take the ability system component and call get gameplay attribute value
change delegate passing in the attribute that I want to bind a callback for.
So first I'll do it for health.
So I'll get aura attribute set and call get health attribute.
So this whole expression here returns that delegate.
So I'm going to use the dot operator here and call add you object passing in this for the user object
and the address of my health changed function callback fully qualified with the class name here like
so.
And now whenever the health changes, this function callback will be called.
Now that's a lot.
All on one line.
If you want, you can break it up.
You can say put an enter there and there.
If you want to do that, you can put it.
Enter there and there.
Put a new line.
It's up to you.
I'm going to go ahead and organize it like this on two lines.
I think that's enough for me.
And there we have it.
So I've bound health changed to this delegate for when our health attribute changes.
So really it's this part here the input for get gameplay attribute value change delegate.
This is the attribute we specify and then this is the callback that we specify specifically.
So if I want to do this for max health change, I can copy these lines, paste them here and instead
of get health attribute, I can call get max health attribute and instead of health change I can use
my callback that I called max health changed.
So now these functions will be called when the attributes change.
So what do we want to do when the health changes?
Well, I just want to broadcast my on health change delegate so my widgets can respond to it.
So I'm going to broadcast it there.
Now, I don't need to access it from aura attribute set.
I actually have that information here in data.
So in order to get the new value from data, I can take this broadcast call and pass in data dot new
value.
And that's how we get that new value that has just changed for the attribute.
Now writer says this can be made const.
So let's listen to writer and why not?
We'll make these functions const.
That means we need to put const here on the definitions as well.
Now for Maxhealth change, we'll do the same thing.
We'll take this line.
Paste it here, except instead of on health changed.
We're going to broadcast the on max health changed broadcasting data new value.
So now whenever health and max health attributes change, these delegates will be broadcast and our
widgets are already bound to on health changed and on max health changed.
At least our health globe widget is bound to these so we can test this out.
We know that our health potion adds to our health and if we go to our attributes set and instead of
emitting our health to 100, we can emit our health to 50, for example, and leave our max health at
100.
That way our health globe will start off half empty or half full, depending on whether you're an optimist
or a pessimist.
And then once we pick up the health potion, we should see that health globe go up to 75% because our
health potion adds 25 to our health.
So tying this all together is going to be your quest.
We never actually called bind callbacks to dependencies, so you're going to need to call that function.
So you need to think about where this should be called.
When is it appropriate to call this function?
Once you've called it, you can play test, go pick up a health potion and see if that health globe
changes in response to the attribute change.
So pause the video and conquer this quest now.
Okay, so the question arises, where do we call bind callbacks to dependencies?
Well, let's take a look at where we're calling broadcast initial values.
That would be over here in the HUD.
When we call init overlay, right, we're broadcasting initial values there, so you might have thought
maybe I can call it there.
Well, we also have get overlay widget controller, which is where that widget controller is constructed
for the very first time.
Now this will be called when we call get overlay widget controller.
So if we place it in that function, those callbacks will be bound to the dependencies there.
So I think that's a great place to put it and that's where I'm going to put that function call.
So as soon as we set the widget controller params, we know that those key variables are set.
As soon as those are set, I'm going to bind callbacks.
So I'm going to take overlay widget controller and call bind callbacks to dependencies right here.
Just before we return the widget controller.
And then we know that the widget controller is callbacks will be bound so that when those attributes
change or whatever other dependencies we bind callbacks to change, we'll get the change broadcast.
So I'm going to run in debug mode.
Let writer compile and we should see a half full health globe since we're now initializing health to
50 and max health to 100.
So I'm hoping to see a half full health globe here.
I'm going to press play.
There it is.
It looks about half full.
And if I pick up this health potion, it goes up.
Look at that.
Excellent.
So that is looking great.
We now have our health globe reacting to changes in our ability system.
We can even double check by entering the console command show debug ability system and we can see that
our health is now 75.
It started at 50, but we picked up a health potion and now we have 75% as shown on the health globe.
So this is looking great.
Now, it seemed like a lot of work to set all this up, but now we have a class designed to handle controlling
the widget data and retrieving it from the system.
And the way we have it set up, our dependencies are all one way.
Our ability system component knows nothing about the overlay widget controller.
It's completely independent of it.
An overlay widget controller knows nothing of the widgets that are bound to its delegates.
They're completely independent of it.
This is going to be a very powerful system as we'll see throughout this course.
So excellent job and I'll see you in the next video.