WEBVTT

00:06.820 --> 00:07.780
Welcome back.

00:08.340 --> 00:15.150
Now every so often when developing a game, if you're keeping multiplayer in mind, it's important to

00:15.150 --> 00:16.620
do a multiplayer test.

00:16.650 --> 00:23.850
Now, we haven't done one in a while and this is usually where crashes and bugs come to light as we

00:23.850 --> 00:26.320
know that our code works in single player.

00:26.340 --> 00:34.170
Let's see what problems we can manifest if we run in multiplayer and we can address and fix those issues

00:34.200 --> 00:35.490
as we see them.

00:35.490 --> 00:40.200
So let's go ahead and run and very important we're going to run in debug mode.

00:41.830 --> 00:46.840
Now we're back in the editor and to play test in multiplayer, we can hit these three dots.

00:46.870 --> 00:50.230
We can increase the number of players and change our net mode.

00:50.380 --> 00:53.620
Now we can choose to play as a listen server.

00:53.620 --> 01:00.010
We can choose to play as client, which would spawn a dedicated server for us and we can connect to

01:00.010 --> 01:00.670
that.

01:01.060 --> 01:03.370
Let's first choose Listen server.

01:03.400 --> 01:08.160
We'll test that out first and we'll increase our number of players to two.

01:08.170 --> 01:10.630
So let's see what happens if we press play.

01:12.100 --> 01:17.710
Now, as soon as my client spawned in, we had a problem.

01:17.710 --> 01:23.410
So we've hit an exception right here in set dot H.

01:23.440 --> 01:26.530
Now, this is some nice debugging practice for us.

01:26.560 --> 01:34.090
We've stopped inside of one of the engine class header files, but we can check our call stack.

01:34.510 --> 01:40.750
You see, a call stack leads up to the crash or the exception when we get one.

01:40.750 --> 01:44.110
And we can always trace back to the source of the problem.

01:44.380 --> 01:48.430
So we have the tea set that we're inside of.

01:48.430 --> 01:53.710
We're inside of find index by hash and here is where our exception has occurred.

01:53.710 --> 02:00.940
And if we go one level deeper into the call stack, we see that we got there from here.

02:00.940 --> 02:02.860
We used find checked.

02:02.980 --> 02:10.720
So here in our you character class info function get class default info, we see that we're passing

02:10.720 --> 02:14.300
in an enum character class.

02:14.330 --> 02:18.440
Looks like it's the ranger type and we're calling find checked.

02:18.470 --> 02:25.550
Now checked indicates that well, we're going to get an exception if we can't find that character class

02:25.550 --> 02:26.270
information.

02:26.270 --> 02:26.900
Right.

02:26.930 --> 02:30.650
Let's go one level deeper into the call stack.

02:30.740 --> 02:34.180
And we're here in our ability system library.

02:34.190 --> 02:41.120
So we saw that we tried to call get class default info here from this character class info.

02:41.210 --> 02:45.530
Now right away I'm seeing here that character class info is null.

02:45.560 --> 02:47.270
Now why could that be?

02:47.300 --> 02:50.650
Well, we're initializing character class info here.

02:50.660 --> 02:53.000
Calling get character class info.

02:53.000 --> 02:57.500
So if we look at that function, we see that we're getting a game mode.

02:57.530 --> 03:05.420
Now game modes are only valid on the server if it's accessed from the client using say gameplay statics

03:05.420 --> 03:06.490
get game mode.

03:06.500 --> 03:13.880
This would return a null pointer and in this function, if this aura game mode pointer is null, then

03:13.880 --> 03:19.120
get character class info returns null and that's going to happen on clients.

03:19.130 --> 03:25.220
So the reason something like this works perfectly fine in a single player game, yet as soon as we start

03:25.220 --> 03:27.350
playing in multiplayer we get a crash.

03:27.350 --> 03:30.500
That's because the game mode is a null pointer.

