WEBVTT

00:06.900 --> 00:13.920
So now that we have an attribute menu, we want to show the values of our attributes.

00:13.920 --> 00:21.090
And for that matter, we want our attribute names to be shown and any other information associated with

00:21.090 --> 00:22.170
those attributes.

00:22.170 --> 00:26.910
Perhaps we'd like to hover over the name and get a tooltip or something like that.

00:26.940 --> 00:30.930
So we need a way to get the data to the attribute menu.

00:31.170 --> 00:38.340
Now, following our architecture pattern, this means we'll need a widget controller so we can have

00:38.340 --> 00:41.640
a widget controller dedicated to the attribute menu.

00:41.670 --> 00:44.610
We can call this attribute menu widget controller.

00:44.730 --> 00:51.930
And then as changes occur in the model, for example, our Ability system component broadcasts a new

00:51.930 --> 00:54.990
change for one of our attributes.

00:55.020 --> 01:02.790
Our widget controller can subscribe to those ability system delegates and then broadcast those changes

01:02.790 --> 01:04.590
to the widget controller.

01:04.890 --> 01:07.390
Now we have a lot of attributes.

01:07.390 --> 01:09.370
So what's the best approach here?

01:09.400 --> 01:17.500
Do we simply subscribe to delegates for all of the attributes and respond to those and then create a

01:17.500 --> 01:24.940
new delegate for each attribute and broadcast it to widgets which subscribe to those attribute change

01:24.940 --> 01:30.280
delegates and just continue this pattern every time we add new attributes.

01:30.280 --> 01:36.430
This is a sort of brute force approach, but if we do that, we're going to have a lot of different

01:36.430 --> 01:38.680
delegates and broadcasts.

01:38.680 --> 01:43.680
When strength changes, the Ability system broadcasts it.

01:43.690 --> 01:49.930
Our widget controller receives that and broadcasts its own delegate on strength changed, for example,

01:50.080 --> 01:55.030
and then the appropriate widget binds to that and displays the value.

01:55.030 --> 02:02.050
And when resilience changes, that results in a delegate broadcast received by our widget controller,

02:02.050 --> 02:05.300
which broadcasts a delegate of its own and so on.

02:05.320 --> 02:08.560
Now this approach is okay.

02:08.560 --> 02:17.230
It does work and it is actually pretty efficient because only the strength row in our attribute menu

02:17.260 --> 02:21.700
is the widget that binds to the on strength change delegate.

02:21.730 --> 02:28.180
No other widgets bind to that delegate, so when it broadcasts, only one widget will respond to it.

02:28.180 --> 02:36.250
But this is not the most scalable pattern because if we add new attributes to our attribute set, then

02:36.250 --> 02:43.390
we have to actively go into the widget controller and bind some kind of callback or lambda to the delegate

02:43.390 --> 02:49.780
broadcast when that new attribute changes and then declare a new delegate to broadcast from the widget

02:49.780 --> 02:53.290
controller and broadcast that to the widgets.

02:53.530 --> 03:00.820
So in other words, just to add a new attribute results in changing quite a lot of code, not only in

03:00.820 --> 03:05.770
the widget controller, but perhaps on the widget blueprint side as well.

03:05.770 --> 03:10.420
And that makes it very hard to maintain and expand.

03:10.720 --> 03:17.890
Now consider the possibility that even though the ability system makes a broadcast, when any given

03:17.890 --> 03:24.420
attribute changes, our widget controller could have its code designed a little bit more cleverly.

03:24.430 --> 03:33.400
Let's say we receive the broadcast for when an attribute changes and instead of broadcasting one specific

03:33.400 --> 03:40.780
delegate for when the corresponding attribute changes, we broadcast one generic delegate on attribute

03:40.780 --> 03:46.840
changed and on attribute change can broadcast a number of pieces of information.

03:46.840 --> 03:53.830
Let's say each attribute is associated with a gameplay tag, so when the strength attribute changes,

03:53.860 --> 04:01.030
our widget controller will simply broadcast one delegate on attribute changed and pass through the gameplay

04:01.030 --> 04:08.230
tag associated with strength and any other information the widget is going to need, such as the name

04:08.230 --> 04:10.990
of the attribute and its value.

04:10.990 --> 04:14.480
Perhaps a description for a tooltip or whatever.

04:14.500 --> 04:18.460
In other words, we can send multiple pieces of information.

04:18.460 --> 04:24.730
We can even package them up into a nice, neat little struct that gets broadcast up to the widget side

04:24.730 --> 04:29.680
and the widget can check that gameplay tag and do what it needs.

04:29.680 --> 04:37.600
Perhaps each row in the attribute menu can have its own tag assigned to it and they can all receive

04:37.600 --> 04:41.860
this delegate and check to see if it's their particular tag that was broadcast.

04:41.860 --> 04:47.130
And if it is, they can take the data from that struct and update themselves.

04:47.140 --> 04:54.310
So it might be appealing to create this struct, something like an aura attribute info struct that we

04:54.310 --> 05:01.990
can send up to the widgets and each widget will be assigned its own gameplay tag that corresponds to

05:01.990 --> 05:03.760
an attribute for example.

05:04.150 --> 05:06.130
So this is a good way to do it.

05:06.130 --> 05:06.460
And the.

