WEBVTT

00:07.050 --> 00:07.950
All right.

00:07.950 --> 00:08.960
Welcome back.

00:08.970 --> 00:16.440
I now have my attribute menu widget controller open, and we're interested in binding callbacks to dependencies

00:16.440 --> 00:24.990
and broadcasting initial values because we'd like to inform the widget, the attribute menu widget that

00:24.990 --> 00:27.780
is of the values that it should display.

00:27.780 --> 00:35.280
In other words, we want to broadcast info to it and that's why we made our aura attribute info struct

00:35.280 --> 00:37.740
which we created in our data asset.

00:37.920 --> 00:40.020
Let's go ahead and clean up our tabs.

00:40.020 --> 00:50.070
I'm going to close other tabs and open up that data asset which exists in public ability system data.

00:50.100 --> 00:51.390
Attribute info.

00:51.390 --> 00:55.980
Here's that attribute info struct or attribute info.

00:56.010 --> 01:02.670
Now, when we want to broadcast info to the attribute menu, we want to broadcast one of these and then

01:02.670 --> 01:09.940
the attribute menu or any of its associated widgets can receive this broadcast and it can check its

01:09.940 --> 01:11.230
own data.

01:11.230 --> 01:16.450
Perhaps it has its own gameplay tag against the gameplay tag here.

01:16.780 --> 01:19.060
That's how I'd like to set this up.

01:19.480 --> 01:24.700
So the first thing I'm going to do is an attribute menu widget controller.

01:24.850 --> 01:33.550
I'd like to first of all get our attribute set and find out the value of, say, one of its attributes

01:33.550 --> 01:34.690
like strength.

01:34.780 --> 01:37.960
So how can we get that attribute set?

01:38.320 --> 01:39.550
Well, that's pretty easy.

01:39.550 --> 01:42.820
We already have an attribute set variable.

01:42.820 --> 01:44.500
It's called attribute set.

01:44.530 --> 01:47.590
Now its type is you attribute set.

01:47.590 --> 01:49.360
So we're going to need to cast it.

01:49.360 --> 01:58.390
So I can say you aura attribute set pointer called, we'll just call it as for now and I'll set it equal

01:58.390 --> 02:05.260
to the result of a cast, but I'll use cast checked so we don't have to worry about using a check assertion

02:05.260 --> 02:13.680
and I'll cast to you or attribute set and writer includes the header for me there and it needs to cast

02:13.680 --> 02:14.670
attribute set.

02:14.700 --> 02:18.840
We need that to be in the parentheses there and it looks like I typoed here.

02:18.840 --> 02:21.840
It needs to be your attribute set there.

02:22.170 --> 02:24.600
And now we have our attribute set.

02:24.600 --> 02:26.190
So we have that.

02:26.220 --> 02:27.600
That's great.

02:27.750 --> 02:31.530
I'd like to get the value of one of our attributes.

02:31.710 --> 02:37.710
Now we're going to be taking this at first from a very naive approach.

02:37.710 --> 02:46.260
We're going to just get strength, right and see what that is and then broadcast info up to our attribute

02:46.260 --> 02:51.330
menu widget so we can say as get strength.

02:51.330 --> 02:53.820
And now we know the value of strength.

02:53.820 --> 02:56.250
So how are we going to use this value?

02:56.280 --> 03:03.360
How are we going to broadcast info up to our attribute menu widget?

03:03.450 --> 03:06.660
Well, to broadcast we need a delegate, don't we?

03:06.660 --> 03:15.280
So I'd like to declare a delegate capable of sending our aura attribute info this aura attribute info

03:15.280 --> 03:17.260
struct up to our widgets.

03:17.260 --> 03:19.750
So let's make a delegate.

03:19.750 --> 03:25.990
And because our widgets are going to want to bind to this and I'd want potentially multiple widgets

03:25.990 --> 03:33.910
to be able to bind to it, we want a dynamic multicast delegate, so I'm going to declare dynamic.

03:35.020 --> 03:42.700
Multicast delegate and we want to broadcast one value, one struct value.

03:42.700 --> 03:50.560
So it's going to be one param and I'm going to call this F attribute info signature.

03:52.470 --> 04:01.980
And its single input parameter type will be a const reference to F or a attribute info.

04:02.010 --> 04:09.810
I'm going to add a forward declaration to it like so, and we'll have it with the name info and it has

04:09.810 --> 04:11.040
to be a reference.

04:11.070 --> 04:13.350
Otherwise we can't forward declare it.