03:30.500 --> 03:37.550
And so if we're trying to access something that's null on a client and get character class info returns

03:37.580 --> 03:45.350
null on clients, then initialize default attributes should really be checking that pointer and returning

03:45.350 --> 03:48.260
early in the case that it's a null pointer.

03:48.500 --> 03:50.020
Now where are we calling this?

03:50.030 --> 03:56.570
We're calling this from Initialized default attributes on the enemy class Initializing default attributes

03:56.570 --> 03:58.640
really should only be done on the server.

03:58.640 --> 04:01.600
So we could just place an authority check here.

04:01.610 --> 04:08.030
Now initialize default attributes if we follow the call stack is being called from init ability actor

04:08.030 --> 04:08.780
info.

04:08.810 --> 04:09.710
Now here.

04:09.710 --> 04:14.300
Still we're doing something that probably should only be done on the server right now.

04:14.300 --> 04:20.960
This trace is all the way back to Aura enemy Beginplay where we're also telling our ability system component

04:20.960 --> 04:27.290
to give startup abilities so we can prevent some nastiness from happening by thinking about how all

04:27.290 --> 04:29.450
of this works in a multiplayer setting.

04:29.450 --> 04:35.300
We really only want to give our startup abilities on the server, yet we know that the ability system

04:35.300 --> 04:37.100
component checks for authority.

04:37.100 --> 04:42.430
Even so, it'd be a good idea not to call it if we're not on the server.

04:42.440 --> 04:49.910
An inability actor info should be called on client and server, but we should take care of that null

04:49.910 --> 04:53.120
pointer in our ability system library.

04:53.120 --> 04:55.070
So let's fix a couple of these issues.

04:55.070 --> 04:59.930
I'm going to hit stop and here in Aura Enemy, let's go back up to begin play.

05:00.290 --> 05:05.090
First of all, I'd like to check for authority before giving startup abilities.

05:05.090 --> 05:13.370
So I'm going to say if has authority, if we have authority, then we'll give our startup abilities.

05:13.370 --> 05:14.360
That's fine.

05:14.510 --> 05:17.660
Next in init ability Actor info.

05:17.690 --> 05:22.370
I'd like to only initialize default attributes if we have authority.

05:24.770 --> 05:32.600
That takes care of that null pointer business as we won't be even calling these functions if we don't

05:32.600 --> 05:33.530
have authority.

05:34.260 --> 05:40.860
Let's go ahead and hit debug and see if that fixes that problem and see what other potential problems

05:40.860 --> 05:41.520
arise.

05:43.360 --> 05:43.930
Okay.

05:43.930 --> 05:45.130
I'm going to press play.

05:46.110 --> 05:50.670
And this time we have two players without any crashes.

05:50.670 --> 05:53.190
So we took care of one problem.

05:53.430 --> 05:57.930
But we should probably test out some of our gameplay mechanics and make sure they work.

05:57.930 --> 06:02.640
Before we do that, though, I'm going to change number of players to three.

06:03.630 --> 06:08.460
It's usually pretty safe to test all scenarios when the number of players is three.

06:10.990 --> 06:17.830
As each player sees the other players, the server player and the other client, and then the server

06:17.830 --> 06:19.210
sees both clients.

06:19.720 --> 06:23.620
Now we can also change the net mode to play as client.

06:23.650 --> 06:26.530
This will spawn a dedicated server.

06:26.530 --> 06:29.470
In this case, three players doesn't really matter.

06:29.470 --> 06:32.830
We can set it to two and still successfully test.

06:33.950 --> 06:37.610
So now we're playing as both clients.

06:37.640 --> 06:39.620
This player is a client.

06:40.040 --> 06:43.760
The other player is a client, and things seem to be okay.

06:45.930 --> 06:50.700
Okay, so I'm going to go back to listen server and let's see about testing out some of our gameplay

06:50.700 --> 06:51.580
mechanics.

06:51.600 --> 06:55.140
One of the more recent ones is our damage text.