05:06.480 --> 05:09.710
Flow of information will proceed as follows.

05:09.720 --> 05:16.080
We have our widget controller which will bind to delegates broadcast from the ability system.

05:16.080 --> 05:20.580
When an attribute changes, the widget controller will know about it.

05:20.610 --> 05:27.780
Then the widget controller can take that attribute and try to figure out what the gameplay tag is that

05:27.780 --> 05:29.880
is associated with that attribute.

05:29.910 --> 05:32.460
That's something we're going to have to figure out how to do.

05:32.460 --> 05:38.670
But once our widget controller is smart enough to make that connection, we can then perform some kind

05:38.670 --> 05:45.900
of lookup to find the correct struct that has the right attribute, name, attribute, description and

05:45.900 --> 05:46.680
so on.

05:46.680 --> 05:49.720
So we can send that data up to the widgets.

05:49.740 --> 05:57.600
If this is data driven, then we can have some kind of either data table or perhaps a data asset that

05:57.600 --> 06:02.700
can package up all the data associated with any given attribute.

06:02.730 --> 06:03.960
Gameplay tag.

06:04.230 --> 06:11.200
Now we've seen how to use data tables and lookup info from those, but so far we haven't used any data

06:11.200 --> 06:12.010
assets.

06:12.040 --> 06:19.660
Data assets are nice because they can look things up not only by name but by anything we'd like, such

06:19.660 --> 06:26.890
as a gameplay tag so we can make a data asset class, call it you attribute info and we can program

06:26.890 --> 06:34.690
the capability of this attribute info data asset to receive a gameplay tag and return a struct that

06:34.690 --> 06:38.740
contains all the information associated with that tag.

06:38.890 --> 06:45.280
Now, once we have that information, we can then make the broadcast up to the widget side and the widgets

06:45.280 --> 06:52.670
can each receive it and check to see if it contains the correct tag so it can update itself with information.

06:52.690 --> 06:55.030
So this means we need to do a few things.

06:55.030 --> 07:02.800
First, we need a widget controller for the attribute menu set up to receive broadcasts from the ability

07:02.830 --> 07:05.200
system when attributes change.

07:05.230 --> 07:12.910
Next, when we receive that attribute, we need a way to figure out what the correct gameplay tag is

07:12.940 --> 07:15.010
associated with that attribute.

07:15.040 --> 07:22.120
We need to map these two together somehow, and we'd also like a way to reference these gameplay tags

07:22.120 --> 07:23.440
in Cplusplus.

07:23.470 --> 07:25.540
Now we've seen one way to do this.

07:25.570 --> 07:32.440
We can use request gameplay tag which takes in an fname where we specify the tag we'd like.

07:32.470 --> 07:40.300
So we're basically asking the gameplay tag manager for a tag structure, giving it the name to look

07:40.300 --> 07:46.480
up and if the gameplay tag manager has that tag, then request gameplay tag will return that for us.

07:46.600 --> 07:53.770
Now this is error prone and I don't like having to have an F name where we type out the string name

07:53.800 --> 07:55.930
of a given gameplay tag.

07:55.930 --> 07:58.090
I'd like a better approach to this.

07:58.090 --> 08:03.310
Some kind of class that stores a global source of tag variables that we can access.

08:03.310 --> 08:05.800
So that's something we'll need to look into.

08:05.980 --> 08:14.710
Now third, we need a data asset capable of receiving gameplay tags and returning our aura attribute

08:14.710 --> 08:16.930
info struct that we need to make.

08:16.930 --> 08:24.010
So that way, as soon as we know the tag for a given attribute, our data asset can give us all the

08:24.010 --> 08:31.960
data we need to send up to our widgets and that will be our last step once we have that struct, that's

08:31.960 --> 08:40.180
to broadcast it up to widgets and our widgets can check their own gameplay tags against the struct gameplay

08:40.180 --> 08:43.630
tag sent up and then they can update themselves.

08:44.200 --> 08:48.610
So this means we have a few next steps for our attribute menu.

08:48.790 --> 08:56.650
First, we need to create our secondary attribute gameplay tags and we want a way to handle tags better

08:56.650 --> 09:01.780
in cplusplus rather than calling request gameplay tag all over the place.

09:01.780 --> 09:07.330
We want some kind of centralized source of gameplay tag variables on the Cplusplus side.

09:07.510 --> 09:15.610
We also need a attribute info data asset that can store these structs and allow us to perform a lookup

09:15.610 --> 09:21.550
based on gameplay tag to find the attribute info we need so we can broadcast it up to widgets.

09:22.030 --> 09:24.490
We also want to create that struct.

09:24.520 --> 09:31.120
We'll make an aura attribute info struct that contains all the information we want to send up to widgets.

09:31.670 --> 09:38.270
And then we need to fill in that data asset with those attribute info structs for each attribute.

09:38.300 --> 09:42.400
And of course we need to create our widget controller for the attribute menu.

09:42.410 --> 09:48.470
This widget controller will tie everything together as it's going to listen to broadcasts made from

09:48.470 --> 09:56.150
the ability system and it can perform its lookup from the data asset attribute info retrieving the attribute

09:56.150 --> 10:00.440
info struct that it can then broadcast up to the widget side.

10:00.470 --> 10:07.340
So now that we know our next steps, let's get started constructing this robust and elegant system.