04:13.770 --> 04:21.090
So now that we have this delegate, we can have a member variable of this type F attribute info signature

04:21.090 --> 04:25.110
and we're going to say attribute info delegate.

04:25.140 --> 04:26.220
We'll call it that.

04:26.430 --> 04:28.770
And it needs to be blueprint assignable.

04:28.770 --> 04:37.320
So it gets a new property with Blueprint Assignable, and I'll go ahead and give it a category as well.

04:38.610 --> 04:44.040
We'll have the category gas with the pipe symbol attribute.

04:44.070 --> 04:45.540
We'll just say attributes.

04:45.630 --> 04:46.050
Okay.

04:46.050 --> 04:47.370
So we have this delegate.

04:47.400 --> 04:52.780
We can broadcast so we can broadcast the value of strength.

04:53.380 --> 04:57.370
But really, any of our widgets can bind to this.

04:57.370 --> 05:00.880
And I'd like multiple widgets to bind to this.

05:01.000 --> 05:06.700
And because we're broadcasting an aura attribute info, we need to fill one of those in with info.

05:06.700 --> 05:07.330
Right?

05:07.360 --> 05:09.190
Well, we have a data asset.

05:09.220 --> 05:17.320
We can use a data asset that already has the name, the description, and a value field that we can

05:17.320 --> 05:19.870
fill in with our strength value here.

05:19.870 --> 05:24.940
So that means our attribute menu widget controller needs one of those data assets.

05:24.970 --> 05:26.440
Our attribute info.

05:26.440 --> 05:27.160
Right.

05:27.460 --> 05:29.170
So let's make a.

05:29.920 --> 05:37.960
Protected section and add a t object pointer of type you attribute info.

05:37.990 --> 05:43.150
That's our data asset type and this will be called attribute info.

05:43.510 --> 05:48.550
Now I want to set this from the blueprint, so I'm going to give it a new property with edits.

05:48.580 --> 05:55.990
We'll make it edit defaults only and as long as we set this then we can use it to look up our attribute

05:55.990 --> 05:58.390
info based on the gameplay tag.

05:58.390 --> 06:06.760
So back in our widget controller cpp file we can first of all check make sure our attribute info is

06:06.760 --> 06:08.740
set and valid.

06:08.740 --> 06:20.050
And if it is, then we can take our attribute info and call the function find attribute info for tag

06:20.260 --> 06:22.750
and we need to pass in the tag.

06:22.750 --> 06:23.290
Right.

06:23.320 --> 06:26.080
Well, we can always get the tag.

06:26.080 --> 06:27.580
It's a native tag.

06:27.580 --> 06:33.380
We can get it from our aura gameplay tags, but we have to include that header don't we?

06:33.410 --> 06:41.810
So let's include aura gameplay tags and we can use F or a gameplay tags.

06:41.840 --> 06:50.540
Get to get the aura gameplay tags and from there we can choose the attributes primary strength gameplay

06:50.540 --> 06:56.300
tag and find attribute info for tag Returns an F or a attribute info.

06:56.750 --> 07:02.450
Let's go ahead and it's not going to be const, we're just going to make an aura attribute info.

07:02.480 --> 07:10.970
We'll call it info and it's not const because we need to set its attribute value so we can say info

07:10.970 --> 07:17.750
dot and here's the attribute value we need to set that and we have it here.

07:17.750 --> 07:20.240
It's as get strength.

07:21.070 --> 07:22.780
So everything else was set.

07:22.810 --> 07:28.420
We set it in the blueprint for the data asset, but we didn't expose the attribute value to the data

07:28.420 --> 07:34.930
asset because we want it to be the correct value that we get from our attribute set at the time that

07:34.930 --> 07:36.210
we broadcast it.

07:36.220 --> 07:44.710
So now that we have correct attribute info, we can broadcast it using our attribute info delegate.

07:44.740 --> 07:53.050
Let's go ahead and make that broadcast attribute info delegate dot broadcast and we can broadcast that

07:53.050 --> 07:56.460
info not window but info.

07:56.470 --> 08:03.850
So in broadcast initial values we're going to broadcast info and our widgets need to bind to this attribute

08:03.850 --> 08:08.530
info delegate before we broadcast our initial values.

08:08.530 --> 08:10.150
That's important.

08:10.420 --> 08:12.850
So there are a couple things to do in blueprint.

08:12.850 --> 08:19.480
First, we need our attribute info set on attribute Widget Controller, our attribute menu, widget

08:19.480 --> 08:27.710
Controller and then we need to make sure that we bind to this delegate in order to receive this info