06:56.150 --> 06:59.780
Well, we can also test out our damage mechanics as well.

07:00.110 --> 07:05.630
Now, I'm seeing on the client that it looks like I am causing damage.

07:07.270 --> 07:10.780
I am seeing the health bar update, which makes sense.

07:10.780 --> 07:17.170
It's linked to our attributes which are replicated, but I'm not seeing the damage text here.

07:17.200 --> 07:19.600
I am seeing it on the server.

07:21.800 --> 07:25.040
Even for my clients damage numbers.

07:25.040 --> 07:27.380
So it's kind of reversed here.

07:27.380 --> 07:32.000
We should see it on the client, those numbers, but not on the server.

07:32.090 --> 07:35.180
I don't mind that we can see the health bar everywhere.

07:35.180 --> 07:36.470
That's totally fine.

07:36.470 --> 07:40.160
I just want to see that floating text on the client and the client.

07:40.160 --> 07:42.680
Only now I'm going to go ahead and.

07:43.330 --> 07:49.330
Show both screens at the same time and hit one of these enemies with the server character.

07:50.070 --> 07:55.350
And I see the damage numbers on the server just fine, but I don't see it on the client.

07:55.350 --> 08:00.990
So really it's only the client that has the problem of not seeing its damage numbers.

08:01.410 --> 08:05.940
Okay, let's go ahead and change the net mode to play as client.

08:07.610 --> 08:08.000
Okay.

08:08.000 --> 08:15.080
And I launched a fireball and it looks like my looping sound component here is a null pointer.

08:15.080 --> 08:18.850
So that appears to be an issue as well.

08:18.860 --> 08:24.290
So it appears that our projectile has been destroyed before.

08:24.290 --> 08:27.800
It could actually construct the looping sound component.

08:27.800 --> 08:34.250
And if that's a danger, we should do a null check before accessing that pointer.

08:34.280 --> 08:40.070
I see it up here in Destroyed, so I'm going to check that here if looping sound component and I'm also

08:40.070 --> 08:46.040
going to check it down here where we're calling stop and on sphere overlap.

08:46.370 --> 08:49.340
So checking the null pointer there.

08:49.640 --> 08:50.350
Okay.

08:50.360 --> 08:54.680
Now let's think about why we're not getting our damage numbers.

08:54.770 --> 09:01.190
I'm going to close all tabs for now and open ability system and aura attribute set.

09:01.220 --> 09:06.500
We know that we have show floating text which uses gameplay statics and calls.

09:06.500 --> 09:08.120
Get player controller.

09:08.130 --> 09:10.530
Now what does this doing exactly?

09:10.560 --> 09:14.610
Well we know that show floating text is called in the server, don't we?

09:14.640 --> 09:21.030
We do because we are calling show floating text from within post gameplay effect.

09:21.030 --> 09:21.720
Execute.

09:21.750 --> 09:22.170
Now.

09:22.170 --> 09:25.200
No, I'm not saying that this only gets executed on the server.

09:25.200 --> 09:26.430
That's not what I'm saying.

09:26.430 --> 09:31.410
But what I am saying is we're calling show floating text inside of this.

09:31.440 --> 09:37.140
If check where we check if the evaluated attribute is incoming damage.

09:37.140 --> 09:39.030
Now this is a meta attribute.

09:39.030 --> 09:40.320
It's not replicated.

09:40.320 --> 09:42.480
We're only setting it on the server.

09:42.510 --> 09:47.700
That's how I know that we're on the server when we call show floating text.

09:47.700 --> 09:53.520
And if we call, get player controller passing in an index of zero on the server, we're going to get

09:53.520 --> 09:56.370
the server's player controller, right?

09:56.370 --> 10:04.710
And if we do that, then PC is the server's player controller no matter who owns this attribute set.

10:04.740 --> 10:06.030
Okay, so what?

10:06.030 --> 10:08.420
So we have the server's player controller.

10:08.430 --> 10:14.670
This of course is talking about a listen server and the controller of the player who's hosting the game.

10:15.120 --> 10:21.660
Well if we call show damage number for that player controller, we know that show damage number is a

10:21.660 --> 10:22.650
client RPC.

10:22.980 --> 10:28.440
So we would expect this show damage number to be executed on the client.

10:28.440 --> 10:35.790
But we've seen that only the player controller owned by a given client exists on that client's machine.

10:35.820 --> 10:41.550
The server controlled player controller doesn't exist on clients.

10:41.580 --> 10:42.270
No.

10:42.300 --> 10:49.380
If we want show damage number to be called on a client's machine, then we have to call show damage

10:49.380 --> 10:53.670
number from the server on the correct player controller.

10:53.670 --> 10:57.300
We can't just get the first player controller that exists.

10:57.300 --> 11:00.240
That's the server controlled player controller.

11:00.240 --> 11:03.030
So which player controller do we want?

11:03.060 --> 11:07.710
Well, we want that source character, the one who's causing the damage.

11:07.710 --> 11:09.720
We can get the controller from that.

11:09.750 --> 11:11.670
We're casting to our player controller.

11:11.670 --> 11:16.380
So instead of calling gameplay statics, get player controller instead.

11:16.380 --> 11:19.410
Let's get props dot source character.

11:19.930 --> 11:22.930
And from source character, we can get the controller.

11:23.140 --> 11:26.060
So making sure to add that last parentheses there.

11:26.080 --> 11:31.420
Now that we're getting the source character, the character who's the one responsible for launching

11:31.420 --> 11:34.300
the fireball, we're getting that controller.

11:34.330 --> 11:39.760
Now, all controllers exist on the server, but because we're getting the correct controller and calling

11:39.760 --> 11:46.900
a client RPC on it, it'll be executed on the client that owns that controller and that controller is

11:46.900 --> 11:49.000
valid on that client.

11:49.000 --> 11:55.870
So this right here, this little change should fix our problem and we should see damage numbers on the

11:55.870 --> 11:58.420
client who launched the fireball.

11:58.660 --> 12:04.870
Now we'll still see it on the server as well because show damage number will also be executed on the

12:04.870 --> 12:05.200
server.

12:05.200 --> 12:07.090
That's how client rpcs work.

12:07.120 --> 12:11.020
They'll be executed on the server but also on the owning client.

12:11.020 --> 12:18.430
So what we need to do is go to show damage number the implementation in or a player controller.

12:18.550 --> 12:22.190
So here's the show damage number implementation here.

12:22.190 --> 12:25.010
We should check if we are the local controller.

12:25.310 --> 12:30.230
So what we can do is place an end here and say is local controller.

12:30.230 --> 12:36.200
That way we'll only see that damage text if we're the local controller, if we're on the server and

12:36.200 --> 12:42.650
we're calling this on a client owned player controller then is local controller will return false and

12:42.650 --> 12:45.290
the server will not see those damage numbers.

12:46.060 --> 12:50.350
So now we should only see the damage floating text on the correct machine.

12:50.350 --> 12:55.300
So let's run in debug mode and just verify that that's going to work.

12:56.440 --> 12:59.980
Okay, so we're going to press play and I have my client here.

13:00.010 --> 13:02.530
Let's see if we can see the damage numbers.

13:02.530 --> 13:05.440
And it looks like our fireballs are now passing through.

13:05.440 --> 13:07.180
The enemies, they're not hitting them.

13:07.330 --> 13:09.820
So let's see what happened.

13:10.000 --> 13:12.060
We'll go back to our projectile.

13:12.070 --> 13:15.400
We can place a break point in on sphere overlap here.

13:16.800 --> 13:22.620
I'm going to set this back to play as listen server and I'm going to launch a fireball.

13:23.910 --> 13:30.750
Okay, so on sphere overlap works only if we have authority should we apply the gameplay effect and