08:27.710 --> 08:29.690
on the blueprint side.

08:29.690 --> 08:35.240
So let's run in debug mode, we'll compile and launch and we'll take care of those things and see if

08:35.240 --> 08:37.370
we can receive that attribute info.

08:37.370 --> 08:41.430
Delegate And it looks like I have a compiler error.

08:41.450 --> 08:48.710
You attribute info undeclared identifier here in attribute menu widget controller and that means I need

08:48.710 --> 08:51.900
to forward declare you attribute info.

08:51.920 --> 08:54.800
Let's go ahead and do that up here at the top.

08:55.340 --> 08:57.080
I'll do it first class.

08:57.200 --> 08:59.810
You attribute info.

08:59.840 --> 09:01.430
Let's go ahead and compile again.

09:02.170 --> 09:08.050
It's very common to forget these little details when you're working with a lot of moving parts.

09:08.050 --> 09:13.180
So I don't worry when I forget little details like that, and neither should you.

09:13.450 --> 09:14.130
Okay.

09:14.140 --> 09:15.790
Let's go ahead and run this.

09:16.530 --> 09:20.370
And I'll go ahead and open up our asset editors.

09:20.370 --> 09:28.860
We have a few things open, but I do want to go to UI, widget controller and attribute menu Widget

09:28.860 --> 09:29.400
Controller.

09:29.400 --> 09:36.900
Now we have an exposed property here, the attribute info and we can select our data asset attribute

09:36.900 --> 09:39.330
info and compile and save that.

09:39.360 --> 09:47.220
Now our widget controller has it and now it can use that from here in broadcast initial values when

09:47.220 --> 09:49.230
it broadcasts the delegate.

09:49.380 --> 09:55.950
So a couple things we need to bind to the delegate and decide when to call broadcast initial values.

09:56.250 --> 10:02.730
So first, why don't we go to our attribute menu widget and let's look at what we need to receive.

10:02.730 --> 10:10.440
Each of these rows needs to receive data whenever its corresponding attribute changes or when we broadcast

10:10.440 --> 10:11.700
initial values.

10:11.820 --> 10:16.090
And we want to assign an attribute to each one.

10:16.090 --> 10:23.470
For example, I'd like this one here to be assigned the value of strength and this one to be intelligence

10:23.470 --> 10:24.490
and so on.

10:24.610 --> 10:30.070
So each of these should have its own gameplay tag for the attribute.

10:30.070 --> 10:31.930
It should have an attribute tag.

10:32.110 --> 10:34.060
Now this top one is for something else.

10:34.060 --> 10:37.420
This is for how many attribute points we have.

10:37.420 --> 10:38.980
We don't have a variable for that yet.

10:39.010 --> 10:41.170
We don't have an attribute or a variable.

10:41.200 --> 10:45.100
But for these we do have attributes in our attribute set.

10:45.220 --> 10:49.030
So there's a few things we need to handle.

10:49.030 --> 10:53.110
We need to handle adding an attribute tag to each of these.

10:53.110 --> 10:56.980
But for now, I just like to respond to that delegate.

10:56.980 --> 11:02.710
I'd like to subscribe to it from my widgets so I can at least see something.

11:02.710 --> 11:04.120
So here's what I'd like to do.

11:04.120 --> 11:12.670
I'd like to go to my text value button row class that's going to be in Blueprints UI attribute menu,

11:12.670 --> 11:15.990
and we have a text value button row.

11:15.990 --> 11:17.610
I'm going to open that.

11:17.730 --> 11:26.550
And here in the graph I'd like to set my own widget controller an event construct right here.

11:26.760 --> 11:36.660
So I'm going to call get attribute menu Widget controller using self as a world context object passing

11:36.660 --> 11:40.200
in self here and from this widget controller.

11:40.910 --> 11:43.070
I can search for.

11:44.170 --> 11:51.700
Assign, attribute info, delegate and on event construct, I can assign an event for this.

11:51.730 --> 11:57.100
Now each of these should have its own tag that it checks from the info.

11:57.100 --> 12:05.200
But for now all I want to do is take my info, drag off of it and break it so I can see that information,

12:05.200 --> 12:07.750
and then I can start setting things on this row.

12:07.750 --> 12:13.210
For example, I have text and a numerical value that I'd like to set.

12:13.240 --> 12:20.200
Well, I don't really have access to the text or the number, but I know that the parent class does

12:20.230 --> 12:23.380
and it can expose an inherited function for us.