13:30.750 --> 13:31.800
destroy.

13:31.830 --> 13:32.070
Okay.

13:32.070 --> 13:34.800
I'm going to remove that breakpoint and resume.

13:37.350 --> 13:39.570
Looks like I did cause some damage.

13:39.600 --> 13:42.360
Okay, so we're fine on Allison Server.

13:42.360 --> 13:46.080
Let's play as client for a dedicated server build.

13:49.920 --> 13:50.310
Okay.

13:50.310 --> 13:55.140
So on a dedicated server, it looks like nothing is happening.

13:57.240 --> 14:01.620
So we can place that break point back we have on sphere overlap.

14:01.650 --> 14:03.660
Other actor is the self here.

14:03.660 --> 14:05.640
So we're going to go ahead and resume.

14:11.130 --> 14:16.380
And it looks like after hitting the self, I don't think we ever get to destroy.

14:16.380 --> 14:17.540
But let's see.

14:17.550 --> 14:19.830
Yes, we are getting to destroy actually.

14:19.830 --> 14:21.780
So here's what's happening.

14:21.900 --> 14:25.650
We're destroying our projectile is destroying the self.

14:25.980 --> 14:33.690
But what we should be doing instead of destroying the self is we should make sure that the other actor

14:33.690 --> 14:41.340
has an ability system component and that it's not the actor responsible for this damage effect.

14:41.340 --> 14:42.390
Spec handle.

14:42.420 --> 14:52.140
Remember, the spec handle has data including an effect context and the effect context has lots of things,

14:52.140 --> 14:54.120
including the effect causer.

14:54.420 --> 14:59.190
So what we should do is we should check the effect causer in this effect context as well.

14:59.190 --> 15:06.210
If this effect causer is the other actor and that's the case that's getting us into trouble, we should

15:06.210 --> 15:07.160
not destroy.

15:07.170 --> 15:11.800
We should also not apply the gameplay effect spec to self either.

15:12.190 --> 15:16.180
So in other words, on sphere overlap should do nothing in that case.

15:16.180 --> 15:24.910
So why don't we check the effect causer in our effect spec handle against other actor and just return

15:24.910 --> 15:28.020
early out of on sphere overlap if that's the case.

15:28.030 --> 15:37.210
So here in on sphere overlap we're going to take our damage effect spec handle dot data dot get and

15:37.210 --> 15:39.160
we want the effect context.

15:39.160 --> 15:40.960
So we're going to call get context.

15:40.960 --> 15:45.130
And from the context we want to check our effect causer.

15:45.130 --> 15:47.200
So we're going to call get effect causer.

15:47.440 --> 15:52.690
If the effect causer is equal to other actor, we don't want to do anything.

15:52.690 --> 15:57.850
So we're going to say equals other actor and we're going to place this in an if statement.

15:59.980 --> 16:01.360
And we'll return.

16:01.960 --> 16:02.650
Okay.

16:02.650 --> 16:09.040
Now, we should also check this pointer because where are we setting the damage effect spec handle?

16:09.070 --> 16:16.840
Well, we're doing that in abilities or a projectile spell and we're really only setting that if we're

16:16.870 --> 16:17.950
on the server.

16:17.980 --> 16:25.000
We return early way before doing anything, such as creating the effects back and setting it on the

16:25.000 --> 16:25.960
projectile.

16:25.960 --> 16:28.150
And that's not a replicated variable.

16:28.150 --> 16:35.200
So on clients, this damage effect spec handle will not be valid, at least its data will not be valid.

16:35.200 --> 16:44.650
So what we're going to do is we're going to check damage effect spec handle data dot is valid and we'll

16:44.650 --> 16:46.900
make this an end statement here.

16:47.140 --> 16:52.150
Okay, let's hit debug and let's see what happens on a dedicated server.

16:54.450 --> 16:59.490
Okay, We're going to make sure we're on a let's play as a client.

17:02.430 --> 17:05.250
I'm going to launch one of these.

17:07.340 --> 17:08.090
Okay.

17:08.090 --> 17:09.020
So.

17:10.160 --> 17:13.420
Looks like we might be missing.

17:13.430 --> 17:17.900
Now, these are both clients, so I can test on either one.

17:17.900 --> 17:20.300
It looks like we're going clear over the head.

17:21.890 --> 17:25.460
So I'm going to go ahead and pause and see.

17:26.210 --> 17:26.750
Yes.

17:26.750 --> 17:28.190
Looks like we're going over the head.

17:28.220 --> 17:33.680
That's actually easily fixable if we go into our projectile spell.

17:33.710 --> 17:37.430
And right here we're zeroing our rotation.

17:37.430 --> 17:42.800
And I'd actually like to make these projectiles homing projectiles.

17:42.800 --> 17:48.200
Once we start working on our abilities a little bit more and upgrading them per level.

17:48.200 --> 17:55.820
But for now, I'm going to go ahead and not zero out the pitch as I don't want these to just go over

17:55.820 --> 18:02.750
the head of our enemies because there's always a discrepancy between client and server.

18:02.750 --> 18:08.810
So if our socket location is a little bit high, if it's a little bit off timing from what we see on

18:08.810 --> 18:15.920
clients, then we might be launching too high, but we don't have to zero out the rotation pitch.

18:15.920 --> 18:22.670
What we can do is just set the rotation so that it's aiming straight for the enemy and then we should

18:22.670 --> 18:25.690
see that projectile hit the enemy.

18:25.700 --> 18:27.480
So let's see how this works.

18:29.640 --> 18:31.330
Okay, we're going to press play.

18:31.350 --> 18:34.060
We're playing as a dedicated server now.

18:34.080 --> 18:36.720
I'm going to launch at these enemies.

18:36.720 --> 18:37.750
And there we go.

18:37.750 --> 18:41.280
It looks like we are getting our fireball.

18:41.280 --> 18:43.470
We're getting our damage numbers.

18:43.470 --> 18:46.260
We're not seeing the damage numbers on the other client.

18:46.260 --> 18:50.160
And if we play as a listen server.

18:53.750 --> 18:57.020
Then we can try on the left.

18:59.790 --> 19:02.850
We see the damage number on the left, but not on the right.

19:04.010 --> 19:06.110
And if we launch on the right.

19:07.280 --> 19:10.700
We see the damage number on the right, but not on the left.

19:11.490 --> 19:12.180
All right.

19:12.180 --> 19:14.610
So things are looking pretty good now.

19:14.610 --> 19:21.510
I'm noticing a little bit of a weird sound when my projectiles hit here on the client side.

19:23.640 --> 19:27.450
It sounds kind of like I'm getting more than one sound.

19:28.400 --> 19:30.860
Yeah, that's definitely more than one sound.

19:31.410 --> 19:34.680
Which means probably more than one impact effect.

19:36.300 --> 19:39.300
I don't think it's happening on the server.

19:41.340 --> 19:46.850
Think it's only happening on the client so we can diagnose this issue in our aura projectile.

19:46.860 --> 19:55.770
Now we are playing a sound and spawning our system in multiple places and every time we do so, what

19:55.770 --> 20:00.540
we're doing is we're setting a be hit equal to true if we're not on the server.

20:00.900 --> 20:08.040
So a way that we can be sure that we only get this played once is if that be hit has ever been set to

20:08.070 --> 20:08.340
true.

20:08.370 --> 20:13.470
We just don't play any sounds so we can say if not be hit.

20:17.240 --> 20:19.670
Then we can play the sound spawn.

20:19.700 --> 20:23.210
The particles, basically all the impact effects here.

20:23.390 --> 20:29.650
So we can do that here and we're already checking if not, be hit and destroyed.

20:29.660 --> 20:33.200
So I think that is going to take care of it.