12:23.380 --> 12:30.850
So the parent class is text value row, which does have access to the attribute we can check is variable

12:30.850 --> 12:32.770
for the text block attribute.

12:32.800 --> 12:37.060
We can rename this text block underscore, we'll call it label.

12:37.330 --> 12:47.150
And for the number we have a WP framed value for now, let's just take our text block label and let's

12:47.150 --> 12:49.400
make a function to set its text.

12:49.880 --> 12:57.110
So we'll go to our graph, we'll create a new function, add function, and we'll call this set label

12:57.110 --> 13:05.000
text and we'll get our label text block label and we'll call, set, text the function.

13:06.290 --> 13:11.570
Like so and we'll have an input for our set label text of type text.

13:11.570 --> 13:19.610
So let's add an input, choose text and call this label text and we'll simply pass that in.

13:19.940 --> 13:27.950
And now our base class has a set label text function and our text value button row now has the ability

13:27.950 --> 13:28.910
to set it.

13:29.000 --> 13:37.160
So as soon as this broadcast happens, we can call our inherited function set label text.

13:39.000 --> 13:43.350
We'll do that and we'll pass in our attribute name.

13:44.220 --> 13:44.670
Like.

13:44.670 --> 13:47.130
So now we can compile.

13:47.130 --> 13:51.210
And now this will be set for our attribute menu.

13:51.390 --> 13:57.390
Whenever our delegate gets broadcast from the attribute menu Widget Controller.

13:58.890 --> 14:00.690
So I'm going to save all and press play.

14:00.720 --> 14:06.660
Now, we're not going to see anything because we're not broadcasting that delegate That happens once

14:06.660 --> 14:09.630
we call broadcast initial values.

14:09.660 --> 14:15.630
So here in our attribute menu, we need to decide when to broadcast initial values.

14:15.780 --> 14:19.190
Well, we can do so after our widget controller is set.

14:19.200 --> 14:20.520
That should be fine.

14:20.520 --> 14:26.760
So on our widget controller, which is an attribute menu widget controller, we need to call broadcast

14:26.760 --> 14:27.480
initial values.

14:27.480 --> 14:30.800
But that is not an exposed function, is it?

14:30.810 --> 14:35.610
So why don't we close our editor and go to our attribute menu widget controller.

14:35.610 --> 14:43.170
We know broadcast initial values is a virtual override, so we need to go to our base class in UI,

14:43.200 --> 14:48.420
widget controller or a widget controller and find broadcast initial values.

14:48.420 --> 14:49.440
Here it is.

14:49.440 --> 14:53.040
And we want this to be a blueprint callable function.

14:53.040 --> 14:56.190
So let's just really quickly make that happen.

14:56.220 --> 14:58.140
Now it's blueprint callable.

14:58.170 --> 15:06.490
Now we can run the editor and we can call broadcast initial values so we can get that delegate broadcast.

15:08.690 --> 15:13.790
Okay, let's open up our asset editors and we'll go to Attribute Menu.

15:13.790 --> 15:20.300
And right here, after we've set our widget controller, we can get that widget controller and call

15:20.330 --> 15:22.520
broadcast initial values.

15:22.730 --> 15:31.520
And now that delegate will be broadcast and all of our text value button rows will have their attribute

15:31.520 --> 15:38.090
info delegate event bound to that delegate and they will receive that attribute info.

15:38.090 --> 15:40.430
And by the way, it's just strength.

15:40.430 --> 15:46.730
So all we're doing is getting the attribute info for the strength attribute.

15:47.310 --> 15:52.590
But this is just getting things working, making sure that we can connect all the pieces.

15:52.590 --> 15:59.760
So if we press play and open our menu now, all of our text value button rows have strength.

15:59.790 --> 16:00.870
Look at that.

16:01.020 --> 16:03.560
So this is a great step in the right direction.

16:03.570 --> 16:05.670
Now, of course we have problems, don't we?

16:05.700 --> 16:09.600
We have to be able to set the strength value.

16:09.600 --> 16:16.220
And also anything else that's not assigned strength should not show strength here.

16:16.230 --> 16:18.150
These should show the other attributes.

16:18.180 --> 16:18.720
Don't worry.

16:18.720 --> 16:19.650
We'll get to all that.

16:19.650 --> 16:21.780
We have to take this one step at a time.

16:22.020 --> 16:28.000
The next step is to show the strength value which we should have access to, right?

16:28.020 --> 16:34.020
We should be able to get that from the attribute info struct right here.

16:34.020 --> 16:35.190
The attribute value.