20:33.200 --> 20:39.890
But we can, of course, test it out, see if we don't get that weird double sound when our projectile

20:39.890 --> 20:40.490
hits.

20:43.260 --> 20:49.770
Okay, we're going to press play and I'm going to just use a fireball on the client side.

20:51.310 --> 20:52.960
That sounds a lot better.

20:53.750 --> 20:55.340
Yes, much better.

20:57.910 --> 20:58.750
Okay, cool.

20:58.750 --> 21:03.580
So things are working on client and server in multiplayer.

21:04.530 --> 21:07.170
We know they're working in stand alone mode.

21:13.200 --> 21:17.180
So that was a good test, some good debugging practice.

21:17.190 --> 21:20.730
I'm going to leave this as play as listen server for now.

21:20.730 --> 21:26.700
We'll leave the number of players at two and yes, we can, I believe hit each other with fireballs

21:26.700 --> 21:28.280
and do damage to each other.

21:28.290 --> 21:34.170
Looks like PvP is working even though this isn't a PvP project.

21:34.170 --> 21:35.970
That's not something we're going to focus on.

21:35.970 --> 21:38.010
But yes, we can do damage to each other.

21:38.010 --> 21:43.350
It looks like we can't target each other because we're checking for the enemy interface.

21:43.350 --> 21:49.020
We could easily check for the combat interface instead and target each other if we really wanted to.

21:49.020 --> 21:54.480
But I'm not interested in implementing PvP and all those complexities for this project.

21:54.510 --> 22:02.070
Not at the moment, but just showing that when the fireball does hit anything, that's not the effect

22:02.070 --> 22:03.990
causer, it does cause damage.

22:03.990 --> 22:06.510
So that works as well.

22:06.510 --> 22:09.270
So excellent learning opportunity here.

22:09.270 --> 22:16.360
It's always great to test things out and it's a good idea to make sure things work in multiplayer periodically

22:16.360 --> 22:19.210
if you're programming with multiplayer in mind.

22:19.210 --> 22:26.410
So with all those fixes, we're ready to continue with the course and we have lots of other things we

22:26.410 --> 22:27.490
want to implement.

22:27.520 --> 22:35.020
Not only do we want more gameplay abilities, but we also want a spell menu so that we can change our

22:35.020 --> 22:37.990
abilities, remap them to different inputs.

22:37.990 --> 22:39.490
We want to upgrade our abilities.

22:39.490 --> 22:43.240
We want to level them up so that they have stronger behaviors.

22:43.240 --> 22:48.790
We want our character to be able to level up and gain experience points and show that in the HUD.

22:48.790 --> 22:54.340
And when the character levels up, we're going to want to be able to upgrade our attributes.

22:54.340 --> 23:00.970
We have this attribute points which we don't even have the text set for or any value there.

23:00.970 --> 23:04.300
Once we have attribute points, we want to upgrade our attributes.

23:04.330 --> 23:08.350
We also are going to want to be able to upgrade our spells as well.

23:08.350 --> 23:09.910
So we have lots of things to do.

23:09.910 --> 23:15.880
But before we do those things, it's time for our enemies to start actually running around and attacking

23:15.880 --> 23:18.520
us and trying to do damage back to us.

23:18.520 --> 23:21.670
That way we can test things out with dynamic enemies.

23:21.700 --> 23:29.980
It's important to have at least some basic enemy functionality as we implement the rest of our skills,

23:29.980 --> 23:36.610
because our skills are going to depend on and have very much have a lot to do with our enemies.

23:36.610 --> 23:44.320
So we're going to flesh out some AI for our enemies and then we'll continue on making more complex abilities

23:44.320 --> 23:46.780
and diving deeper into the ability system.

23:46.780 --> 23:52.030
We're also going to incorporate gas into our AI for our enemies.

23:52.030 --> 23:54.730
So we'll be doing that all in the next section.

23:54.730 --> 23:58.630
So great job on this section and I'll see you in the next video.