16:35.220 --> 16:44.390
We could print a string here with the attribute value and I'm going to make this visible for five seconds.

16:44.400 --> 16:51.520
I'm going to make it pinkish red and there's another print string that I want to get rid of here in

16:51.520 --> 16:52.810
attribute Menu.

16:53.350 --> 16:55.690
We're printing the widget controller's name.

16:55.690 --> 16:57.210
I don't want that anymore.

16:57.220 --> 16:59.530
So I'm going to press play and open attributes.

16:59.530 --> 17:03.160
And they're all four of these are printing the value of strength.

17:03.160 --> 17:04.810
So we have access to it.

17:04.840 --> 17:12.490
We need to be able to set the strength, numerical value and really quickly we can just make that happen

17:12.490 --> 17:13.660
before we move on.

17:13.660 --> 17:22.300
We can go into our base class text value row and make a function for setting the numerical value.

17:22.300 --> 17:25.450
So let's go ahead and create a new function.

17:25.460 --> 17:32.020
We'll say add function, and for this new function we'll call this set.

17:32.850 --> 17:34.500
Numerical value.

17:34.500 --> 17:42.720
And we may wish to have two versions one that can set the value to an integer without decimals and one

17:42.720 --> 17:47.220
that can set the value to a floating point with maybe 1 or 2 decimals.

17:47.220 --> 17:52.290
So why don't we say set numerical value INT and this will take an integer.

17:54.430 --> 17:58.120
So integer and we'll call this new value.

17:58.120 --> 17:59.420
But what can this do?

17:59.440 --> 18:05.050
Well, we have to access our widget here called the Framed value.

18:05.050 --> 18:10.410
And the frame value needs a way to set its numerical value as well.

18:10.420 --> 18:13.630
So the frame value should be checked is variable here.

18:14.210 --> 18:18.690
And if we get the framed value, we need a way to set its numerical value.

18:18.710 --> 18:20.300
Let's find that framed value.

18:20.330 --> 18:21.250
Here it is.

18:21.260 --> 18:24.710
And the number is called text block value.

18:24.740 --> 18:26.680
It's set to is variable here.

18:26.690 --> 18:31.190
So from here in text value row, we're getting our framed value.

18:31.220 --> 18:34.610
If we search for text block value here.

18:35.260 --> 18:39.820
And call, set, text the function, not the setter.

18:40.440 --> 18:49.050
Then we can set our text using this integer and we have to take this integer and use to text using to

18:49.050 --> 18:50.330
text integer.

18:50.340 --> 18:53.370
We can pass it in there, so we'll hook that up.

18:53.780 --> 18:58.530
And now that we have a set numerical value and we can compile and save.

18:58.550 --> 19:07.370
And now our text value button row when we receive our delegate broadcast, can simply call set numerical.

19:08.310 --> 19:09.060
Value.

19:09.060 --> 19:13.980
INT And that means we'll take our attribute value and convert it to an int.

19:14.100 --> 19:17.680
That's going to truncate any decimals there.

19:17.700 --> 19:21.660
So if we compile this press play, open the menu.

19:21.660 --> 19:25.850
We see tens for all four primary attributes.

19:25.860 --> 19:31.140
The reason we don't see it for the secondary attributes is these are not using the text value button

19:31.140 --> 19:35.250
row, they're just using the text value row without the button.

19:35.400 --> 19:40.410
And we're binding to this delegate only in text value button row.

19:40.410 --> 19:40.920
Right?

19:40.920 --> 19:47.430
So and this is just to get it working, just to show that we actually are broadcasting those values

19:47.430 --> 19:48.960
from the widget controller.

19:49.050 --> 19:56.220
And that's thanks to our attribute menu, taking our widget controller and calling broadcast initial

19:56.220 --> 19:57.480
values on it.

19:57.480 --> 19:59.220
So we're getting there.

19:59.220 --> 20:01.170
We just have a couple things left to do.

20:01.170 --> 20:07.110
We have to make sure that each of these rows knows what attribute it's supposed to display.

20:07.110 --> 20:13.840
So when it receives the broadcast, it can check that incoming attribute tag against its own tag.

20:13.840 --> 20:21.460
So in the next video, we're going to assign tags for each of these in our attribute menu.

20:21.490 --> 20:22.120
Here it is.

20:22.150 --> 20:25.270
We're going to assign attribute tags to each of them.

20:25.270 --> 20:27.340
So we'll do that next.

20:27.370 --> 20:30.130
Great job and I'll see you soon.
