WEBVTT X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 00:00:16.290 --> 00:00:19.560 SPEAKER 1: All right, welcome to GD 50, lecture 7. 00:00:19.560 --> 00:00:22.950 This week we'll be talking about one of my favorite franchises of all time, 00:00:22.950 --> 00:00:24.870 a core part of my childhood-- 00:00:24.870 --> 00:00:27.850 Pokemon as shown by the Poke Ball on the screen there. 00:00:27.850 --> 00:00:32.280 So back in 1997 I think it was, the first Pokemon 00:00:32.280 --> 00:00:34.004 game was released, Red and Blue. 00:00:34.004 --> 00:00:36.420 I believe it was released a year earlier in Japan where it 00:00:36.420 --> 00:00:39.661 was released as Red, Blue, and Green. 00:00:39.661 --> 00:00:42.160 And the overall goal of the game was fairly straightforward. 00:00:42.160 --> 00:00:43.284 You were a Pokemon trainer. 00:00:43.284 --> 00:00:47.250 Your goal was to go out into the world and try and capture 00:00:47.250 --> 00:00:51.900 any number of 151 different types of these creatures called 00:00:51.900 --> 00:00:56.460 Pokemon that were based on a whole bunch of different types of creatures. 00:00:56.460 --> 00:01:00.170 Shown in the screenshot here, there's a Weepinbell fighting and Geodude. 00:01:00.170 --> 00:01:03.270 A Geodude was a rock type, Weepinbeel was a grass type. 00:01:03.270 --> 00:01:05.280 You had different types of Pokemon. 00:01:05.280 --> 00:01:08.340 When they fight each other, some types were better than other types, 00:01:08.340 --> 00:01:12.572 like this sort of very large rock, paper, scissors relationship. 00:01:12.572 --> 00:01:14.280 And it was just a very addicting formula. 00:01:14.280 --> 00:01:17.100 You'd have a team of these creatures that you had caught and raised 00:01:17.100 --> 00:01:20.670 and battled, and you'd fight other trainers. 00:01:20.670 --> 00:01:23.490 And the awesome part of this was you could go 00:01:23.490 --> 00:01:25.440 and you could actually fight your friends, 00:01:25.440 --> 00:01:28.200 or trade Pokemon with your friends that they had caught. 00:01:28.200 --> 00:01:30.200 And you would often share stories back and forth 00:01:30.200 --> 00:01:32.991 about the different rare creatures that you would have encountered, 00:01:32.991 --> 00:01:34.170 and all sorts of things. 00:01:34.170 --> 00:01:37.170 You'd have a customized party that was sort of a part of you. 00:01:37.170 --> 00:01:38.700 And so this is Pokemon Red. 00:01:38.700 --> 00:01:40.160 The series has evolved over time. 00:01:40.160 --> 00:01:43.368 This is a screenshot of Gold and Silver, which was released a couple of years 00:01:43.368 --> 00:01:45.150 afterwards for the Gameboy Color. 00:01:45.150 --> 00:01:48.120 Again, this was released for the regular Gameboy. 00:01:48.120 --> 00:01:51.180 Gold and Silver introduced a bunch of new features including breeding, 00:01:51.180 --> 00:01:53.310 and a day, night cycle, and a lot of other things 00:01:53.310 --> 00:01:55.310 that became part of the core series. 00:01:55.310 --> 00:01:58.500 Here is Ruby and Sapphire, which was for the Gameboy Advance 00:01:58.500 --> 00:02:01.500 and got a significant graphical update, but the core formula 00:02:01.500 --> 00:02:03.330 stayed much the same. 00:02:03.330 --> 00:02:08.130 Here is Diamond and Pearl, which is for the DS, which 00:02:08.130 --> 00:02:11.730 it made use of two screens, as seen on the top and bottom there. 00:02:11.730 --> 00:02:14.460 Here is Black and White, which was another step forward 00:02:14.460 --> 00:02:18.060 in that it introduced three dimensional graphics for the over world, 00:02:18.060 --> 00:02:21.960 so you could actually see some sort of 3D for the first time in the franchise. 00:02:21.960 --> 00:02:26.230 And then more recently, we've seen for the 3DS, games like X and Y, 00:02:26.230 --> 00:02:29.940 which is shown here, and Omega Sapphire, Alpha Ruby-- 00:02:29.940 --> 00:02:33.990 Alpha Sapphire and Omega Ruby, and Moon and Sun. 00:02:33.990 --> 00:02:37.680 And so this is a great illustration of why 00:02:37.680 --> 00:02:41.700 the RPG genre of video games, role playing game, 00:02:41.700 --> 00:02:44.880 even though it's sort of its own unique take on the formula. 00:02:44.880 --> 00:02:47.760 But it allows us to, we can sort of dissect this and take a look 00:02:47.760 --> 00:02:51.210 at what makes an RPG and what makes a Pokemon game altogether 00:02:51.210 --> 00:02:52.860 for a nice cool demonstration. 00:02:52.860 --> 00:02:54.943 So today, we'll be talking about a few new things. 00:02:54.943 --> 00:02:58.800 We'll be doing things a lot differently in this lecture example 00:02:58.800 --> 00:03:03.060 relative to other examples, because we're transitioning away from the state 00:03:03.060 --> 00:03:07.500 machine and talking about a construct called the state stack, which 00:03:07.500 --> 00:03:10.800 is effectively a more advanced version of the state machine. 00:03:10.800 --> 00:03:15.420 Whereas before, we had a state machine that was in one state at a time, 00:03:15.420 --> 00:03:19.560 whereby we could be in the play state or the start state or what 00:03:19.560 --> 00:03:22.290 not, we can now actually have multiple states 00:03:22.290 --> 00:03:25.920 that exist in parallel that are on a stack of data structure, which you've 00:03:25.920 --> 00:03:29.110 seen in CS 50 if you've taken, where we can have, 00:03:29.110 --> 00:03:32.070 for example, the field state, the play state at the very bottom, 00:03:32.070 --> 00:03:36.180 which is always there, and then we can push states onto the stack 00:03:36.180 --> 00:03:39.120 as we need to for example, a dialog state 00:03:39.120 --> 00:03:41.410 so that we can actually display some dialog, 00:03:41.410 --> 00:03:44.940 some text to the screen without getting rid of the play state 00:03:44.940 --> 00:03:46.720 that we had there before. 00:03:46.720 --> 00:03:50.220 It allows us to render multiple things at the same time, 00:03:50.220 --> 00:03:52.530 and then also return back to prior states, 00:03:52.530 --> 00:03:55.060 rather than completely create new states every time 00:03:55.060 --> 00:03:57.040 we want to make a transition. 00:03:57.040 --> 00:03:58.860 We'll be talking about turn based systems. 00:03:58.860 --> 00:04:02.970 So an RPGs like Pokemon and others, there 00:04:02.970 --> 00:04:06.210 are often battle systems that are usually 00:04:06.210 --> 00:04:09.090 turn based in this particular genre where you're fighting-- you have 00:04:09.090 --> 00:04:11.605 one team or one character fighting against against one other team or one 00:04:11.605 --> 00:04:13.980 other character, and you take turns fighting each other. 00:04:13.980 --> 00:04:16.846 And you have an indefinite amount of time to make your decision 00:04:16.846 --> 00:04:18.720 and then form some sort of strategy as to how 00:04:18.720 --> 00:04:20.490 you want to approach the problem. 00:04:20.490 --> 00:04:23.340 We'll be taking a look at a very primitive turn based system, 00:04:23.340 --> 00:04:26.610 but a fully functional one today. 00:04:26.610 --> 00:04:32.250 Another huge aspect of this genre is graphical user interfaces or GUIs 00:04:32.250 --> 00:04:33.510 as they're shortened. 00:04:33.510 --> 00:04:37.740 Things like panels, and scroll bars, and text boxes, and menus, all 00:04:37.740 --> 00:04:42.270 sorts of these things that allow us to get a more visual sort of look 00:04:42.270 --> 00:04:46.680 at our data, and allow us to navigate a much more complex game ecosystem more 00:04:46.680 --> 00:04:47.670 efficiently. 00:04:47.670 --> 00:04:50.820 And to tie it all together, RPG mechanics at large, 00:04:50.820 --> 00:04:53.700 we'll be looking at things like leveling up and experience 00:04:53.700 --> 00:04:57.720 and how to calculate the damage that one party does to the other party 00:04:57.720 --> 00:04:59.810 throughout the course of a battle. 00:04:59.810 --> 00:05:04.170 And so it will be a fairly complicated set of examples, 00:05:04.170 --> 00:05:08.580 but fairly illustrative of the genre as a whole. 00:05:08.580 --> 00:05:11.790 So I'd like to demonstrate sort of the example that I put together. 00:05:11.790 --> 00:05:15.040 If I could get a volunteer from the audience to come up and take a look. 00:05:15.040 --> 00:05:18.120 Tony that'd be awesome, thank you so much. 00:05:18.120 --> 00:05:23.850 So this is my simple but fully featured, more or less, demonstration of Pokemon. 00:05:23.850 --> 00:05:27.760 So if you want to enter or return. 00:05:27.760 --> 00:05:29.630 So this is a-- 00:05:29.630 --> 00:05:30.930 so here we have a-- 00:05:30.930 --> 00:05:35.040 we can see right off the bat, we have a text box and a play state 00:05:35.040 --> 00:05:36.340 like we did before. 00:05:36.340 --> 00:05:41.034 So this text box is actually a state that's layered above the place. 00:05:41.034 --> 00:05:43.950 So you can see it has some instructions about, if you want to press P, 00:05:43.950 --> 00:05:45.120 you can heal your Pokemon. 00:05:45.120 --> 00:05:46.730 You can press Enter to dismiss. 00:05:46.730 --> 00:05:47.880 So if you go ahead and press Enter, you'll 00:05:47.880 --> 00:05:49.620 be able to actually move around now. 00:05:49.620 --> 00:05:52.500 And so something to note is before, input was actually 00:05:52.500 --> 00:05:57.060 halted while the dialogue was on the top of the screen for the play state. 00:05:57.060 --> 00:06:01.110 You're actually not allowed to access or update this bottom state, 00:06:01.110 --> 00:06:05.220 because the state stack is only allowing input to the top state. 00:06:05.220 --> 00:06:09.990 And so I have limited the play here just to this box, 00:06:09.990 --> 00:06:13.830 but if we walk in the tall grass down here, in Pokemon, 00:06:13.830 --> 00:06:15.630 in order to actually initiate an encounter 00:06:15.630 --> 00:06:19.554 with another Pokemon or another wild Pokemon, you walk in the grass. 00:06:19.554 --> 00:06:20.970 So here we've walked in the grass. 00:06:20.970 --> 00:06:25.500 There's a random chance for this to happen, there's a 1 in 10 chance 00:06:25.500 --> 00:06:26.370 basically. 00:06:26.370 --> 00:06:28.310 So it's saying that a wild Bamboon appeared. 00:06:28.310 --> 00:06:29.550 So a wild creature appeared. 00:06:29.550 --> 00:06:32.550 He's level 5, we're level 5, should be a fairly even battle. 00:06:32.550 --> 00:06:34.982 So you can press Enter, and it will say go 00:06:34.982 --> 00:06:37.440 the name of your Pokemon, which is an Aardart in this case, 00:06:37.440 --> 00:06:39.410 and it's randomly allocated at the moment. 00:06:39.410 --> 00:06:41.160 So go ahead and press Enter one more time. 00:06:41.160 --> 00:06:43.360 Now we can see on the bottom right, we have a menu. 00:06:43.360 --> 00:06:46.290 So we can fight or we can run, so those two choices. 00:06:46.290 --> 00:06:47.686 So we can go ahead and fight. 00:06:47.686 --> 00:06:49.560 So we fight, whichever Pokemon has the higher 00:06:49.560 --> 00:06:51.900 speed will go first and do damage. 00:06:51.900 --> 00:06:55.287 We obviously, do a lot more damage, but he's a little bit faster, 00:06:55.287 --> 00:06:56.370 so he's going to go first. 00:06:56.370 --> 00:06:57.453 So we fight one more time. 00:07:00.130 --> 00:07:03.050 We should be able to knock him out. 00:07:03.050 --> 00:07:06.252 So as soon as we do, we get a victory message, we get a victory song. 00:07:06.252 --> 00:07:08.460 If we press Enter, we'll actually get some experience 00:07:08.460 --> 00:07:10.320 for defeating that enemy. 00:07:10.320 --> 00:07:12.837 So we've got quite a bit of experience, we got 65 XP. 00:07:12.837 --> 00:07:15.420 In that bottom bar, we can see we have all these GUI elements, 00:07:15.420 --> 00:07:19.380 we've got a panel here, we have text boxes, we have progress bars, 00:07:19.380 --> 00:07:24.360 all these pieces are coming together to give us sort of this turn based system. 00:07:24.360 --> 00:07:27.420 And so after this, we may level up just to demonstrate 00:07:27.420 --> 00:07:31.803 leveling, which is part of the RPG mechanic side of this game. 00:07:31.803 --> 00:07:34.960 So we have to press this one more time. 00:07:34.960 --> 00:07:35.770 We did, perfectly. 00:07:35.770 --> 00:07:36.970 So they leveled up. 00:07:36.970 --> 00:07:44.300 And so now we're level 6, so we can see the 6 changed above our progress bars. 00:07:44.300 --> 00:07:46.300 So now will be a little bit stronger every time. 00:07:46.300 --> 00:07:49.258 And the stats aren't shown here, it's actually a part of the assignment 00:07:49.258 --> 00:07:52.630 is to create a menu that will actually show you how you leveled up, 00:07:52.630 --> 00:07:54.550 what stats actually increased. 00:07:54.550 --> 00:07:57.400 But underneath the hood, behind the scenes, 00:07:57.400 --> 00:07:59.680 you actually are getting stat increases. 00:07:59.680 --> 00:08:03.250 And so here we can see that if we our HP goes all the way down to zero, 00:08:03.250 --> 00:08:04.090 we faint. 00:08:04.090 --> 00:08:06.730 And when we faint, the screen instead of fading to white 00:08:06.730 --> 00:08:09.063 will actually fade to black to illustrate the difference 00:08:09.063 --> 00:08:11.040 between the two transitions. 00:08:11.040 --> 00:08:13.760 And so that we can keep playing indefinitely, 00:08:13.760 --> 00:08:16.360 the game will restore your Pokemon back to full health. 00:08:16.360 --> 00:08:18.274 And so this will go on forever. 00:08:18.274 --> 00:08:20.440 This is effectively what the simulator is, it's just 00:08:20.440 --> 00:08:22.480 a simple series of infinite battles. 00:08:22.480 --> 00:08:24.450 There are random Pokemon in the grass. 00:08:24.450 --> 00:08:27.880 There's five total that you can fight. 00:08:27.880 --> 00:08:30.172 But all the core pieces of what make the game are here. 00:08:30.172 --> 00:08:31.879 So actually, let's illustrate running too 00:08:31.879 --> 00:08:34.850 if you wouldn't mind, just so that we can see if there is a difference. 00:08:34.850 --> 00:08:37.710 So we can actually flee, and then battle we'll get cut short there. 00:08:37.710 --> 00:08:39.880 We won't get any XP, we won't faint, but we still 00:08:39.880 --> 00:08:41.419 get taken back to the play state. 00:08:41.419 --> 00:08:43.090 So that's all for the Pokemon demo. 00:08:43.090 --> 00:08:45.925 Thanks so much Tony for coming up to demo it. 00:08:45.925 --> 00:08:53.427 Well, there's a lot of pieces involved here, but as we will see, 00:08:53.427 --> 00:08:56.260 once we have a lot of these sort of foundational pieces implemented, 00:08:56.260 --> 00:09:00.040 it's not too difficult to start layering more and more of these 00:09:00.040 --> 00:09:02.860 onto the game to make it even more rich. 00:09:02.860 --> 00:09:05.562 In fact, the assignment is to-- 00:09:05.562 --> 00:09:08.020 and we'll see this at the end, I'll recap this at the end-- 00:09:08.020 --> 00:09:12.040 but the assignments goal is for you to implement a menu-- 00:09:12.040 --> 00:09:16.300 similar to the menu that we saw where fight and run were shown-- 00:09:16.300 --> 00:09:19.330 that will show you what your current stat is for each of your stats, 00:09:19.330 --> 00:09:22.080 there's attack, defense, speed, and your HP. 00:09:22.080 --> 00:09:25.960 It will show you what your stat is before leveling, the amount 00:09:25.960 --> 00:09:28.400 that it will increase by, and then the final amount, 00:09:28.400 --> 00:09:31.570 which is sort of similar to how the actual Pokemon games work, 00:09:31.570 --> 00:09:35.230 so you can see rather than just seeing, oh I increased my level from 5 to 6, 00:09:35.230 --> 00:09:38.692 6 to 7, you can see, oh, my strength increased from 12 to 14. 00:09:38.692 --> 00:09:41.650 I'm a little bit stronger, I'm going to do more damage on the next play 00:09:41.650 --> 00:09:43.240 through. 00:09:43.240 --> 00:09:47.080 So our goal here, we're going to take a look at the field state, the play 00:09:47.080 --> 00:09:49.190 state, and the battle state. 00:09:49.190 --> 00:09:53.370 And there's a common dichotomy in most of these sorts of games, 00:09:53.370 --> 00:09:55.930 be it Final Fantasy, or Dragon Quest, or Pokemon 00:09:55.930 --> 00:09:58.710 where there is a field, where you are walking around, 00:09:58.710 --> 00:10:02.440 you're character interacting with a game world with NPCs, going through towns, 00:10:02.440 --> 00:10:03.650 and what have you. 00:10:03.650 --> 00:10:05.844 And then a battle mode, sort of a battle state 00:10:05.844 --> 00:10:08.260 where you're actually fighting against some sort of enemy, 00:10:08.260 --> 00:10:11.060 or a series of enemies, a party or a single creature. 00:10:11.060 --> 00:10:14.080 And so we've implemented simple versions of both of these to illustrate 00:10:14.080 --> 00:10:17.770 and also the transitions between them. 00:10:17.770 --> 00:10:21.100 Before we start, I want to make another sort of plug 00:10:21.100 --> 00:10:26.050 for this howtomakeanrpg.com, this book, I actually learned a lot from this 00:10:26.050 --> 00:10:28.510 and about using LUA in the context of game development. 00:10:28.510 --> 00:10:30.926 And I pitched this I think in one of the earlier lectures, 00:10:30.926 --> 00:10:34.570 but if you want a deeper dive into a lot of these constructs, 00:10:34.570 --> 00:10:38.320 and to sort of get a sense for how you might do something like cut scenes, 00:10:38.320 --> 00:10:42.162 or more complicated battle layouts, and a lot more like-- 00:10:42.162 --> 00:10:44.620 it goes into a lot of detail about a lot of awesome things, 00:10:44.620 --> 00:10:45.620 definitely check it out. 00:10:45.620 --> 00:10:49.060 It's not free, but if you're interested in this genre, which I am, 00:10:49.060 --> 00:10:50.880 it's definitely worthwhile. 00:10:50.880 --> 00:10:53.350 Here's what the sprite sheets look like that we'll be 00:10:53.350 --> 00:10:55.750 using for this sort of demonstration. 00:10:55.750 --> 00:10:58.586 The Pokemon aside, which are individual textures. 00:10:58.586 --> 00:11:00.460 Here we're using a simple sprite sheet, which 00:11:00.460 --> 00:11:03.280 just has a bunch of tiles, most of which we did not use. 00:11:03.280 --> 00:11:08.620 Note that the bush, the tall grass is not on any sort of background. 00:11:08.620 --> 00:11:13.030 And therefore, we need to layer, basically 00:11:13.030 --> 00:11:17.260 have two separate tile maps as opposed to one, which we didn't do last time. 00:11:17.260 --> 00:11:22.180 And we were reusing the sprite sheet that we used in the Zelda lecture. 00:11:22.180 --> 00:11:24.970 Before, we used it for all the enemies, the skeletons, ghosts, 00:11:24.970 --> 00:11:26.090 and slimes, et cetera. 00:11:26.090 --> 00:11:28.750 But now we're actually using it for the PCs that it contains. 00:11:28.750 --> 00:11:34.060 Specifically, just the male NPC here, which is our main character. 00:11:34.060 --> 00:11:37.870 The foundational class that we're using in this lecture 00:11:37.870 --> 00:11:42.130 that sort of everything else revolves around and makes this work 00:11:42.130 --> 00:11:44.170 is the state stack. 00:11:44.170 --> 00:11:49.560 And so before, what we had was a state machine, right, 00:11:49.560 --> 00:11:51.530 where we were in one state at a time. 00:11:51.530 --> 00:11:55.090 So you can almost think of it like, we have a box here, 00:11:55.090 --> 00:11:57.190 and it just has one socket. 00:11:57.190 --> 00:11:59.710 And then we're always looking at this one socket, 00:11:59.710 --> 00:12:02.350 whether it's the play state, or the battle state, 00:12:02.350 --> 00:12:05.500 or a transition of some kind. 00:12:05.500 --> 00:12:08.710 And now we're transitioning into the idea of, instead, 00:12:08.710 --> 00:12:14.740 of just one state that we can only see at once, we'll make it a stack. 00:12:14.740 --> 00:12:18.640 And so what we can do with this is, rather than just having one, 00:12:18.640 --> 00:12:22.150 we can therefore render multiple states at a time, right? 00:12:22.150 --> 00:12:27.460 So let's say this is like the field, right, or the play state. 00:12:27.460 --> 00:12:31.540 And then maybe this is like a dialogue, or something, right? 00:12:31.540 --> 00:12:34.680 Like we saw before in the field, we had a text box. 00:12:34.680 --> 00:12:37.460 We can actually layer things on top of each other. 00:12:37.460 --> 00:12:42.670 And then maybe this is like a fade out, right, or a fade in. 00:12:42.670 --> 00:12:45.520 So we start with the play state maybe, and we're walking around, 00:12:45.520 --> 00:12:47.320 and we interact with in NPC. 00:12:47.320 --> 00:12:50.590 Rather than transition the play state to a dialog state, 00:12:50.590 --> 00:12:55.360 which would, in our previous model, completely eliminate the play state, 00:12:55.360 --> 00:12:58.960 because there's only one state that could be active at a time. 00:12:58.960 --> 00:13:02.290 Now we just render, however many states we have in our stack, 00:13:02.290 --> 00:13:05.660 we just render them sequentially based on the order that they were popped in. 00:13:05.660 --> 00:13:09.610 We would rendered this first, we basically render from the bottom up. 00:13:09.610 --> 00:13:12.130 Render the play state, then the dialogue, then the fade in. 00:13:12.130 --> 00:13:15.421 And this will have the effect of doing a whole bunch of different things, which 00:13:15.421 --> 00:13:17.410 we'll see in the distro. 00:13:17.410 --> 00:13:21.430 But we only really ever need to update one state at a time, 00:13:21.430 --> 00:13:26.620 right, because if we have the play state active and the dialog state active 00:13:26.620 --> 00:13:29.950 and the fade in state active, in this order, as a stack, 00:13:29.950 --> 00:13:33.886 right, we were pushing the operation for pushing for getting something 00:13:33.886 --> 00:13:36.010 onto the stack is called a push, and getting it off 00:13:36.010 --> 00:13:38.140 is called a pop if unfamiliar. 00:13:38.140 --> 00:13:41.530 If we're pushing all of these states on, then usually, 00:13:41.530 --> 00:13:44.654 we only need to update whatever's on top, right? 00:13:44.654 --> 00:13:46.570 If there's no fade in for example, and we only 00:13:46.570 --> 00:13:49.300 have a dialog state active, or a dialogue and a place 00:13:49.300 --> 00:13:53.110 state in that order top to bottom, then we usually 00:13:53.110 --> 00:13:55.782 don't want him update what's going on in the play state. 00:13:55.782 --> 00:13:58.240 We're only concerned with the dialogue that's taking place. 00:13:58.240 --> 00:14:00.050 We only want that to take input. 00:14:00.050 --> 00:14:02.050 And when we press Spacebar, Enter, or whatever 00:14:02.050 --> 00:14:06.340 button clears that dialog state, we pop it off, right, 00:14:06.340 --> 00:14:08.070 and then we're back to the play state. 00:14:08.070 --> 00:14:10.810 Then we're just updating the play state. 00:14:10.810 --> 00:14:14.649 And so being able to update just what's on top while 00:14:14.649 --> 00:14:16.690 being able to render everything that's on bottom. 00:14:16.690 --> 00:14:18.760 And this doesn't hold true for all game formulas, 00:14:18.760 --> 00:14:22.640 there's certainly some games where you can have a dialogue and a play state 00:14:22.640 --> 00:14:28.050 both get updated, but that's still using a state stack of sorts, 00:14:28.050 --> 00:14:31.780 you're just then updating things in a top down way. 00:14:31.780 --> 00:14:35.530 But this allows us to do all kinds of things like transitions, 00:14:35.530 --> 00:14:38.440 and preserving-- like for example, the fact that we have a play state 00:14:38.440 --> 00:14:40.840 and we can pop a battle state on top of that, 00:14:40.840 --> 00:14:43.270 where we don't see the play state underneath it, 00:14:43.270 --> 00:14:45.577 we only see the battle state, and that's all updating. 00:14:45.577 --> 00:14:47.410 But it is we pop the battle state off, we're 00:14:47.410 --> 00:14:49.510 right back where we just were in the play state. 00:14:49.510 --> 00:14:53.860 It's preserved its state, for lack of a better word, from before. 00:14:53.860 --> 00:14:58.750 And this is something that this model affords us comfortably. 00:14:58.750 --> 00:15:01.120 And so that's sort of the foundational class that's 00:15:01.120 --> 00:15:03.190 implemented in this distro, which will allow 00:15:03.190 --> 00:15:06.080 us to do all kinds of awesome things. 00:15:06.080 --> 00:15:09.580 So let's go ahead and take a look at what that looks like. 00:15:09.580 --> 00:15:11.500 I have state stack open here. 00:15:11.500 --> 00:15:15.460 So state stack has just a set of states here. 00:15:18.430 --> 00:15:20.530 And then whenever we want to insert a state, 00:15:20.530 --> 00:15:23.540 it's going to be at the end of the state stack. 00:15:23.540 --> 00:15:25.450 So it's going to be whatever the last-- 00:15:25.450 --> 00:15:28.990 so if we're looking at it as a series of states in a table, 00:15:28.990 --> 00:15:31.870 it'll be whatever the last index is in the table. 00:15:31.870 --> 00:15:35.530 That will be our, the top of our stack. 00:15:35.530 --> 00:15:38.440 And you can implement this either way in reverse if you wanted to. 00:15:38.440 --> 00:15:44.890 It's just easier, because you can just do a simple table.remove to get rid 00:15:44.890 --> 00:15:45.490 of the-- 00:15:48.100 --> 00:15:52.420 table.remove on that table to get rid of the last state 00:15:52.420 --> 00:15:54.280 without having to shift back everything. 00:15:54.280 --> 00:15:57.940 So if we did it starting at index one, you'd have to shift everything back. 00:15:57.940 --> 00:16:00.940 And it would also be a little bit weird, because you would start at one, 00:16:00.940 --> 00:16:03.070 and then things would go left. 00:16:03.070 --> 00:16:07.690 But basically, in order to update whatever our end state is, 00:16:07.690 --> 00:16:13.870 we just do at #self.states, which will be however large our state stack is, 00:16:13.870 --> 00:16:16.570 we just call update on that state. 00:16:16.570 --> 00:16:19.420 And then process AI is here, although we're not using it. 00:16:19.420 --> 00:16:21.640 But if you had AI, it would be the same thing 00:16:21.640 --> 00:16:26.950 as basically an update for artificial intelligence for your state. 00:16:26.950 --> 00:16:29.500 Rather than rendering just one state at a time, 00:16:29.500 --> 00:16:32.140 we iterate through all of our states here 00:16:32.140 --> 00:16:35.140 using ipairs, which will iterate through them numerically 00:16:35.140 --> 00:16:38.230 starting at one going to the end. 00:16:38.230 --> 00:16:41.410 So we call for istate, and ipairs of self.state, render it, 00:16:41.410 --> 00:16:47.260 so that will render everything back to front, or bottom to top, 00:16:47.260 --> 00:16:49.060 and allow us to get this layered look where 00:16:49.060 --> 00:16:51.268 we have a play state going on underneath for example, 00:16:51.268 --> 00:16:54.230 and then a dialogue on top. 00:16:54.230 --> 00:16:56.230 Or we have a battle state going at the very top, 00:16:56.230 --> 00:16:59.410 and maybe that battle state itself pushes a dialogue 00:16:59.410 --> 00:17:02.230 state to the top of the stack, or a bunch of other states, 00:17:02.230 --> 00:17:05.410 a transition, whatever you would like. 00:17:05.410 --> 00:17:08.290 To clear it, we just reset the table to an empty table. 00:17:08.290 --> 00:17:12.010 To push a state, we just do an insert on that state, and then 00:17:12.010 --> 00:17:14.680 we call enter on that state. 00:17:14.680 --> 00:17:19.240 As we did before, sort of similarly with state machine, when we changed a state, 00:17:19.240 --> 00:17:21.369 we would call enter on it and exit, but now we're 00:17:21.369 --> 00:17:23.050 just calling enter when we push. 00:17:23.050 --> 00:17:26.470 And then to pop, all we do is call exit on whatever 00:17:26.470 --> 00:17:30.460 the last state is in our state stack, and then just 00:17:30.460 --> 00:17:32.650 call table.remove on self.states. 00:17:32.650 --> 00:17:36.790 And by default, when you call table.remove on a table, just a table 00:17:36.790 --> 00:17:40.930 with no other arguments, it'll remove whatever 00:17:40.930 --> 00:17:43.165 the last index is of that table. 00:17:43.165 --> 00:17:44.100 Does that makes sense? 00:17:44.100 --> 00:17:46.558 Anybody have any questions as to how the state stack works? 00:17:49.300 --> 00:17:51.650 All right, awesome. 00:17:51.650 --> 00:17:56.700 So let's take a look then at the start state. 00:17:56.700 --> 00:17:59.980 So this is the start date. 00:18:03.850 --> 00:18:06.250 Fairly simple, we just have a couple of text labels, 00:18:06.250 --> 00:18:10.690 and then we have just a randomly assigned sprite going left to right. 00:18:10.690 --> 00:18:14.724 How do we think we're achieving the movement? 00:18:14.724 --> 00:18:17.230 Yep, timer.tween, and then we're just drawing 00:18:17.230 --> 00:18:19.840 an ellipse, right, pretty simple. 00:18:19.840 --> 00:18:24.830 And then when we press Enter, note the transition. 00:18:24.830 --> 00:18:31.140 Notice that there's a fade to white, and then fade to transparent. 00:18:31.140 --> 00:18:34.850 And so if we recall from when we looked at match three, how do we do this, 00:18:34.850 --> 00:18:36.792 do we remember? 00:18:36.792 --> 00:18:40.110 AUDIENCE: [INAUDIBLE] 00:18:42.480 --> 00:18:44.930 SPEAKER 1: Exactly, and the rectangle was stored where? 00:18:50.090 --> 00:18:52.510 Sorry, to repeat for the camera, we had a rectangle 00:18:52.510 --> 00:18:56.380 that filled the entire screen, and we just tween the transparency for it, 00:18:56.380 --> 00:18:57.710 which is true. 00:18:57.710 --> 00:19:01.120 The rectangle there before though was stored 00:19:01.120 --> 00:19:04.570 in whatever state was active at the time, which was like the start date, 00:19:04.570 --> 00:19:08.710 or the I think begin game state was the name. 00:19:08.710 --> 00:19:13.450 The actual state that wasn't necessarily relevant at the transition. 00:19:13.450 --> 00:19:18.130 But using a state stack, we can actually decouple this idea. 00:19:18.130 --> 00:19:21.580 We can take the concept of a transition, and because imagine 00:19:21.580 --> 00:19:24.567 if we wanted to make a transition between every single state 00:19:24.567 --> 00:19:25.900 that existed in our game, right? 00:19:25.900 --> 00:19:28.233 If we wanted to transition from the battle to the field, 00:19:28.233 --> 00:19:33.340 or the field to the battle, or whatever else we might want, like the start 00:19:33.340 --> 00:19:36.820 to the field, we would need a rectangle in every single one 00:19:36.820 --> 00:19:39.580 of those that has an opacity that we're keeping track of. 00:19:39.580 --> 00:19:44.500 And that's not necessarily germane to the purpose of that state, right? 00:19:44.500 --> 00:19:47.380 So because we now have a state stack, we can actually 00:19:47.380 --> 00:19:52.870 abstract out this idea of a transition, and turn it into its own state. 00:19:52.870 --> 00:19:56.230 We can have a transition state. 00:19:56.230 --> 00:19:59.470 And recall that since we're just layering everything 00:19:59.470 --> 00:20:03.130 [? off ?] all these states, and we're rendering them sequentially, 00:20:03.130 --> 00:20:07.840 having a state that possesses it's own for example, opacity rectangle, 00:20:07.840 --> 00:20:12.080 we can just layer that, push that onto the stack, and render that, 00:20:12.080 --> 00:20:16.160 and it'll give us the illusion of having this transition. 00:20:16.160 --> 00:20:19.000 But we don't need to actually have it be part of the state 00:20:19.000 --> 00:20:21.380 that we're trying to transition out of and into. 00:20:21.380 --> 00:20:23.720 Does that make sense? 00:20:23.720 --> 00:20:27.469 So let's take a look, for example, at the-- 00:20:27.469 --> 00:20:29.260 let's take a look at the start state first, 00:20:29.260 --> 00:20:32.920 just so we can see where that actually gets kicked off. 00:20:32.920 --> 00:20:36.160 So the start state, we kick off some music, we have a sprite, 00:20:36.160 --> 00:20:37.210 and a sprite x and y. 00:20:37.210 --> 00:20:40.570 These are values that are relevant to the sprite that's moving, actually, 00:20:40.570 --> 00:20:43.089 we only have one sprite ever moving left to right. 00:20:43.089 --> 00:20:45.380 It just gets teleported to the right edge of the screen 00:20:45.380 --> 00:20:47.620 as soon as it gets taken to one edge. 00:20:47.620 --> 00:20:51.340 So we only have one sprite, one x and y. 00:20:51.340 --> 00:20:53.440 And then every three seconds as we see here, 00:20:53.440 --> 00:20:59.890 we have a callback function that will tween the sprites x to negative 64 00:20:59.890 --> 00:21:03.370 over 0.2 seconds, so really quickly. 00:21:03.370 --> 00:21:06.190 And then on finish, teleport it to the right. 00:21:06.190 --> 00:21:08.380 And then do the same exact thing, but tween it 00:21:08.380 --> 00:21:11.170 to the center over 0.2 seconds. 00:21:11.170 --> 00:21:18.190 And then as soon as we press Enter or Return, note this here, 00:21:18.190 --> 00:21:22.960 we have gStateStack, not a gStateMachine anymore, 00:21:22.960 --> 00:21:27.490 and we're pushing on to it a fade in state, 00:21:27.490 --> 00:21:32.170 which takes an RGB, a duration, and a callback function. 00:21:32.170 --> 00:21:38.080 Now if you look at main.lua, this is relevant, 00:21:38.080 --> 00:21:42.790 because now we no longer have a state machine, right? 00:21:42.790 --> 00:21:45.670 We previously had a global state machine, gStateMachine. 00:21:45.670 --> 00:21:49.450 We would give it a list of indexes into functions, anonymous functions. 00:21:49.450 --> 00:21:53.150 Those would return the instantiation of a state. 00:21:53.150 --> 00:21:55.885 And then when we called change, the state machine will 00:21:55.885 --> 00:22:00.820 index into its list of states, and call that anonymous function, 00:22:00.820 --> 00:22:04.090 which would have the result of changing the state to some state 00:22:04.090 --> 00:22:07.000 that we've implemented as a class, right? 00:22:07.000 --> 00:22:09.190 Now we just create a state stack and we just 00:22:09.190 --> 00:22:14.320 push a new start state onto the class. 00:22:14.320 --> 00:22:18.220 And so what this will do is effectively the same thing, only now 00:22:18.220 --> 00:22:23.101 we can layer things onto the start state, right, or play state, 00:22:23.101 --> 00:22:25.850 or whatever we want to, and we're not going to ever get rid of it. 00:22:25.850 --> 00:22:28.250 I mean, we can get rid of it, but we don't have to. 00:22:28.250 --> 00:22:32.680 For the play state, especially, we want that to pretty much never get 00:22:32.680 --> 00:22:35.260 popped off the stack, because that's going 00:22:35.260 --> 00:22:36.960 to preserve all of our information. 00:22:36.960 --> 00:22:40.210 We're going to default back to that to store all of our character information, 00:22:40.210 --> 00:22:43.210 our Pokemon information, whatever else we might 00:22:43.210 --> 00:22:46.690 want to add onto this shell of a game in inventory, 00:22:46.690 --> 00:22:49.360 et cetera, a world state at large. 00:22:49.360 --> 00:22:53.140 We want to preserve that and keep that consistent across all of our battle 00:22:53.140 --> 00:22:54.580 states and so forth. 00:22:54.580 --> 00:22:58.060 And the battle states will just pull information from that world, 00:22:58.060 --> 00:23:01.840 from that play state, and construct a battle as needed. 00:23:01.840 --> 00:23:04.570 Does that makes sense? 00:23:04.570 --> 00:23:08.590 OK, so here we're effectively, the only real changes we've made to main 00:23:08.590 --> 00:23:11.790 are no longer a state machine, now we have a state stack, 00:23:11.790 --> 00:23:14.230 going to push start state, that start state 00:23:14.230 --> 00:23:18.790 has some behavior just like any other state that we've implemented before. 00:23:22.570 --> 00:23:29.560 And what I was about to get into before was here on line 36 of the start state, 00:23:29.560 --> 00:23:32.540 we're pushing another state onto the stack. 00:23:32.540 --> 00:23:36.951 So there's already a start state, and it's from within the start state itself 00:23:36.951 --> 00:23:37.450 actually. 00:23:40.279 --> 00:23:42.820 We're going to take that stack, which is just one level deep, 00:23:42.820 --> 00:23:44.560 and then we're going to make it two levels deep now. 00:23:44.560 --> 00:23:46.360 So now we're going to add a fade in state. 00:23:46.360 --> 00:23:49.270 And the fade in state as we can see, takes in an RGB. 00:23:49.270 --> 00:23:52.160 Does anybody have a guess as to what the RGB is relevant for? 00:23:55.046 --> 00:23:58.425 AUDIENCE: [INAUDIBLE] 00:23:58.425 --> 00:24:00.800 SPEAKER 1: To whether you want to fade in black or white? 00:24:00.800 --> 00:24:02.035 Yes, any color. 00:24:02.035 --> 00:24:04.660 We can make this, we can make it a fade to red if we wanted to, 00:24:04.660 --> 00:24:06.350 or fade to blue. 00:24:06.350 --> 00:24:10.490 But we don't have to create two separate classes for a fade in white, 00:24:10.490 --> 00:24:13.850 fade in black, fade out black, fade out white. 00:24:13.850 --> 00:24:16.760 We can just give it a color. 00:24:16.760 --> 00:24:20.360 And then I mean, we could even go a level further with this, 00:24:20.360 --> 00:24:23.960 and make it take in an opacity as well, so that we don't need a fade in state, 00:24:23.960 --> 00:24:26.690 or a fade out state, we just need a fade state, right? 00:24:26.690 --> 00:24:30.110 And the fade state will determine, based on whatever 00:24:30.110 --> 00:24:37.654 last opacity parameter we give it, the right way to fade in and out. 00:24:37.654 --> 00:24:40.070 But in this case, the difference between the fade in state 00:24:40.070 --> 00:24:44.090 and the fade out state is one knows to go to 0, one knows to go to 255. 00:24:44.090 --> 00:24:46.700 That's really the only key difference. 00:24:46.700 --> 00:24:51.830 And then this 1, the duration, right, we need to tell it how long to fade. 00:24:51.830 --> 00:24:55.610 And then this last bit here is a function. 00:24:55.610 --> 00:24:59.960 We're giving it an anonymous function, this is a callback function, 00:24:59.960 --> 00:25:06.650 because the fade in state by nature is an asynchronous state. 00:25:06.650 --> 00:25:08.480 It does its behavior over time. 00:25:08.480 --> 00:25:10.940 So we need a way, we need to tell it, OK, 00:25:10.940 --> 00:25:14.360 when you finished doing what you're doing, call this bit of code 00:25:14.360 --> 00:25:19.010 here, so that we can do something not immediately, 00:25:19.010 --> 00:25:22.250 we can sort of defer its execution till later. 00:25:22.250 --> 00:25:26.910 And this is something that we'll see common throughout this lecture, 00:25:26.910 --> 00:25:29.870 because we have this implemented also in like dialogue for example, 00:25:29.870 --> 00:25:34.910 because we don't know when the user is going to press Spacebar on the dialog 00:25:34.910 --> 00:25:36.630 state and clear the window. 00:25:36.630 --> 00:25:39.320 But what if we want that window, the clearing of that dialog 00:25:39.320 --> 00:25:41.690 to trigger some sort of event, right? 00:25:41.690 --> 00:25:44.830 For example, if they press Enter when they're in the battle, 00:25:44.830 --> 00:25:46.534 we want it to go to the next action. 00:25:46.534 --> 00:25:48.700 We don't necessarily know when it's going to happen, 00:25:48.700 --> 00:25:54.770 so we'll just pass in an anonymous function to that dialogue state 00:25:54.770 --> 00:25:59.760 that the class will call whenever the close function is called on that dialog 00:25:59.760 --> 00:26:00.260 state. 00:26:00.260 --> 00:26:03.170 It says, when closed, execute this anonymous function. 00:26:03.170 --> 00:26:06.320 And then that anonymous function can do whatever you want to do. 00:26:06.320 --> 00:26:09.170 It could pop another other several states onto the stack. 00:26:09.170 --> 00:26:12.057 But this is what allows us to chain asynchronous behavior. 00:26:12.057 --> 00:26:12.890 That's the key here. 00:26:15.650 --> 00:26:18.800 So this anonymous function-- so we'll take a look now actually 00:26:18.800 --> 00:26:23.340 at the fade in state, just so we can see what this looks like. 00:26:23.340 --> 00:26:26.360 So we see here, fade in state, right, takes in the color. 00:26:26.360 --> 00:26:30.560 We saw before, that will be the color we fade to. 00:26:30.560 --> 00:26:34.580 The length of time that it'll take us to actually perform the transition. 00:26:34.580 --> 00:26:46.390 And what are we using for the transition do we think, timer.tween, right? 00:26:46.390 --> 00:26:51.890 So most everything that we'll do actually 00:26:51.890 --> 00:26:55.150 throughout the course of this lecture that has asynchronous behavior, 00:26:55.150 --> 00:26:57.420 we can implement it with timer, which is nice. 00:26:57.420 --> 00:27:01.600 It allows us to fairly succinctly and declaratively tell 00:27:01.600 --> 00:27:04.670 right out what exactly we want to have happen over time. 00:27:04.670 --> 00:27:07.930 In this case, we're going to tween over the course of time 00:27:07.930 --> 00:27:11.840 the opacity of our self to 255. 00:27:11.840 --> 00:27:15.627 So the fade in is going to fade into the full color of whatever we 00:27:15.627 --> 00:27:16.210 have given it. 00:27:16.210 --> 00:27:22.180 So it's going to go from 0, which is shown here by default, to 255. 00:27:22.180 --> 00:27:27.550 And then as soon as we finish that tween, 00:27:27.550 --> 00:27:32.740 that is when we pop the fade in state. 00:27:32.740 --> 00:27:35.920 We're going to pop ourselves off the state effectively, off the stack 00:27:35.920 --> 00:27:37.840 effectively. 00:27:37.840 --> 00:27:41.150 And then here, we're calling on fade complete. 00:27:41.150 --> 00:27:43.210 And that's where the anonymous function is. 00:27:43.210 --> 00:27:45.430 On fade complete is passed in here. 00:27:45.430 --> 00:27:52.630 So by putting that function into the finish function of the tween operation, 00:27:52.630 --> 00:27:58.710 we've allowed ourselves to defer that function that we've written up in the-- 00:27:58.710 --> 00:28:01.120 it's in the start state. 00:28:01.120 --> 00:28:04.750 We defer the execution of this function until after that tween operation 00:28:04.750 --> 00:28:05.700 takes place. 00:28:05.700 --> 00:28:08.220 Does that make sense? 00:28:08.220 --> 00:28:09.764 OK, awesome. 00:28:09.764 --> 00:28:11.180 And that's effectively what it is. 00:28:11.180 --> 00:28:13.970 And that's a common theme that we'll see if you're looking through the distro, 00:28:13.970 --> 00:28:15.620 you'll see it in a lot of places. 00:28:15.620 --> 00:28:17.870 Anonymous functions or callback functions 00:28:17.870 --> 00:28:24.860 rather being passed into things like the dialogs, and the fades, 00:28:24.860 --> 00:28:26.747 and a few other places. 00:28:26.747 --> 00:28:28.580 In the take turns state for example, there's 00:28:28.580 --> 00:28:30.920 a function that takes in at a callback function as well. 00:28:30.920 --> 00:28:38.210 And that's effectively how you can chain asynchronous behavior that 00:28:38.210 --> 00:28:41.105 executes over time, rather than it being blocking. 00:28:41.105 --> 00:28:44.630 Does anybody have any questions so far as to how this works, at all? 00:28:47.780 --> 00:28:51.980 All right, so when the fade is done-- 00:28:51.980 --> 00:28:54.440 we're still the start state here-- 00:28:54.440 --> 00:28:58.820 at this point, the fade is done, we're executing this anonymous function. 00:28:58.820 --> 00:29:09.840 We're going to pop the start state off of the stack in this case. 00:29:09.840 --> 00:29:12.570 And then we're going to push a-- 00:29:12.570 --> 00:29:15.780 we're going to do two pushes here. 00:29:15.780 --> 00:29:20.960 One is to push a play state, which recall is where the NPC [INAUDIBLE] 00:29:20.960 --> 00:29:23.210 character walking around. 00:29:23.210 --> 00:29:27.294 And another one is to push a dialogue state. 00:29:27.294 --> 00:29:29.960 And so what this will have the effect of doing is rather than us 00:29:29.960 --> 00:29:33.150 immediately going into the play state and being able to walk around, 00:29:33.150 --> 00:29:35.634 we're actually put right into a world where 00:29:35.634 --> 00:29:37.550 there is a message waiting for us that we have 00:29:37.550 --> 00:29:40.640 to press Enter on in order to continue. 00:29:40.640 --> 00:29:45.230 And when we press Enter, because we're pushing the play state first, 00:29:45.230 --> 00:29:47.410 and then the dialogue state, the dialogue state 00:29:47.410 --> 00:29:49.670 is at the top of the stack, right, because things 00:29:49.670 --> 00:29:53.060 get pushed onto like a stack of plates. 00:29:53.060 --> 00:29:56.150 You put a play state plate on the bottom and then another plate on top, 00:29:56.150 --> 00:30:00.180 and that plate is the dialogue state in this case. 00:30:00.180 --> 00:30:02.330 And you can only interact with the top-- 00:30:02.330 --> 00:30:06.290 we're only updating the top plate at once in this model. 00:30:06.290 --> 00:30:08.630 We could obviously make a more complicated state 00:30:08.630 --> 00:30:14.090 stack that allows us to have several layers of states being updated at once, 00:30:14.090 --> 00:30:19.940 but for simplicity, we only opted to allow the top layer to be updated. 00:30:19.940 --> 00:30:21.986 The dialog state is going to be the active state, 00:30:21.986 --> 00:30:23.360 it's going to be receiving input. 00:30:23.360 --> 00:30:25.930 All of them are going to be rendered, so we're 00:30:25.930 --> 00:30:27.680 going to render things from the bottom up. 00:30:27.680 --> 00:30:28.940 We're going to render the play state, then 00:30:28.940 --> 00:30:31.010 we're going to render the dialog state, but the dialog state's 00:30:31.010 --> 00:30:31.910 going to be active. 00:30:31.910 --> 00:30:35.120 We're only going to be able to press anything on that state. 00:30:35.120 --> 00:30:40.550 And then lastly, actually, even beyond the dialogue state, 00:30:40.550 --> 00:30:43.500 we're pushing another state, we're pushing a fade out state. 00:30:43.500 --> 00:30:47.150 And in this case, it's the opposite of the fade in state, 00:30:47.150 --> 00:30:51.170 it just takes in an RGB, and we'll go from 255 opacity 00:30:51.170 --> 00:30:54.180 to zero opacity in that case. 00:30:54.180 --> 00:31:00.470 And so what that allows us to do for playing right, 00:31:00.470 --> 00:31:03.320 we're here in the start state, pressing Enter. 00:31:03.320 --> 00:31:06.860 That's our fade in state was there. 00:31:06.860 --> 00:31:11.510 And then we pushed to the play state and the dialogue state and the fade 00:31:11.510 --> 00:31:15.440 out state at once, so you would almost think 00:31:15.440 --> 00:31:18.020 that we push a fade in and then the fade out, 00:31:18.020 --> 00:31:21.560 but we have to lay that foundation before we 00:31:21.560 --> 00:31:24.170 put the fade out state on top of the stack, 00:31:24.170 --> 00:31:27.720 right, because the top layer gets updated. 00:31:27.720 --> 00:31:30.890 So we have to push the fade out state on top of all of those. 00:31:30.890 --> 00:31:32.797 That will get updated, that will fade out, 00:31:32.797 --> 00:31:34.880 and then we're back to the two states that we push 00:31:34.880 --> 00:31:36.870 before we pushed the fadeout state. 00:31:36.870 --> 00:31:39.240 Does that make since? 00:31:39.240 --> 00:31:40.300 OK. 00:31:40.300 --> 00:31:44.710 Does anybody have any questions as to how that sort of flow works? 00:31:44.710 --> 00:31:47.110 Cool. 00:31:47.110 --> 00:31:49.510 All right, so that's the gist behind, I mean, 00:31:49.510 --> 00:31:54.280 that's essentially the core of what we're doing today 00:31:54.280 --> 00:31:56.890 is the state stack pushing multiple states. 00:31:56.890 --> 00:31:58.940 And then just figuring out the right order 00:31:58.940 --> 00:32:02.710 the need to push them in to get the desired appearance that you want, 00:32:02.710 --> 00:32:03.340 right? 00:32:03.340 --> 00:32:07.180 We push the fade out state while we're in the start state, 00:32:07.180 --> 00:32:08.430 or fade in state rather. 00:32:08.430 --> 00:32:10.990 That will take us to white, and then like sort 00:32:10.990 --> 00:32:17.440 of, almost like underneath the-- behind the curtain, we're popping everything, 00:32:17.440 --> 00:32:20.770 and then we're adding the play, dialogue, and then another fade out 00:32:20.770 --> 00:32:21.380 state. 00:32:21.380 --> 00:32:25.419 And so you sort of have to balance the order that you put things in in order 00:32:25.419 --> 00:32:26.710 to achieve the desired results. 00:32:26.710 --> 00:32:28.876 It may not necessarily be exactly as you intuitively 00:32:28.876 --> 00:32:32.110 think until you think about just how we're updating and rendering 00:32:32.110 --> 00:32:34.030 things on a stack. 00:32:34.030 --> 00:32:38.195 And so that's the ultimate hurdle I think in really getting comfortable 00:32:38.195 --> 00:32:41.320 with the distro, but once you've gotten that, everything else sort of falls 00:32:41.320 --> 00:32:42.290 into place. 00:32:42.290 --> 00:32:46.600 That and the sort of abundance of asynchronous functions, as we'll 00:32:46.600 --> 00:32:49.660 see pretty shortly when we look at GUIs, and how we've implemented 00:32:49.660 --> 00:32:51.590 a lot of basic GUI functionality. 00:32:51.590 --> 00:32:54.460 A lot of that is very, very call back driven, 00:32:54.460 --> 00:32:58.012 just because of the nature of it being based on user input, right? 00:32:58.012 --> 00:33:00.220 You don't know when the user's going to do any input, 00:33:00.220 --> 00:33:04.240 so defer whatever happens with that GUI code 00:33:04.240 --> 00:33:08.140 with the triggers involved when the user presses Spacebar, 00:33:08.140 --> 00:33:13.660 Enter, and then call that function that you've passed into that GUI widget. 00:33:13.660 --> 00:33:17.020 All right, so we've taken a look at the state stack. 00:33:17.020 --> 00:33:20.270 We've taken a look at the start state, the fade in state, 00:33:20.270 --> 00:33:22.290 let's take a look now at the play state. 00:33:25.690 --> 00:33:26.624 So the play state-- 00:33:26.624 --> 00:33:28.540 a lot of this is actually very similar to what 00:33:28.540 --> 00:33:35.080 we did back with Zelda, which is a very similar type of game top down. 00:33:35.080 --> 00:33:40.450 View, the only difference really with that was RPGs of this nature-- 00:33:40.450 --> 00:33:42.730 Final Fantasy, Pokemon, Dragon Quest, they're 00:33:42.730 --> 00:33:47.110 tile based to the degree of even your movement is tile based. 00:33:47.110 --> 00:33:51.620 And so we've striven to implement that with this lecture. 00:33:51.620 --> 00:33:57.340 So when we move our player, our character, 00:33:57.340 --> 00:34:02.660 it doesn't have free motion like we did with Zelda for example. 00:34:02.660 --> 00:34:03.950 So I'll demonstrate this. 00:34:03.950 --> 00:34:07.360 So I can go to the field state here, the play state, sorry. 00:34:07.360 --> 00:34:09.969 And then when I move, if I press right, he 00:34:09.969 --> 00:34:13.850 moves in that direction at a perfect grid interval. 00:34:13.850 --> 00:34:16.690 So if I move up, I'm taking my hand instantly away, 00:34:16.690 --> 00:34:20.980 he's going to keep moving, and he's going to stick hard set to this grid. 00:34:20.980 --> 00:34:25.130 And that's just a sort of trend that these games have implemented. 00:34:25.130 --> 00:34:29.139 It allows you to stay perfectly aligned with the grid, and helps you 00:34:29.139 --> 00:34:30.800 I guess certain game-- 00:34:30.800 --> 00:34:33.429 I don't think it's strictly necessary for probably 00:34:33.429 --> 00:34:37.239 most of the games that choose to implement this. 00:34:37.239 --> 00:34:41.500 I think it was a symptom of tile based games from the NES and Gameboy 00:34:41.500 --> 00:34:47.170 era being easier to design and implement, 00:34:47.170 --> 00:34:51.699 because they're very tile based systems. 00:34:51.699 --> 00:34:55.030 But I mean, even as an aesthetic choice, I suppose it makes sense, 00:34:55.030 --> 00:34:57.472 because everything aligns very perfectly. 00:34:57.472 --> 00:35:00.430 So that's the core difference really with the field state in this game. 00:35:00.430 --> 00:35:09.160 So how can we go about implementing a grid aligned movement system like this 00:35:09.160 --> 00:35:12.170 with our player relative to how we did it in Zelda for example? 00:35:16.690 --> 00:35:18.862 How do we think-- sure yeah? 00:35:18.862 --> 00:35:23.200 AUDIENCE: So we don't x and y's, we just have the tile positions. 00:35:23.200 --> 00:35:26.410 SPEAKER 1: So you don't have x and y's, we just have the tile positions. 00:35:26.410 --> 00:35:30.790 Close, I would say it's more focused on the tile positions, 00:35:30.790 --> 00:35:33.790 but you still do need an x and a y, because you still 00:35:33.790 --> 00:35:37.142 need to draw that sprite at that exact position. 00:35:37.142 --> 00:35:38.250 Right, yes Tony? 00:35:38.250 --> 00:35:42.400 AUDIENCE: Well, when you need to move the sprite, instead 00:35:42.400 --> 00:35:47.080 of moving at every update, you tween it between the two tile locations. 00:35:47.080 --> 00:35:51.680 SPEAKER 1: Exactly, so rather than moving the sprite 00:35:51.680 --> 00:35:57.970 at exact pixel positions per update, you tween the sprite when you receive input 00:35:57.970 --> 00:35:59.950 to a specific location. 00:35:59.950 --> 00:36:02.780 And then we actually stop input at that point as well. 00:36:02.780 --> 00:36:08.020 There's no use for us having any input when we're not exactly at a given tile, 00:36:08.020 --> 00:36:12.170 so we disable input while he's walking effectively. 00:36:12.170 --> 00:36:16.150 And so this is implemented, if we're looking at the distro in the entity 00:36:16.150 --> 00:36:19.318 class, there is a-- 00:36:19.318 --> 00:36:20.350 I believe it's in here-- 00:36:24.660 --> 00:36:25.800 maybe player, hold on. 00:36:32.360 --> 00:36:35.030 Oh sorry, no it's entity walk state, not the entity. 00:36:35.030 --> 00:36:38.600 Entity is just a container for the information that's relevant. 00:36:38.600 --> 00:36:42.510 So here in the entity walk state, we have attempt move. 00:36:42.510 --> 00:36:45.395 And so what attempt move does is essentially 00:36:45.395 --> 00:36:49.820 it looks to make sure that we're within the bounds of the map, right? 00:36:49.820 --> 00:36:51.970 And then if we are-- 00:36:51.970 --> 00:36:56.917 every entity in this game now has a map y and x, and a regular y and x. 00:36:56.917 --> 00:36:59.000 And so the regular y and x, we still need in order 00:36:59.000 --> 00:37:01.880 to draw our sprite at a specific location on the map. 00:37:01.880 --> 00:37:09.320 We still need to draw it going between 240 something and 230 something, right? 00:37:09.320 --> 00:37:12.650 But we need a map x and a map y to basically say, OK, 00:37:12.650 --> 00:37:15.680 the sprite should be at this position on the map. 00:37:15.680 --> 00:37:19.220 And then we'll just tween it between that position times 16, 00:37:19.220 --> 00:37:22.610 and it's the position plus or minus x or y 00:37:22.610 --> 00:37:26.000 times 16, which will give us the exact x and y value that we 00:37:26.000 --> 00:37:27.480 need to draw it onto the map. 00:37:27.480 --> 00:37:28.980 And so that's what we're doing here. 00:37:28.980 --> 00:37:32.630 So were going to call attempt move on input. 00:37:32.630 --> 00:37:34.440 So anytime we do any input-- 00:37:34.440 --> 00:37:39.950 and this is done in the player like idle, or player, yeah, player 00:37:39.950 --> 00:37:41.900 idle class-- 00:37:41.900 --> 00:37:43.820 player idle state. 00:37:43.820 --> 00:37:46.520 We change the animation to write animation. 00:37:46.520 --> 00:37:48.710 And then we get it's current map x and y. 00:37:48.710 --> 00:37:51.410 And then based on whatever direction the player is looking, 00:37:51.410 --> 00:37:56.720 or the entity is looking, we could use this for an NPC class, or the like. 00:37:56.720 --> 00:37:59.870 We just modify our 2x and 2y. 00:37:59.870 --> 00:38:04.390 So to 2x and 2y is going to be the value that we're tweening towards times 16, 00:38:04.390 --> 00:38:05.950 right? 00:38:05.950 --> 00:38:10.940 And so if we're trying to go outside the map boundaries, 00:38:10.940 --> 00:38:13.340 just changing us back to idle won't let us do that. 00:38:13.340 --> 00:38:19.620 Otherwise, set our map y and map x to that position immediately, 00:38:19.620 --> 00:38:22.880 right, because that's just a minus or plus one operation. 00:38:22.880 --> 00:38:28.010 And then over the course of 0.5 seconds, actually tween to that value. 00:38:28.010 --> 00:38:30.770 And we can see here, we're tweening to the tile size, 00:38:30.770 --> 00:38:35.212 and actually to the tile size minus self.entity.height divided by 2. 00:38:35.212 --> 00:38:36.170 Do we know why that is? 00:38:40.820 --> 00:38:45.385 We do that, because if we're looking at the field, we can see here, 00:38:45.385 --> 00:38:48.010 notice that we're not perfectly lined up with the grass, right? 00:38:48.010 --> 00:38:50.050 It's kind of like we're halfway above it, 00:38:50.050 --> 00:38:53.050 because it looks just a little bit more natural this way, 00:38:53.050 --> 00:38:54.967 this is how most sort of games look. 00:38:54.967 --> 00:38:56.800 And if you're in a game like this and you're 00:38:56.800 --> 00:38:58.821 like walking up against a wall for example, 00:38:58.821 --> 00:39:00.820 this will allow you to sort of look as if you're 00:39:00.820 --> 00:39:03.100 up against the wall rather than sort of being 00:39:03.100 --> 00:39:06.880 at the edge of where the bottom of the wall is, and kind of looks unnatural. 00:39:06.880 --> 00:39:12.290 Hence why we minus 1/2 our height right there. 00:39:12.290 --> 00:39:15.910 And then when we're finished, we actually 00:39:15.910 --> 00:39:18.770 test to see whether we're still pressing a key, and if we are, 00:39:18.770 --> 00:39:20.710 then change our state to walk again, which 00:39:20.710 --> 00:39:24.727 we'll just repeat this process depending on which direction we're looking at. 00:39:24.727 --> 00:39:25.810 And that's effectively it. 00:39:25.810 --> 00:39:28.462 And that's what allows us to get this grid based movement. 00:39:28.462 --> 00:39:29.920 Any questions as to how this works? 00:39:33.280 --> 00:39:33.780 Cool. 00:39:37.335 --> 00:39:43.200 Let's take a look then at the play state, let's go back to it. 00:39:43.200 --> 00:39:46.110 So we have a level, the level contains our entity, 00:39:46.110 --> 00:39:49.394 and it can contain all of our entities, and whatever 00:39:49.394 --> 00:39:50.685 objects you want it to contain. 00:39:53.190 --> 00:39:55.530 In this case, when we're in the play state as well, 00:39:55.530 --> 00:39:57.279 we're going to check to see if we press P, 00:39:57.279 --> 00:39:59.820 because that's recall, where we can heal our Pokemon, 00:39:59.820 --> 00:40:05.410 just a little game hack just to make demoing it a little bit easier. 00:40:05.410 --> 00:40:11.800 But if we press P, we play the heal sound, we take our-- 00:40:11.800 --> 00:40:16.110 and we'll look a little bit more detail as to this, all this in a little bit. 00:40:16.110 --> 00:40:24.090 But self.level.player.pa rty.pokemon@index1.currenthp 00:40:24.090 --> 00:40:29.416 equals self.level.player.party.pokemon@1.hp. 00:40:29.416 --> 00:40:32.040 So the difference is current HP is whatever you currently have, 00:40:32.040 --> 00:40:33.330 you could have taken damage. 00:40:33.330 --> 00:40:35.730 HP is whatever your max HP is. 00:40:35.730 --> 00:40:38.860 And this is like in a nutshell how you get 00:40:38.860 --> 00:40:44.820 like stat changes in games and RPGs, and health and mp differences. 00:40:44.820 --> 00:40:48.577 You've got to keep track of a max and a current value for all of those things, 00:40:48.577 --> 00:40:50.910 and then depending on whether you're buffed or debugged, 00:40:50.910 --> 00:40:54.120 or whether you have taken damage or not, or used spells or not, 00:40:54.120 --> 00:40:56.610 you can have an accurate reflection of where 00:40:56.610 --> 00:41:01.350 your character is and then always return back to that state 00:41:01.350 --> 00:41:03.420 whenever you need to. 00:41:03.420 --> 00:41:06.570 The interesting thing here, the slightly more complicated thing 00:41:06.570 --> 00:41:10.350 is when we press P, we want to show a dialog that says, 00:41:10.350 --> 00:41:13.680 and I'll demonstrate this, we want to show a dialog just 00:41:13.680 --> 00:41:18.120 like this one that says, we press P, your Pokemon has been healed, right? 00:41:18.120 --> 00:41:19.200 Now I can't move. 00:41:19.200 --> 00:41:20.790 I'm pressing the arrow keys. 00:41:20.790 --> 00:41:23.430 I can't move my character at all, because this dialog state-- 00:41:23.430 --> 00:41:28.950 we're in a new state, well, we've pushed a new state onto the state stack. 00:41:28.950 --> 00:41:32.380 And that's the dialog state here, which has taken a value. 00:41:32.380 --> 00:41:37.030 And because it's the top layer of the stack, it can't get updated, 00:41:37.030 --> 00:41:40.200 or it's being updated, and we can't update the play state, right, 00:41:40.200 --> 00:41:44.850 based on how we've modeled our state stacks operation, or how it works. 00:41:44.850 --> 00:41:47.970 And then as soon as I press Enter, it gets popped off, 00:41:47.970 --> 00:41:49.030 we've just popped it off. 00:41:49.030 --> 00:41:51.570 Now the place states at the top, I can move again. 00:41:51.570 --> 00:41:52.740 So that's what's going on. 00:41:52.740 --> 00:42:02.700 So the dialog state then is actually very similar in a sense, to the fade 00:42:02.700 --> 00:42:06.450 in and fade out state in that, notice that it takes an anonymous function. 00:42:06.450 --> 00:42:09.251 When does this anonymous function get called? 00:42:09.251 --> 00:42:09.750 Do we know? 00:42:12.750 --> 00:42:16.311 At the end of what? 00:42:16.311 --> 00:42:18.600 AUDIENCE: [INAUDIBLE] 00:42:18.600 --> 00:42:24.790 SPEAKER 1: Yeah, well, when the user closes the dialog box, correct. 00:42:24.790 --> 00:42:27.800 So let's take a look at the dialog state then. 00:42:27.800 --> 00:42:32.640 And we can see, it's actually pretty simple, it's pretty small. 00:42:32.640 --> 00:42:36.480 We have a text that it takes and a callback, right? 00:42:36.480 --> 00:42:39.600 The text is used here. 00:42:39.600 --> 00:42:42.870 We instantiate, and this we'll see in detail when we start looking at GUIs, 00:42:42.870 --> 00:42:45.450 and all the widgets they've implemented here. 00:42:45.450 --> 00:42:52.020 This text box gets put at a hard coded position, and it receives this text. 00:42:52.020 --> 00:42:56.490 And then we set our self.callback to that callback function. 00:42:56.490 --> 00:43:00.630 If we have closed the text box, meaning, we're 00:43:00.630 --> 00:43:03.990 looking to see at self.textbox.isClosed, which 00:43:03.990 --> 00:43:07.080 is a function of the text box class. 00:43:07.080 --> 00:43:12.660 If it's closed, then execute self.callback, and then pop 00:43:12.660 --> 00:43:15.870 this dialog state of the stack, right? 00:43:15.870 --> 00:43:19.710 So it's similar in a sense, to the fade in and fade out, 00:43:19.710 --> 00:43:21.430 and then it takes anonymous function. 00:43:21.430 --> 00:43:23.388 The only difference is in how it gets executed. 00:43:23.388 --> 00:43:25.350 With the fade in state, the anonymous function 00:43:25.350 --> 00:43:28.160 was called at the end of the finish function, which 00:43:28.160 --> 00:43:30.100 is part of the tween object. 00:43:30.100 --> 00:43:33.840 In this case, we're executing the callback function explicitly when 00:43:33.840 --> 00:43:35.460 we've closed the text box. 00:43:35.460 --> 00:43:40.440 So we're waiting for user input versus waiting for some asynchronous operation 00:43:40.440 --> 00:43:42.570 to finish. 00:43:42.570 --> 00:43:45.990 And then of course, we call text box render, 00:43:45.990 --> 00:43:49.566 and then we'll see all of these methods shortly as part of these widgets, 00:43:49.566 --> 00:43:52.690 but at a glance, this is all that's really happening with the dialog state. 00:43:52.690 --> 00:43:55.980 Very simple, using the same pattern that we've 00:43:55.980 --> 00:44:01.530 seen of deferring future behavior to anonymous functions. 00:44:01.530 --> 00:44:07.025 Any questions as to how this works, or anything so far? 00:44:07.025 --> 00:44:09.164 Cool. 00:44:09.164 --> 00:44:11.330 All right, let's take a look back at the play state, 00:44:11.330 --> 00:44:14.180 I believe we're getting close to being finished with the play state. 00:44:14.180 --> 00:44:18.810 Yes, so everything, that's basically what the play state is in this game. 00:44:18.810 --> 00:44:22.170 And then a lot of what's going on takes place in a level as well. 00:44:22.170 --> 00:44:29.000 So in a nutshell, we have two maps, two layers, right, 00:44:29.000 --> 00:44:32.990 because the grass in the tile sheet is its own sort of [? alphaed ?] 00:44:32.990 --> 00:44:36.440 out object, it's got transparency around it. 00:44:36.440 --> 00:44:40.100 We keep a layer of the base, a layer of the grass underneath, 00:44:40.100 --> 00:44:43.610 and then a separate layer for the tall grass. 00:44:43.610 --> 00:44:45.950 And then we can just look and to see when 00:44:45.950 --> 00:44:51.260 we're walking in the player walk state when we've walked over tall grass. 00:44:51.260 --> 00:44:55.076 And then what do we need to do to start a random encounter? 00:45:01.171 --> 00:45:01.670 Yes? 00:45:01.670 --> 00:45:04.710 AUDIENCE: [INAUDIBLE] 00:45:04.710 --> 00:45:07.040 SPEAKER 1: Yes, how do we initiated though? 00:45:07.040 --> 00:45:08.890 That what are we looking for? 00:45:08.890 --> 00:45:11.297 We do push a battle state as soon as we've triggered one, 00:45:11.297 --> 00:45:12.380 but how do we trigger one? 00:45:12.380 --> 00:45:13.702 What are we looking for? 00:45:13.702 --> 00:45:17.750 AUDIENCE: [INAUDIBLE] player is in the grass. 00:45:17.750 --> 00:45:20.150 I don't know if it's on moving to a new grass, 00:45:20.150 --> 00:45:22.870 or if it's time spent in the grass. 00:45:22.870 --> 00:45:25.820 Yeah, we do a random chance whenever the players on grass. 00:45:25.820 --> 00:45:29.539 And it's whenever they start to walk and there on grass in this case. 00:45:29.539 --> 00:45:31.330 But you can do it either way, you can do it 00:45:31.330 --> 00:45:33.830 when they're leaving the grass, walking into the grass. 00:45:33.830 --> 00:45:35.871 In this case, it's whenever you press the button, 00:45:35.871 --> 00:45:38.780 and they happen to be on grass, it'll do a random chance, one in 10. 00:45:38.780 --> 00:45:43.130 And if it's equal to 1, 10% chance it'll trigger an encounter. 00:45:43.130 --> 00:45:46.670 So that's the gist behind triggering a random encounter, 00:45:46.670 --> 00:45:48.602 and a lot of these games really-- 00:45:48.602 --> 00:45:49.810 some games do it differently. 00:45:49.810 --> 00:45:52.795 They'll sometimes make it more likely the more steps you've taken, 00:45:52.795 --> 00:45:55.670 they'll like sort of keep a counter to say, oh, I've taken 100 steps, 00:45:55.670 --> 00:45:57.680 it should be a lot more likely now. 00:45:57.680 --> 00:46:01.700 Some games will just be completely random, 1 in 10, 1 in 5, 00:46:01.700 --> 00:46:05.210 depending on how the developers decided to implement their game. 00:46:05.210 --> 00:46:08.540 The former is a bit more robust. 00:46:08.540 --> 00:46:11.750 But for simplicity, we just chose, math.random10 equals 1. 00:46:14.680 --> 00:46:19.410 So yeah, we create the tile maps here, pretty straightforward. 00:46:19.410 --> 00:46:26.630 And then the actual random encountering takes place in the player walk state. 00:46:26.630 --> 00:46:29.570 So here we have check for encounter. 00:46:29.570 --> 00:46:33.800 And so what this does is whenever we enter the walk state, which 00:46:33.800 --> 00:46:37.650 is we press the button to enter, or to walk, 00:46:37.650 --> 00:46:40.190 this entire function gets called, because we 00:46:40.190 --> 00:46:43.160 do the transition to the player walk state in the state machine. 00:46:43.160 --> 00:46:45.826 All of the entities are still using just a regular state machine 00:46:45.826 --> 00:46:46.880 not a state stack. 00:46:46.880 --> 00:46:49.400 Wasn't necessary for this demonstration, though I'm sure 00:46:49.400 --> 00:46:52.879 there are some used cases for using a state stack for an entity. 00:46:52.879 --> 00:46:55.170 In this case, we're just using a regular state machine. 00:46:55.170 --> 00:46:59.360 So when we change to the walk state, we are calling enter as we've seen. 00:46:59.360 --> 00:47:02.830 And then we call self, checkForEncounter. 00:47:02.830 --> 00:47:07.340 And so self, checkForEncounter will set a flag 00:47:07.340 --> 00:47:14.290 if we have not started an encounter basically and will allow us to move. 00:47:14.290 --> 00:47:17.525 And if we have checked for an encounter, it will, 00:47:17.525 --> 00:47:21.470 or if we have triggered an encounter, it will push in checkForEncounter, 00:47:21.470 --> 00:47:26.310 it'll actually push a battle state onto the stack. 00:47:26.310 --> 00:47:30.900 So checkForEncounter just basically does what we said before. 00:47:30.900 --> 00:47:34.957 If the grass layer, because we have two layers, 00:47:34.957 --> 00:47:37.040 right, we have the base layer and the grass layer. 00:47:37.040 --> 00:47:43.760 So if the layer at yx where yx is are entities map x and map y. 00:47:43.760 --> 00:47:46.610 If the ID of that is equal to tall grass, 00:47:46.610 --> 00:47:50.750 and we have just a global constant table called 00:47:50.750 --> 00:47:52.960 Tile IDs, which has all these IDs. 00:47:52.960 --> 00:47:57.080 And math.random10 is equal to 1, OK, change the entity state to idle, 00:47:57.080 --> 00:48:00.500 so don't let them keep walking. 00:48:00.500 --> 00:48:02.645 Pause the field music rather than stopping, 00:48:02.645 --> 00:48:06.380 so that way when we come back to the field later and we press play, 00:48:06.380 --> 00:48:09.980 it will be at the exact point that it was before. 00:48:09.980 --> 00:48:14.900 Triggered the battle music, and then, we've seen this already, fade in state, 00:48:14.900 --> 00:48:16.940 push to the stack, right? 00:48:16.940 --> 00:48:19.945 So over one second, we're going to fade to white. 00:48:19.945 --> 00:48:22.070 So this will have the effect of the music starting, 00:48:22.070 --> 00:48:23.960 but we're fading to white right away, which 00:48:23.960 --> 00:48:27.785 is very sort of similar to how most RPGs do it. 00:48:27.785 --> 00:48:29.660 And then we have our callback function, which 00:48:29.660 --> 00:48:32.720 will execute as soon as the fade in state's done, right? 00:48:32.720 --> 00:48:35.720 In this case, push to battle state. 00:48:35.720 --> 00:48:37.900 Battle state takes an entity, and the entity 00:48:37.900 --> 00:48:39.650 has all of our Pokemon information, that's 00:48:39.650 --> 00:48:41.710 why we're passing that into the battle state. 00:48:41.710 --> 00:48:44.290 So the battle state can say, oh, what Pokemon do you have? 00:48:44.290 --> 00:48:49.010 OK, I'll be able to look at your party and say, OK, your first Pokemon 00:48:49.010 --> 00:48:52.520 is this, send him out to battle, et cetera, right? 00:48:52.520 --> 00:48:56.180 And then lastly, push a fade out state, right, 00:48:56.180 --> 00:49:02.570 because now we've got the battle state on top of the play state, 00:49:02.570 --> 00:49:05.260 but we want to fade into it, right? 00:49:05.260 --> 00:49:08.180 So we're going to fade, we're going to put the battle state first, 00:49:08.180 --> 00:49:10.820 and then because we're using a stack, we're 00:49:10.820 --> 00:49:14.450 going to put the fate out state on top of that, and then fade out to that, 00:49:14.450 --> 00:49:15.990 pop that off the stack. 00:49:15.990 --> 00:49:19.760 And then we have our battle state that we just pushed, right? 00:49:19.760 --> 00:49:21.760 And then self.encounterFound get's set here. 00:49:21.760 --> 00:49:25.130 And that's creating an encounter, checking randomly, 00:49:25.130 --> 00:49:27.760 pushing the right things under the stack, battle state, 00:49:27.760 --> 00:49:30.200 fade state, fade in, fade out. 00:49:30.200 --> 00:49:32.900 And then you're set to go. 00:49:32.900 --> 00:49:35.400 So that's effectively what the-- 00:49:35.400 --> 00:49:41.600 it's known in RPGs as the field versus the battle or encounter state. 00:49:41.600 --> 00:49:44.882 Even though we're calling it play state here, we've left the field, 00:49:44.882 --> 00:49:46.590 we've gone into the battle at this point. 00:49:46.590 --> 00:49:48.500 And so now we've seen basically everything 00:49:48.500 --> 00:49:51.790 that the field has to offer us. 00:49:51.790 --> 00:49:54.530 And we've covered everything that's relevant there. 00:49:54.530 --> 00:49:59.030 So we're going to take a break now for five to 10 minutes, 00:49:59.030 --> 00:50:01.980 and then when we get back from the break, 00:50:01.980 --> 00:50:04.640 we'll talk about GUI elements, panels, text boxes, 00:50:04.640 --> 00:50:09.470 and then we'll dive into the sort of mechanics of the battle state. 00:50:09.470 --> 00:50:12.600 All right, welcome back to lecture 7, Pokemon. 00:50:12.600 --> 00:50:14.960 So before the break, we talked about the play state, 00:50:14.960 --> 00:50:17.280 we talked about the states stack more importantly, 00:50:17.280 --> 00:50:20.870 and then we talked about how a anonymous functions are 00:50:20.870 --> 00:50:25.500 sort of the backbone to how we get a lot of this asynchronous 00:50:25.500 --> 00:50:29.820 and deferred behavior for our game, which is very common in RPGs, 00:50:29.820 --> 00:50:34.550 and I mean, a lot of genres, a lot of complicated genres of this sort. 00:50:34.550 --> 00:50:39.560 Another big key part of games like this are the graphical user 00:50:39.560 --> 00:50:42.890 interfaces, or GUIs as they're shortened to. 00:50:42.890 --> 00:50:46.550 Things like panels on the screen, things like labels-- 00:50:46.550 --> 00:50:53.880 text labels that move around, things like lists, text boxes, scroll bars, 00:50:53.880 --> 00:50:56.150 and you can get a lot crazier with it. 00:50:56.150 --> 00:51:03.140 In this particular lecture, we'll be talking mostly about panels, labels, 00:51:03.140 --> 00:51:05.870 text boxes, and scroll bars-- 00:51:05.870 --> 00:51:08.760 progress bars rather, not scroll bars. 00:51:08.760 --> 00:51:12.220 But the sort of the first I think corner-- 00:51:12.220 --> 00:51:17.000 or the first sort of like keystone GUI widget 00:51:17.000 --> 00:51:21.410 that we should take into consideration is the panel. 00:51:21.410 --> 00:51:27.203 So a panel is [INAUDIBLE]. 00:51:33.330 --> 00:51:41.680 So if we look at this in a game-- 00:51:41.680 --> 00:51:44.500 just pretend this is a panel I guess. 00:51:44.500 --> 00:51:47.710 So this is effectively all a panel is, right? 00:51:47.710 --> 00:51:49.960 It's just sort of a rectangle. 00:51:49.960 --> 00:51:54.107 It allows us to-- if you're looking at most user interfaces, 00:51:54.107 --> 00:51:56.440 like text boxes on your screen, or if you're on Facebook 00:51:56.440 --> 00:52:00.250 and you're looking at almost anything, like your little message 00:52:00.250 --> 00:52:03.520 window, a lot of those things at the very core, the very bottom, 00:52:03.520 --> 00:52:05.530 the foundational part is just a panel. 00:52:05.530 --> 00:52:11.023 So any guesses to how in Love2D, we can make a simple panel? 00:52:11.023 --> 00:52:12.899 AUDIENCE: Two rectangles of different colors. 00:52:12.899 --> 00:52:14.814 SPEAKER 1: Two rectangles of different colors, 00:52:14.814 --> 00:52:16.360 that's exactly what we end up doing. 00:52:16.360 --> 00:52:18.650 So that's effectively how we can make a panel. 00:52:18.650 --> 00:52:24.100 There's another way of making a panel, which we won't do in this lecture, 00:52:24.100 --> 00:52:26.530 but it's called-- 00:52:26.530 --> 00:52:30.640 we use as a construct called a nine patch. 00:52:30.640 --> 00:52:37.240 So a nine patch is-- 00:52:37.240 --> 00:52:41.000 imagine taking this little image here, and it's of some arbitrary size, 00:52:41.000 --> 00:52:42.704 but it's very small. 00:52:42.704 --> 00:52:44.620 And this is very similar to how a lot of games 00:52:44.620 --> 00:52:48.220 implemented their panels or their graphical user 00:52:48.220 --> 00:52:52.270 interfaces back in the 80s and 90s, I mean, to a lot of games till this day. 00:52:52.270 --> 00:52:58.330 But back when hardware was fundamentally tile based, 00:52:58.330 --> 00:53:06.850 you could take a image like this, split it up into nine pieces-- 00:53:06.850 --> 00:53:11.060 nine patch is where the terminology comes from. 00:53:11.060 --> 00:53:15.700 And sort of similar to how we actually constructed the Zelda dungeon, recall, 00:53:15.700 --> 00:53:20.950 where you have corner pieces, and then a top, bottom, right, and left side. 00:53:20.950 --> 00:53:24.320 You just layer this, one of each of these, 00:53:24.320 --> 00:53:28.000 first off, right, of the corner pieces. 00:53:28.000 --> 00:53:33.580 And then however many you need of these on the sides 00:53:33.580 --> 00:53:36.220 to create this rectangle, right? 00:53:36.220 --> 00:53:39.040 So imagine we've created-- 00:53:39.040 --> 00:53:45.260 these are all, if we can visualize these as being a bunch of tiles, right? 00:53:52.750 --> 00:53:55.120 So just imagine that we've taken these corner pieces, 00:53:55.120 --> 00:53:58.240 these are the corner pieces, we've taken one of each of those. 00:53:58.240 --> 00:54:02.410 And then we take these side pieces, and we just like draw a bunch of them 00:54:02.410 --> 00:54:04.000 like that. 00:54:04.000 --> 00:54:06.730 And then we take this centerpiece, and then we 00:54:06.730 --> 00:54:11.260 can either layer it, or tile it a bunch of times, or just stretch it. 00:54:11.260 --> 00:54:15.160 And stretching it has a bunch of nice bonuses associated with it depending 00:54:15.160 --> 00:54:18.660 on how you've set your filter mode, love.graphics.setdefaultfilter, 00:54:18.660 --> 00:54:21.130 if you set it to bilinear versus nearest, 00:54:21.130 --> 00:54:23.230 you can actually get a nice gradient. 00:54:23.230 --> 00:54:26.020 And if you set it to nearest, you get a nice pixelated look. 00:54:26.020 --> 00:54:29.761 But you'll see this often, and Unity has nice support for this. 00:54:29.761 --> 00:54:32.260 Take an image that has maybe more complicated than you could 00:54:32.260 --> 00:54:34.100 get with just two rectangles, right? 00:54:34.100 --> 00:54:37.780 Something that actually has a design and maybe a gradient color, and actually 00:54:37.780 --> 00:54:40.270 layer-- 00:54:40.270 --> 00:54:46.030 I mean, create a arbitrarily sized text box to fit your needs. 00:54:46.030 --> 00:54:49.770 And if these aren't even increments or whatever your tile size 00:54:49.770 --> 00:54:53.680 is on your 9 patch, you could just scale the top, bottom, left, and right side 00:54:53.680 --> 00:54:56.690 as well just to keep it scaled, the centerpiece. 00:54:56.690 --> 00:54:58.865 So does that makes sense. 00:54:58.865 --> 00:55:01.240 So this is common, we won't be using that in our lecture, 00:55:01.240 --> 00:55:06.182 but it's a very, very common piece to a lot of graphical user interface design. 00:55:06.182 --> 00:55:09.390 In a lot of games, you'll see it a lot if you get more into game development, 00:55:09.390 --> 00:55:12.400 so it's definitely worth talking about. 00:55:12.400 --> 00:55:17.620 Another piece that we'll be talking about today is the text box. 00:55:17.620 --> 00:55:20.814 So I mean, what's a guess as to what the text box, 00:55:20.814 --> 00:55:23.730 how we can implement a text box, and how we will implement a text box? 00:55:27.450 --> 00:55:33.000 So what foundational piece can we start with? 00:55:33.000 --> 00:55:35.023 We already have-- yeah? 00:55:35.023 --> 00:55:37.765 AUDIENCE: You just put use the love print 00:55:37.765 --> 00:55:40.171 to the screen over one of those boxes. 00:55:40.171 --> 00:55:43.420 SPEAKER 1: So use the love print to the screen over one of the boxes, exactly. 00:55:43.420 --> 00:55:44.280 Yep. 00:55:44.280 --> 00:55:49.800 So maintain a list of text items, right, text. 00:55:49.800 --> 00:55:57.090 And then just draw them inside a panel, and there's a text box. 00:55:57.090 --> 00:56:00.360 You've taken two ideas, and sort of mix them together. 00:56:00.360 --> 00:56:03.080 A selection is kind of the same thing. 00:56:03.080 --> 00:56:07.290 It's a the only difference being that with a selection-- 00:56:07.290 --> 00:56:10.720 so a selection is another thing if we think about, 00:56:10.720 --> 00:56:15.970 for example a menu where we have fight, and like run, 00:56:15.970 --> 00:56:20.880 and it may be in a more fleshed out game, we have like an item thing, 00:56:20.880 --> 00:56:21.840 right? 00:56:21.840 --> 00:56:25.830 So that's a menu effectively. 00:56:25.830 --> 00:56:28.650 It is very similar to what we get with a text box, 00:56:28.650 --> 00:56:32.910 but it's got a set of ingredients here, fight, item, run, 00:56:32.910 --> 00:56:40.170 which they aren't set to wrap, they're not one like contiguous set of text. 00:56:40.170 --> 00:56:42.420 It's just a bunch of items. 00:56:42.420 --> 00:56:45.870 And then nice thing about a selection is that you can 00:56:45.870 --> 00:56:49.830 have a cursor on your selection, right? 00:56:49.830 --> 00:56:53.052 And then what do we need to associate with like, for example, 00:56:53.052 --> 00:56:54.760 if we want this to actually do something, 00:56:54.760 --> 00:56:57.220 and if we think about what we've been doing so far, 00:56:57.220 --> 00:56:59.220 how do we go about implementing functionality 00:56:59.220 --> 00:57:00.680 with a selection like this? 00:57:00.680 --> 00:57:04.353 Like what needs to get associated with each of those entries in our selection? 00:57:08.430 --> 00:57:09.910 Callback function, right? 00:57:09.910 --> 00:57:11.680 Just as we've done with everything else. 00:57:11.680 --> 00:57:15.690 If you have a fight item here, each of these, if we think of the selection 00:57:15.690 --> 00:57:19.110 as being just this part of what we're looking at, 00:57:19.110 --> 00:57:22.700 right, because this background part is just a panel, we don't care about that. 00:57:22.700 --> 00:57:24.450 We care about the selection at the moment. 00:57:24.450 --> 00:57:27.250 The selection is the items and the arrow, right? 00:57:27.250 --> 00:57:30.630 When as we'll see in the assignment, your goal will actually 00:57:30.630 --> 00:57:33.750 be to take selection and get rid of the arrow functionality, 00:57:33.750 --> 00:57:36.060 because for the assignment, you don't need 00:57:36.060 --> 00:57:40.620 or want to have a selection active, a cursor active. 00:57:40.620 --> 00:57:43.620 You just want a list of things. 00:57:43.620 --> 00:57:52.570 But based on what the cursor is pointing at and when we press Enter or whatnot, 00:57:52.570 --> 00:57:55.770 we should index into the selection, and then 00:57:55.770 --> 00:57:59.680 execute a callback that's associated with each of these items. 00:57:59.680 --> 00:58:02.400 And that's how we can get behavior out of the selection, 00:58:02.400 --> 00:58:05.410 rather than just being a list of things that we render to the screen. 00:58:05.410 --> 00:58:08.340 If we have fight, and we click Enter, a callback 00:58:08.340 --> 00:58:12.247 is set to maybe push a state onto the stack that 00:58:12.247 --> 00:58:15.330 will trigger an interaction between the two entities on the screen, right? 00:58:15.330 --> 00:58:17.010 The first one will attack the second one, 00:58:17.010 --> 00:58:18.600 the second one will attack the first one. 00:58:18.600 --> 00:58:21.766 And that's sort of its own asynchronous set of states that do its own thing, 00:58:21.766 --> 00:58:24.750 but it's kicked off via an anonymous function 00:58:24.750 --> 00:58:27.980 that we've associated with each of these things, right? 00:58:27.980 --> 00:58:32.460 An item pushes another state, which is like an item mini state, where then you 00:58:32.460 --> 00:58:36.240 open up a brand new set of menus that you can look through all your items, 00:58:36.240 --> 00:58:40.246 and each of those items has a callback associated with it, right? 00:58:40.246 --> 00:58:42.120 Your potion has a callback associated with it 00:58:42.120 --> 00:58:45.750 that says, when I click on this, either by default, 00:58:45.750 --> 00:58:48.120 just restore the HP of my active Pokemon, 00:58:48.120 --> 00:58:50.070 or let me choose who to restore. 00:58:50.070 --> 00:58:53.960 So therefore, push another state, which is like a select Pokemon 00:58:53.960 --> 00:58:58.120 screen with its own set of callbacks associated with each of those. 00:58:58.120 --> 00:59:01.911 It's just in order to get all of this sort of complicated behavior 00:59:01.911 --> 00:59:04.410 that you need to, it's really ultimately just pushing states 00:59:04.410 --> 00:59:07.290 and adding callback functions to all of these different options 00:59:07.290 --> 00:59:09.570 that you can select. 00:59:09.570 --> 00:59:13.589 And then run, push a fade state, and then pop this state, 00:59:13.589 --> 00:59:14.880 and then push a fade out state. 00:59:14.880 --> 00:59:16.380 And that's really all we're doing. 00:59:16.380 --> 00:59:20.250 And so this look at all of these GUI widgets 00:59:20.250 --> 00:59:24.060 here is just sort of a conceptual look, but we'll take a look very shortly 00:59:24.060 --> 00:59:25.830 at some actual implementation. 00:59:25.830 --> 00:59:34.060 The last one that I want to look at is the progress bar. 00:59:34.060 --> 00:59:37.350 So a progress bar for example, the HP that we've 00:59:37.350 --> 00:59:45.000 seen in the actual battle where when we take damage, it goes from right to 00:59:45.000 --> 00:59:46.009 left. 00:59:46.009 --> 00:59:48.300 Any guesses as to how we've implemented a progress bar? 00:59:48.300 --> 00:59:48.914 Yes, Tony? 00:59:48.914 --> 00:59:50.534 AUDIENCE: Once again, two rectangles. 00:59:50.534 --> 00:59:52.200 SPEAKER 1: Two rectangles, yes, exactly. 00:59:52.200 --> 00:59:55.860 One, and then the nice thing about rectangles in Love2D 00:59:55.860 --> 01:00:00.840 is you can set the edges on them to be rounded or not 01:00:00.840 --> 01:00:02.760 via an optional parameter. 01:00:02.760 --> 01:00:05.760 So without anything more complicated than a rectangle 01:00:05.760 --> 01:00:09.917 we can just create these sort of almost ellipsoid progress 01:00:09.917 --> 01:00:11.250 bars, very simple progress bars. 01:00:11.250 --> 01:00:14.310 Ones the red, right, the red that's the background. 01:00:14.310 --> 01:00:15.870 And then ones the outline, the black. 01:00:15.870 --> 01:00:18.780 And one is set to fill with the first parameter, 01:00:18.780 --> 01:00:21.850 one's set to line with the first parameter. 01:00:21.850 --> 01:00:24.750 Now how do we go about animating whether or not, 01:00:24.750 --> 01:00:29.080 how do we animate the decreasing amount of health when we take damage? 01:00:29.080 --> 01:00:29.580 Yes? 01:00:29.580 --> 01:00:31.597 AUDIENCE: Between the width. 01:00:31.597 --> 01:00:33.180 SPEAKER 1: Between the width, exactly. 01:00:33.180 --> 01:00:34.560 And what are we tweening it by? 01:00:34.560 --> 01:00:36.626 How are we tweening it? 01:00:36.626 --> 01:00:38.792 How would we calculate how much we need to tween it? 01:00:38.792 --> 01:00:44.536 AUDIENCE: Well, you could just have your width equal your health remaining. 01:00:44.536 --> 01:00:47.160 SPEAKER 1: If your width is set to equal your health remaining, 01:00:47.160 --> 01:00:49.860 then your health is maybe 10. 01:00:49.860 --> 01:00:52.860 And you want your health bar to be like 100 pixels 01:00:52.860 --> 01:00:54.585 long, how is that going to work though? 01:00:54.585 --> 01:00:55.740 AUDIENCE: Multiply it. 01:00:55.740 --> 01:00:57.810 SPEAKER 1: You could multiply it, but if you 01:00:57.810 --> 01:01:01.260 know the width that you want your progress bar to be, 01:01:01.260 --> 01:01:05.760 you can just multiply the width by the ratio of the max 01:01:05.760 --> 01:01:12.030 value of your HP, or sorry, the ratio of your current HP over your max HP, 01:01:12.030 --> 01:01:12.990 right? 01:01:12.990 --> 01:01:16.200 So if you're missing-- if you have 50 HP, and you're missing 5 HP, 01:01:16.200 --> 01:01:18.240 your ratio is 45 over 50. 01:01:18.240 --> 01:01:22.950 And if you multiply that by your width, you get the exact amount of width 01:01:22.950 --> 01:01:26.625 that you need regardless of how wide you want the bar to be, 01:01:26.625 --> 01:01:29.250 if you want to be 1,000 pixels, if you want it to be 50 pixels, 01:01:29.250 --> 01:01:35.569 as long as you multiply current health over max health times the width, 01:01:35.569 --> 01:01:37.110 you'll get that ratio no matter what. 01:01:37.110 --> 01:01:38.764 Does that makes sense? 01:01:38.764 --> 01:01:39.590 Cool. 01:01:39.590 --> 01:01:43.140 So that's a look at all the GUI widgets that we're looking at, how they sort 01:01:43.140 --> 01:01:46.630 relate to what we're doing. 01:01:46.630 --> 01:01:48.760 We'll take a look at their implementation here. 01:01:48.760 --> 01:01:51.141 So I'm going to go ahead and open up the panel. 01:01:51.141 --> 01:01:52.890 And I'm going to move a little bit quickly 01:01:52.890 --> 01:01:57.150 so we can get into sort of the meat of the battle here. 01:01:57.150 --> 01:02:03.420 The panel is as we've said before just two rectangles, right? 01:02:03.420 --> 01:02:06.000 It takes in an xy within a height. 01:02:06.000 --> 01:02:08.060 And then we would just draw two rectangles. 01:02:08.060 --> 01:02:09.750 One is larger than the other. 01:02:09.750 --> 01:02:12.930 The bottom rectangle is slightly larger than the top rectangle. 01:02:12.930 --> 01:02:16.010 So the first rectangle gets drawn and it's whitish. 01:02:16.010 --> 01:02:21.020 And then-- oh, I'm sorry, sorry about that. 01:02:21.020 --> 01:02:23.810 We have a xy within a height. 01:02:23.810 --> 01:02:26.120 And then we're drawing two rectangles to the screen. 01:02:26.120 --> 01:02:29.330 We have the background rectangle, which is drawn first, 01:02:29.330 --> 01:02:32.840 which is going to be the full xy width and height of the panel. 01:02:32.840 --> 01:02:36.290 And then we're going to draw that at a white color, and then draw-- 01:02:36.290 --> 01:02:39.500 in the context of this game-- we're drawing everything at the same color, 01:02:39.500 --> 01:02:40.760 but we can change the color. 01:02:40.760 --> 01:02:42.900 If we wanted to parameterize it, we could do that. 01:02:42.900 --> 01:02:46.070 We could set, we could have a color option here in the constructor. 01:02:46.070 --> 01:02:49.190 We're not doing that, we're just drawing everything the same color. 01:02:49.190 --> 01:02:51.510 But that's how you would get like customized menus, 01:02:51.510 --> 01:02:54.694 some RPGs let you do that. 01:02:54.694 --> 01:02:57.860 And then what we're doing here is we're just within a small slightly smaller 01:02:57.860 --> 01:02:58.730 boundary. 01:02:58.730 --> 01:03:02.179 So just two pixels smaller on the x and y. 01:03:02.179 --> 01:03:04.220 Where you are going to draw the second rectangle, 01:03:04.220 --> 01:03:06.950 which is a kind of dark shade of gray. 01:03:06.950 --> 01:03:09.425 And that is a panel, that is all panel is. 01:03:09.425 --> 01:03:11.300 And then we could just have a function called 01:03:11.300 --> 01:03:14.430 toggle, which sets it to visible or not visible. 01:03:14.430 --> 01:03:19.130 And if it's visible, get rid of it, or if it's visible, sorry, draw it. 01:03:19.130 --> 01:03:21.560 Otherwise, don't draw anything when it gets rendered. 01:03:21.560 --> 01:03:23.240 So that's a panel in a nutshell. 01:03:23.240 --> 01:03:26.160 Any questions? 01:03:26.160 --> 01:03:26.960 Cool. 01:03:26.960 --> 01:03:32.160 So the next thing that we should look at is the text box. 01:03:32.160 --> 01:03:33.290 So a text box-- 01:03:33.290 --> 01:03:37.340 so the text box is a little bit more complicated than a panel. 01:03:37.340 --> 01:03:41.990 A text box in a nutshell needs to take in some arbitrary body of text, 01:03:41.990 --> 01:03:45.590 and it needs to chop it up based on how wide your text box is. 01:03:45.590 --> 01:03:49.070 And if it surpasses the height of your text box, 01:03:49.070 --> 01:03:54.710 right, ideally, you should page your text so that you can press Space bar, 01:03:54.710 --> 01:04:00.020 Enter and go through pages of text until you've exhausted all of your text. 01:04:00.020 --> 01:04:06.170 And you press Enter one last time, and you get rid of that text box. 01:04:06.170 --> 01:04:11.210 And so we have a panel here, which we have an xy width and height 01:04:11.210 --> 01:04:12.710 in our constructor for the text box. 01:04:12.710 --> 01:04:14.349 And we have our text as well. 01:04:14.349 --> 01:04:16.640 And then we have a font if we want to explicitly decide 01:04:16.640 --> 01:04:19.490 what font we want to use. 01:04:19.490 --> 01:04:25.190 In this case, or at large, we're going to say 01:04:25.190 --> 01:04:30.530 that we instantiate a panel at xy width and height, nothing too fancy. 01:04:30.530 --> 01:04:35.510 And then the fancyish part, the slightly more complicated part 01:04:35.510 --> 01:04:38.330 is here on line 20 where we say, underscore 01:04:38.330 --> 01:04:46.170 self.textChucks gets self.font, getWrap, self.text, self.width minus 12. 01:04:46.170 --> 01:04:49.190 So anybody know what this function does or want to take a guess? 01:04:55.190 --> 01:04:55.690 Yes? 01:04:55.690 --> 01:04:58.023 AUDIENCE: Is that the page thing you were talking about? 01:04:58.023 --> 01:05:01.192 SPEAKER 1: Exactly, it's the paging of the text. 01:05:01.192 --> 01:05:02.650 Is the chunking of the text rather. 01:05:02.650 --> 01:05:07.060 Not the paging of the text, so much as is the chunking of the text, which 01:05:07.060 --> 01:05:08.650 we will use to page the text. 01:05:08.650 --> 01:05:12.430 So we take some you know arbitrarily large body of text, 01:05:12.430 --> 01:05:16.060 it can be as large as we want it to be, and given-- 01:05:16.060 --> 01:05:20.090 this is actually a function of to Love2D font object. 01:05:20.090 --> 01:05:23.020 So this is given to us from Love2D. 01:05:23.020 --> 01:05:26.350 Get wrap will return two values, the second of which 01:05:26.350 --> 01:05:32.620 is all of the pieces of text that the main big body is divided into 01:05:32.620 --> 01:05:33.770 based on the width. 01:05:33.770 --> 01:05:37.270 So this self.width of minus 12, that's how wide 01:05:37.270 --> 01:05:39.917 it's going to divide our text into chunks of up to, 01:05:39.917 --> 01:05:42.250 it could be slightly smaller than, because it divides it 01:05:42.250 --> 01:05:44.740 based on the word. 01:05:44.740 --> 01:05:51.280 But no piece of text will ever exceed self.width minus 12 width. 01:05:51.280 --> 01:05:57.040 And this will allow us to then render several lines of text within our text 01:05:57.040 --> 01:06:01.420 box, and they will never exceed the boundary, right? 01:06:01.420 --> 01:06:05.770 And so the paging functionality is actually in next chunks. 01:06:05.770 --> 01:06:09.400 So we call self next here at the end of [? knitt ?] function. 01:06:09.400 --> 01:06:13.750 And then self next basically checks to see, OK, are we at the end of the text? 01:06:13.750 --> 01:06:16.350 If we are, then we're not going to display any text, 01:06:16.350 --> 01:06:18.450 and we're going to close the window. 01:06:18.450 --> 01:06:20.110 We're going to close the panel. 01:06:20.110 --> 01:06:24.470 But if we are not at the end of the text, like we still get text left, 01:06:24.470 --> 01:06:26.830 what we want to do is new table. 01:06:26.830 --> 01:06:30.940 And then we're going to, up to three iterations, 01:06:30.940 --> 01:06:33.220 we keep track of where we are in our chunks, right? 01:06:33.220 --> 01:06:36.827 We get self.text chunks equal to all of those chunks, right. 01:06:36.827 --> 01:06:38.410 And that could be an arbitrary number. 01:06:38.410 --> 01:06:41.719 It can be only one chunk, there could be like 30 chunks, right? 01:06:41.719 --> 01:06:43.510 We need a counter to keep track of where we 01:06:43.510 --> 01:06:47.530 are in terms of like based on what page we're on, right, 01:06:47.530 --> 01:06:51.680 and however many lines we rendered to the screen thus far. 01:06:51.680 --> 01:06:55.030 So starting at I, and I get's chunk counter, 01:06:55.030 --> 01:06:57.100 and chunk counter will get incremented by three 01:06:57.100 --> 01:07:00.430 every time we call next chunks, which is every page. 01:07:00.430 --> 01:07:04.030 We could have easily just called this next page as well. 01:07:04.030 --> 01:07:05.950 It's going to insert into that chunks table 01:07:05.950 --> 01:07:08.560 that we just created, self.textChucks at i. 01:07:08.560 --> 01:07:12.250 And once we've reached the number of chunks total 01:07:12.250 --> 01:07:16.420 that we returned from get wrap, we're going to flag end of text 01:07:16.420 --> 01:07:19.990 as being true, and then we're going to return it. 01:07:19.990 --> 01:07:22.300 And so what this will do is, eventually, we're 01:07:22.300 --> 01:07:26.920 going to be equal to the number of chunks that we got from font get wrap, 01:07:26.920 --> 01:07:28.300 right? 01:07:28.300 --> 01:07:31.585 And once we are, that will signal with next 01:07:31.585 --> 01:07:34.570 that it's time to close the text box, because end of text 01:07:34.570 --> 01:07:38.920 will have been set to true at the end of that last chunking process. 01:07:38.920 --> 01:07:41.562 And then we can see here, when we update text box, 01:07:41.562 --> 01:07:43.520 and that whenever it's on the top of the stack, 01:07:43.520 --> 01:07:47.000 remember, we're looking for a Space or an Enter press, 01:07:47.000 --> 01:07:48.880 and then we just call self next. 01:07:48.880 --> 01:07:53.170 And that will have the effect of eventually closing our text box. 01:07:53.170 --> 01:07:56.230 And then is closed recall, we looked at that earlier, we checked 01:07:56.230 --> 01:07:59.300 to see it is the text box closed? 01:07:59.300 --> 01:08:01.270 And that's just a flag that we set here. 01:08:01.270 --> 01:08:06.280 And then for rendering purposes, we render the panel first. 01:08:06.280 --> 01:08:10.750 And then for each of our displaying chunks, so we only have up to three 01:08:10.750 --> 01:08:16.480 displaying chunks at one time, which gets set by the next chunks function. 01:08:16.480 --> 01:08:22.569 We just print that to the screen using i as a multiplier on our y. 01:08:22.569 --> 01:08:29.439 And so that will render up two or three lines, i, i plus 1, i plus 2. 01:08:29.439 --> 01:08:31.899 Any questions as to how the text box works? 01:08:34.460 --> 01:08:36.939 It's a little more work than the panel for sure, 01:08:36.939 --> 01:08:38.470 but it's fairly straightforward. 01:08:38.470 --> 01:08:40.960 We're just keeping a list of a bunch of text things, 01:08:40.960 --> 01:08:46.200 and then we're just chunking them based on how wide the text 01:08:46.200 --> 01:08:48.100 box is, the dimensions thereof. 01:08:50.710 --> 01:08:53.040 And then let's take one look at this selection. 01:08:53.040 --> 01:09:01.240 So a selection is basically, a list of text items with a cursor, right? 01:09:01.240 --> 01:09:04.540 And as I said before when we were looking at the screen over there, 01:09:04.540 --> 01:09:08.890 each of those text items has a text value and a callback function. 01:09:08.890 --> 01:09:10.840 And the callback function is what allows us 01:09:10.840 --> 01:09:16.130 to assign behavior to this selection object beyond just displaying things, 01:09:16.130 --> 01:09:16.630 right? 01:09:16.630 --> 01:09:18.921 Because when you have a menu, when you have a selection 01:09:18.921 --> 01:09:22.479 and you select something, you want behavior to happen, right? 01:09:22.479 --> 01:09:26.439 So each of these items indef.items will expect to have a callback function. 01:09:29.939 --> 01:09:32.649 And then here, when we update the selection, what we're doing 01:09:32.649 --> 01:09:35.398 is we're updating whatever our current selection is, which is just 01:09:35.398 --> 01:09:38.740 a number between 1 and the number of items in that selection making sure 01:09:38.740 --> 01:09:42.590 that if we're at one and we go minus one, that we go back to the bottom. 01:09:42.590 --> 01:09:45.310 And if we're at the bottom when we press, and we go up, 01:09:45.310 --> 01:09:47.240 we go back to the top. 01:09:47.240 --> 01:09:51.880 And we play sounds, cutesy, things like that. 01:09:51.880 --> 01:09:52.979 And then for each-- 01:09:52.979 --> 01:09:56.440 and for our selection here, from one to number of items, 01:09:56.440 --> 01:09:58.720 we calculate how much padding that we need. 01:09:58.720 --> 01:10:01.480 And we draw the cursor at our current selection, 01:10:01.480 --> 01:10:06.700 and then we draw each item based on i and whatever our gap width is 01:10:06.700 --> 01:10:08.680 of our panel, which we assign it to. 01:10:08.680 --> 01:10:11.920 So we divide our panel up, and then basically just 01:10:11.920 --> 01:10:14.650 keep track of where current y is and draw 01:10:14.650 --> 01:10:17.620 the actual selection and the cursor if that's 01:10:17.620 --> 01:10:19.300 the current selection to the screen. 01:10:21.820 --> 01:10:25.060 Any questions as to how a selection sort of works? 01:10:29.740 --> 01:10:35.260 Notice here, if we press Return, if our selection is being updated, 01:10:35.260 --> 01:10:40.450 self.items at self.currentSelection.onSelect. 01:10:40.450 --> 01:10:44.680 So it's expected that that item will have an onSelect function, which 01:10:44.680 --> 01:10:47.560 is that callback function. 01:10:47.560 --> 01:10:50.259 OK, and lastly, we'll take a look at the menu. 01:10:50.259 --> 01:10:52.300 And then we'll finally take a look at the battle, 01:10:52.300 --> 01:10:55.420 which is where sort of everything kind of comes together with all of this. 01:10:55.420 --> 01:10:56.810 And that'll be it. 01:10:56.810 --> 01:10:59.600 And then we'll talk about the assignment. 01:10:59.600 --> 01:11:01.660 So the menu is a panel and a selection together. 01:11:01.660 --> 01:11:05.770 That's the gist behind what a menu is in this game. 01:11:05.770 --> 01:11:07.930 You can define a menu to be a lot of things, 01:11:07.930 --> 01:11:11.620 and you can get a lot more complicated with a menu, but in this example, 01:11:11.620 --> 01:11:15.190 in this implementation, we're just saying a menu is a selection 01:11:15.190 --> 01:11:17.950 and a panel put together as one item. 01:11:17.950 --> 01:11:24.810 And we've seen it in the game, [? if we're ?] going to run it. 01:11:24.810 --> 01:11:26.910 That's just a text box. 01:11:26.910 --> 01:11:28.557 Going to look for a battle. 01:11:32.050 --> 01:11:33.077 OK, so here's a battle. 01:11:33.077 --> 01:11:35.410 That's just an empty panel at the bottom, regular panel, 01:11:35.410 --> 01:11:36.410 but now it's a text box. 01:11:36.410 --> 01:11:38.710 We push the text box onto the stack. 01:11:38.710 --> 01:11:40.840 Push another text box onto the stack. 01:11:40.840 --> 01:11:42.710 And so this is a menu right here. 01:11:42.710 --> 01:11:45.910 Notice that there is a cursor and there's 01:11:45.910 --> 01:11:47.890 a selection embedded within a panel. 01:11:47.890 --> 01:11:50.380 And each of those items, the fight and the run, 01:11:50.380 --> 01:11:54.440 those have a callback associated with them. 01:11:54.440 --> 01:11:56.950 The purpose of the fight callback is to trigger a new state 01:11:56.950 --> 01:12:02.830 where the two Pokemon asynchronously attack each other, in chain behavior 01:12:02.830 --> 01:12:03.760 one after the other. 01:12:03.760 --> 01:12:07.720 And then run pushes a dialogue, then pushes a fade state, 01:12:07.720 --> 01:12:11.650 then pops both of them, and then pushes a fade out state 01:12:11.650 --> 01:12:13.330 and puts us back to the play state. 01:12:13.330 --> 01:12:15.330 So that's effectively what's going on and that's 01:12:15.330 --> 01:12:18.130 an example of what the menu looked like. 01:12:18.130 --> 01:12:21.970 And so a menu, just a selection with a panel put together. 01:12:21.970 --> 01:12:26.650 When we draw the menu, we draw the panel and then the selection. 01:12:26.650 --> 01:12:29.860 And then when we update the menu, we only update the selection, 01:12:29.860 --> 01:12:32.305 because that's all we care about. 01:12:32.305 --> 01:12:34.060 And that's basically it. 01:12:34.060 --> 01:12:37.810 And so the menu itself will get a def, that def 01:12:37.810 --> 01:12:41.362 should have items, that items will get passed to the selection. 01:12:44.140 --> 01:12:46.105 That's pretty much, that's it for the-- 01:12:46.105 --> 01:12:47.580 oh, progress bar as well. 01:12:47.580 --> 01:12:51.440 We'll look at progress bars when we get to the actual battle state. 01:12:51.440 --> 01:12:55.390 So now, let's take a look at a few of the classes and data structures 01:12:55.390 --> 01:12:57.800 that are pertinent to the Pokemon themselves. 01:12:57.800 --> 01:13:00.670 So if you look at party as are first class, very 01:13:00.670 --> 01:13:03.250 simple class, literally just this-- 01:13:03.250 --> 01:13:07.060 self.pokemon is def.pokemon is just a container at this point. 01:13:07.060 --> 01:13:09.970 You can take this-- 01:13:09.970 --> 01:13:12.640 I mean, even in I think a fully fleshed game, 01:13:12.640 --> 01:13:15.850 you wouldn't really need much more than just this. 01:13:15.850 --> 01:13:18.230 But if you needed to expand upon this idea at all 01:13:18.230 --> 01:13:21.700 and you know preserve metadata that exists for the party, 01:13:21.700 --> 01:13:24.340 this would be a perfect way to do it. 01:13:24.340 --> 01:13:31.390 The actual pokemon class itself is not a whole lot more than effectively 01:13:31.390 --> 01:13:33.400 a bunch of stats. 01:13:33.400 --> 01:13:36.240 And that's a lot of what an RPG is. 01:13:36.240 --> 01:13:38.876 This genre is-- it's mostly just numbers. 01:13:38.876 --> 01:13:40.750 You're just comparing numbers against numbers 01:13:40.750 --> 01:13:42.640 and then adding a roll of the dice. 01:13:42.640 --> 01:13:46.690 That's effectively, that's what Dungeons & Dragons, a lot of it is. 01:13:46.690 --> 01:13:47.696 And that's-- yes? 01:13:47.696 --> 01:13:49.630 AUDIENCE: Would it make more sense to store 01:13:49.630 --> 01:13:57.100 just delta per level and your initial one, so you can have fewer variables? 01:13:57.100 --> 01:13:58.460 SPEAKER 1: Say it one more time. 01:13:58.460 --> 01:14:00.376 AUDIENCE: Wouldn't it make more sense, instead 01:14:00.376 --> 01:14:03.150 of storing your HP and everything for each level 01:14:03.150 --> 01:14:06.490 to store your initial stats in each area, 01:14:06.490 --> 01:14:09.990 and how much you would go up per level. 01:14:09.990 --> 01:14:14.080 SPEAKER 1: Would it make more sense to store the amount that you go up 01:14:14.080 --> 01:14:16.450 per level for your Pokemon? 01:14:16.450 --> 01:14:19.070 Yes, that is what we're doing. 01:14:19.070 --> 01:14:20.800 So we have a base-- 01:14:20.800 --> 01:14:24.910 so here's how the split works for the stats in this case, right? 01:14:24.910 --> 01:14:28.860 We have base HP, base attack, base defense, and base speed. 01:14:28.860 --> 01:14:31.600 A level 1 Pokemon has-- a level 0 Pokemon 01:14:31.600 --> 01:14:35.800 has these stats of this species, right? 01:14:35.800 --> 01:14:39.430 Every Bamboon or whatever Pokemon that we choose 01:14:39.430 --> 01:14:42.820 will have whatever we've allocated it to be it's base HP, 01:14:42.820 --> 01:14:45.280 base, attack, base defense, base speed. 01:14:45.280 --> 01:14:50.500 And then the thing about Pokemon and I mean, a lot of RPGs 01:14:50.500 --> 01:14:52.660 will sort of do this thing, but we need some way 01:14:52.660 --> 01:14:58.420 of leveling up the Pokemon in an necessarily non-deterministic way. 01:14:58.420 --> 01:15:02.782 Like two Piggies that level up may not have the same stats, right? 01:15:02.782 --> 01:15:04.990 One might have slightly higher attack than the other, 01:15:04.990 --> 01:15:07.240 one might have slightly higher defense than the other. 01:15:07.240 --> 01:15:11.020 We do this using what's called an IV, and that's what Pokemon itself does. 01:15:11.020 --> 01:15:13.450 And it's short for individual value, this is sort of 01:15:13.450 --> 01:15:16.810 like the DNA of your Pokemon, right? 01:15:16.810 --> 01:15:23.420 So this HP IV is separate from your base attack, base speed, base et cetera. 01:15:23.420 --> 01:15:26.890 And this basically, it gets compared against a dice roll every time 01:15:26.890 --> 01:15:28.480 you level up three times. 01:15:31.610 --> 01:15:34.330 And this is how I've programmed it, it's not necessarily 01:15:34.330 --> 01:15:38.890 how Pokemon itself does it, but you will roll a dice six times, 01:15:38.890 --> 01:15:42.760 or three times, one through six like a normal die. 01:15:42.760 --> 01:15:49.630 And you'll look to see if that roll is greater than your IV, right? 01:15:49.630 --> 01:15:55.990 Or it'll check to see whether your IV is less than or equal to that dice roll. 01:15:55.990 --> 01:15:57.560 And if it is-- 01:15:57.560 --> 01:16:00.640 or sorry, if it's greater than or equal to that dice roll. 01:16:00.640 --> 01:16:06.580 And if it is, it will increment that stat by 1 for those three dice rolls. 01:16:06.580 --> 01:16:11.500 So you can get up to three more, or you can increase the stat 01:16:11.500 --> 01:16:14.200 by up to three times per level. 01:16:14.200 --> 01:16:16.990 But you can only have an IV up to five. 01:16:16.990 --> 01:16:23.056 So you're rolling against a six, and you will occasionally not roll a 6. 01:16:23.056 --> 01:16:27.970 It checks to see whether or not the IV is 01:16:27.970 --> 01:16:29.800 greater than or equal to the dice roll. 01:16:29.800 --> 01:16:32.650 And if it's not greater than or equal to the dice roll in the event 01:16:32.650 --> 01:16:36.430 that it is a six, or if the IV is up to a four 01:16:36.430 --> 01:16:39.700 for example, which means a five or six will go against it, 01:16:39.700 --> 01:16:41.770 then it will not get a stat increase. 01:16:41.770 --> 01:16:44.920 And this is a sort of simple way of implementing this DNA based system. 01:16:44.920 --> 01:16:47.320 It's randomized, but it's a weighted, right? 01:16:47.320 --> 01:16:50.050 If you have a higher IV, you have a higher likelihood 01:16:50.050 --> 01:16:53.350 of being greater than or equal to the dice roll. 01:16:53.350 --> 01:16:55.960 And so that's how we implement stat increases. 01:16:55.960 --> 01:17:03.130 And then we need a way of keeping track of what our stats are, 01:17:03.130 --> 01:17:04.660 like our actual stats. 01:17:04.660 --> 01:17:07.330 So our actual HP, our actual attack, our actual defense, 01:17:07.330 --> 01:17:10.165 and actual speed that's been calculated level by level, 01:17:10.165 --> 01:17:11.665 we need a way to keep track of that. 01:17:11.665 --> 01:17:14.190 We need level, we need our current XP, and then 01:17:14.190 --> 01:17:15.940 we need our-- and the amount of XP to gain 01:17:15.940 --> 01:17:19.270 a level, which will get higher and higher per level, as you can see here, 01:17:19.270 --> 01:17:24.520 because it takes in the self.level times self.level. 01:17:24.520 --> 01:17:28.150 And then it multiplies that by five times 0.75. 01:17:28.150 --> 01:17:29.470 And then your current HP. 01:17:32.340 --> 01:17:38.230 So we're really not storing our value level by level, 01:17:38.230 --> 01:17:42.220 we need the base because we need to know what our base was. 01:17:42.220 --> 01:17:46.910 I mean, we could effectively globally reference these variables, 01:17:46.910 --> 01:17:49.810 but it's minor efficiency gains at that point. 01:17:49.810 --> 01:17:52.300 But we need the IVs and we need the-- 01:17:52.300 --> 01:17:56.050 I mean, we need a reference to the IVs, we need a reference to the base HP, 01:17:56.050 --> 01:18:01.750 and we need to keep track of whatever our actual stats are, 01:18:01.750 --> 01:18:04.210 and then our current HP always, because our current HP 01:18:04.210 --> 01:18:07.010 can differ from our actual HP. 01:18:07.010 --> 01:18:10.690 And in the actual game, you can have your attack, defense, 01:18:10.690 --> 01:18:13.960 and speed also vary match by match, because you 01:18:13.960 --> 01:18:17.770 have moves that lower your speed, lower your attack, 01:18:17.770 --> 01:18:19.450 lower your defense, et cetera. 01:18:19.450 --> 01:18:21.200 In this case, we haven't implemented that, 01:18:21.200 --> 01:18:23.459 so we don't have a current attack, current defense. 01:18:23.459 --> 01:18:26.500 But in a more complete implementation, you would have that sort of thing. 01:18:26.500 --> 01:18:28.125 Does that sort of answer your question? 01:18:28.125 --> 01:18:29.290 Is that in the right vain? 01:18:29.290 --> 01:18:29.790 OK. 01:18:32.390 --> 01:18:35.020 And so here's the level up code. 01:18:35.020 --> 01:18:38.200 So like I said, three dice rolls, one to three. 01:18:38.200 --> 01:18:43.450 If six is less than or equal to our IV, so it could be a six, in which case, 01:18:43.450 --> 01:18:47.160 it would be greater than what are max IV could possibly be. 01:18:47.160 --> 01:18:52.150 IVs range from one to five, but if it's less than or equal to that IV, 01:18:52.150 --> 01:18:54.250 then we're going to consider that a stat increase. 01:18:54.250 --> 01:19:03.490 It's a weighted odd to determine whether or not we get a stat boost. 01:19:03.490 --> 01:19:07.340 And it does this for every stat, and then it returns all of the increases. 01:19:07.340 --> 01:19:11.590 And this is relevant, this line 95 for a return HP increase, 01:19:11.590 --> 01:19:13.540 return attack increase, defense increase. 01:19:13.540 --> 01:19:16.690 This will be relevant for assignment 7, because your goal is 01:19:16.690 --> 01:19:20.650 to take these increases and actually display them to this user in the battle 01:19:20.650 --> 01:19:23.560 state when he gets a victory, or he or she gets a victory 01:19:23.560 --> 01:19:25.310 and has gained a level. 01:19:25.310 --> 01:19:29.740 You will display a menu with a selection that has all of these things, 01:19:29.740 --> 01:19:30.970 and you'll need this value. 01:19:30.970 --> 01:19:36.550 So it returns these values here, and you'll be calling this function any way 01:19:36.550 --> 01:19:39.390 from your battle state stats level up. 01:19:39.390 --> 01:19:45.310 Or we'll be calling level up rather, which returns self stats level up. 01:19:45.310 --> 01:19:47.630 And that's all a Pokemon is. 01:19:47.630 --> 01:19:50.700 It's effectively mostly a data structure. 01:19:50.700 --> 01:19:57.640 And we use this in our battles to throw dice effectively back and forth, 01:19:57.640 --> 01:20:05.650 and have a victor and a loser, and then gain XP and gain levels that way. 01:20:05.650 --> 01:20:09.490 So any questions as to how a Pokemon object class works? 01:20:12.370 --> 01:20:13.962 Cool. 01:20:13.962 --> 01:20:16.670 We'll take a quick look at what the actual definitions look like, 01:20:16.670 --> 01:20:18.240 which you can probably take a guess. 01:20:18.240 --> 01:20:20.870 It's very simple, just key names. 01:20:20.870 --> 01:20:24.300 And then we have the actual name, we have the sprite names, 01:20:24.300 --> 01:20:26.810 we have the HP, attack, defense-- 01:20:26.810 --> 01:20:29.390 all the things that get put into the actual object, 01:20:29.390 --> 01:20:31.700 they need a reference to in the definitions. 01:20:31.700 --> 01:20:34.101 And so Pokemon ultimately are just this, they're 01:20:34.101 --> 01:20:37.100 just data, right, which is what we talked about in a prior lecture, data 01:20:37.100 --> 01:20:38.210 driven design. 01:20:38.210 --> 01:20:40.220 The more you can take all of your Pokemon 01:20:40.220 --> 01:20:44.210 and make them into, or anything, Pokemon or any object, 01:20:44.210 --> 01:20:47.270 and turn it into an easy to write data structure like this, 01:20:47.270 --> 01:20:49.040 the easier it is for you to add more. 01:20:49.040 --> 01:20:53.304 We could easily add, it wouldn't take too long to create 150 of these. 01:20:53.304 --> 01:20:55.220 I mean, they wouldn't be all that interesting, 01:20:55.220 --> 01:20:58.200 because we don't have moves implemented yet. 01:20:58.200 --> 01:21:03.800 But in an ideal world, we'd find a way to also model moves as data, 01:21:03.800 --> 01:21:07.610 and therefore, you can just link moves to your data structure, 01:21:07.610 --> 01:21:09.410 to your Pokemon object like this. 01:21:09.410 --> 01:21:10.936 Yes Tony, did you have a question? 01:21:10.936 --> 01:21:13.310 AUDIENCE: Well, I just wanted to mention that the paradox 01:21:13.310 --> 01:21:15.150 games are very good about that. 01:21:15.150 --> 01:21:16.832 [INAUDIBLE] 01:21:16.832 --> 01:21:18.290 SPEAKER 1: Oh, like Crusader Kings? 01:21:18.290 --> 01:21:18.915 AUDIENCE: Yeah. 01:21:21.960 --> 01:21:25.590 SPEAKER 1: The comment was Paradox Games are very good about data driven design. 01:21:25.590 --> 01:21:28.417 I'm assuming you've dug through their files? 01:21:28.417 --> 01:21:30.250 AUDIENCE: To some extent, and also it's just 01:21:30.250 --> 01:21:33.927 if you play their games for awhile, it's everywhere, like to the extent 01:21:33.927 --> 01:21:36.260 that sometimes on the Wiki, they put the source code up. 01:21:36.260 --> 01:21:37.880 SPEAKER 1: Oh, yeah. 01:21:37.880 --> 01:21:40.340 Yeah, no, it's just good game design. 01:21:40.340 --> 01:21:41.880 Ultimately, if you want to-- 01:21:41.880 --> 01:21:44.660 and their games are large, they have a lot of content. 01:21:44.660 --> 01:21:46.901 If you want to have a lot of content in your game, 01:21:46.901 --> 01:21:49.400 you need to find a way to take the burden off the programmer 01:21:49.400 --> 01:21:51.316 and put it onto the designer, or at least make 01:21:51.316 --> 01:21:53.650 it easier for the programmer, because making source code 01:21:53.650 --> 01:21:56.899 and debugging source code all day long, especially for very complicated things 01:21:56.899 --> 01:21:57.740 is not easy. 01:21:57.740 --> 01:22:01.100 And it's ultimately not a desired thing to do, right? 01:22:01.100 --> 01:22:04.610 It's a lot easier for me to whip up a new creature in 10 lines of code 01:22:04.610 --> 01:22:10.700 here and feel good about it than hard coding a lot of these sort of things, 01:22:10.700 --> 01:22:11.780 right? 01:22:11.780 --> 01:22:17.000 So shifting as much of it to data as you possibly can should be your end goal. 01:22:17.000 --> 01:22:19.670 So that's what Pokemon defs look like. 01:22:19.670 --> 01:22:21.565 Before we get into the actual battle, we want 01:22:21.565 --> 01:22:23.420 to take a look at what a battle sprite is. 01:22:23.420 --> 01:22:27.470 So a battle sprite is what was rendering onto the screen, right? 01:22:27.470 --> 01:22:29.720 So we take a look here. 01:22:29.720 --> 01:22:33.920 That's not a battle sprite, but almost a battle sprite. 01:22:33.920 --> 01:22:35.900 That was just a texture. 01:22:35.900 --> 01:22:43.160 So if we get into a battle, slowly but surely. 01:22:43.160 --> 01:22:46.850 All right, so these are battle sprites, and they don't look much different 01:22:46.850 --> 01:22:48.980 than a regular sprite, and they're not that much 01:22:48.980 --> 01:22:50.630 different than a regular sprite. 01:22:50.630 --> 01:22:55.940 But they have some functionality that's important, mainly that functionality 01:22:55.940 --> 01:23:01.760 where one is flashing, and then one was being opaque, right? 01:23:01.760 --> 01:23:07.730 So in order to do both of those things, we need to store some sort of data 01:23:07.730 --> 01:23:09.850 within our sprite, right? 01:23:09.850 --> 01:23:10.964 Yes? 01:23:10.964 --> 01:23:14.470 AUDIENCE: Zelda for the invulnerability flashing. 01:23:14.470 --> 01:23:15.470 SPEAKER 1: Yes, exactly. 01:23:15.470 --> 01:23:18.050 For what we used in Zelda for the invulnerability flashing. 01:23:18.050 --> 01:23:24.560 For the enemy, or I should say, for whoever is getting attacked, yes. 01:23:24.560 --> 01:23:28.080 They are getting an opacity flag stored. 01:23:28.080 --> 01:23:32.730 They have an opacity flag stored in their object that we can tween, right, 01:23:32.730 --> 01:23:34.730 we can tween on and off over the course of time. 01:23:34.730 --> 01:23:38.074 That's what we did with the entity in Zelda when it took damage. 01:23:38.074 --> 01:23:40.615 And we set it to invulnerable, and while it was invulnerable, 01:23:40.615 --> 01:23:42.320 it was flashing on and off. 01:23:42.320 --> 01:23:47.930 But we can't necessarily do that with the sprite that's blinking white, 01:23:47.930 --> 01:23:52.970 because there's not really a like white flag, right? 01:23:52.970 --> 01:23:55.760 We can't make something completely white with just a flag. 01:23:55.760 --> 01:23:59.060 That's something that we actually need to use a shader for. 01:23:59.060 --> 01:24:03.200 And so a shader, and we're not going to get into too much detail about this, 01:24:03.200 --> 01:24:07.520 shaders are pretty complex, a little arcane at first. 01:24:07.520 --> 01:24:10.340 But what they are is effectively a little program that 01:24:10.340 --> 01:24:13.520 runs on your graphics card, and that looks at when you're drawing something, 01:24:13.520 --> 01:24:16.400 it looks at every pixel depending on what kind of shader you're doing. 01:24:16.400 --> 01:24:19.130 But for the sake of this demonstration, we'll look at every pixel 01:24:19.130 --> 01:24:23.510 that you're drawing to the screen, and perform some sort of function 01:24:23.510 --> 01:24:27.890 on that pixel, and produce a new value, right? 01:24:27.890 --> 01:24:31.610 And this is how you get a lot of really crazy awesome things to happen, 01:24:31.610 --> 01:24:34.350 but it can be pretty insane. 01:24:34.350 --> 01:24:39.482 Shader Toy, I think is the website that has a ton of really cool-- 01:24:39.482 --> 01:24:42.440 I'm not going to pull it up now, just 'cause I don't remember the name, 01:24:42.440 --> 01:24:44.000 I believe it's shader toy. 01:24:44.000 --> 01:24:47.041 There's a website where people post all the shaders that they've written, 01:24:47.041 --> 01:24:49.460 and you can see a lot of really crazy stuff, things 01:24:49.460 --> 01:24:53.720 that you would never imagined were possible with just code like this 01:24:53.720 --> 01:24:56.150 effectively, looking at positions of pixels 01:24:56.150 --> 01:24:58.670 and [? pictures ?] on the screen and whatnot. 01:24:58.670 --> 01:25:05.450 But effectively what this does, this is a white shader, the goal of this shader 01:25:05.450 --> 01:25:07.490 is to just turn a sprite completely white. 01:25:07.490 --> 01:25:10.610 That's all the goal of this shader is. 01:25:10.610 --> 01:25:14.390 So it gets a float called white factor, which [? you'd ?] say here. 01:25:14.390 --> 01:25:17.240 And then white factor effectively is just 01:25:17.240 --> 01:25:20.810 going to be summed onto whatever the RGB is 01:25:20.810 --> 01:25:25.350 of that pixel, whatever pixel that we're drawing when the shader is active. 01:25:25.350 --> 01:25:29.990 What that has the effect of doing is, white factor, if it's equal to 1. 01:25:29.990 --> 01:25:32.720 Here's the thing about shaders and a lot of this stuff, 01:25:32.720 --> 01:25:35.240 a lot of the data structures within shaders 01:25:35.240 --> 01:25:37.890 are based on floats that are from zero to one. 01:25:37.890 --> 01:25:43.790 So if we assign the RGB of something to a vec 3 that's 1, which is 111, 01:25:43.790 --> 01:25:46.520 that's going to be 255, 255, 255. 01:25:46.520 --> 01:25:50.660 Therefore, that pixels RGB is white, pure white, right? 01:25:50.660 --> 01:25:58.460 And so what we're doing here is on our battle sprite, self.blinking 01:25:58.460 --> 01:26:01.775 and one or zero, remember, that's the LUA [? turnerri ?] operations. 01:26:01.775 --> 01:26:07.070 So we're saying, if self.blinking is true, one else zero. 01:26:07.070 --> 01:26:15.860 So send our shader white factor based on whatever value self.blinking is. 01:26:15.860 --> 01:26:19.700 And so that will have the effect of the shader getting a one or a zero, 01:26:19.700 --> 01:26:22.400 and adding a one or a zero to the RGB of that sprite. 01:26:22.400 --> 01:26:25.670 And if blinking is set to true, the sprite's 01:26:25.670 --> 01:26:29.270 going to basically be drawn every pixel at 255, 255, 255. 01:26:29.270 --> 01:26:33.500 Otherwise, it'll get drawn with whatever that image's pixel value is 01:26:33.500 --> 01:26:35.085 at that position. 01:26:35.085 --> 01:26:37.220 Does that makes sense? 01:26:37.220 --> 01:26:37.907 OK. 01:26:37.907 --> 01:26:39.740 The syntax is a little bit weird, but that's 01:26:39.740 --> 01:26:42.020 what's happening here in this shader. 01:26:42.020 --> 01:26:44.540 And there's a link here where I found the shader, 01:26:44.540 --> 01:26:47.960 but it's a very simple, very simple shader, 01:26:47.960 --> 01:26:50.840 probably like one of the simplest shaders you could write. 01:26:50.840 --> 01:26:55.460 But it's a great example of what you can do with a shader, and pretty simply. 01:26:55.460 --> 01:26:59.210 And it's nice, because you can take like texture coordinates and do math 01:26:59.210 --> 01:27:02.060 based on that, or pixel coordinates and do math based on that. 01:27:02.060 --> 01:27:04.910 You can pass in like a sine function for example, in your file, 01:27:04.910 --> 01:27:09.379 and have that sine function perform work on like RG or B value of your sprite 01:27:09.379 --> 01:27:10.670 and do all kinds of cool stuff. 01:27:10.670 --> 01:27:14.154 It's really neat, like the possibilities are limitless with shaders. 01:27:14.154 --> 01:27:16.070 But that's how we get it to blink, because you 01:27:16.070 --> 01:27:18.410 can't do that outside of this-- 01:27:18.410 --> 01:27:21.830 I mean, there's probably some weird way could get it to work as well, 01:27:21.830 --> 01:27:28.820 but this is probably the simplest way we can get our sprites blinking white. 01:27:28.820 --> 01:27:36.890 And so self.blinking just gets a timer.every0.1 or whatever. 01:27:36.890 --> 01:27:41.010 We'll actually see that in the attack state. 01:27:41.010 --> 01:27:45.350 But that'll flick to self.blinking between true and false. 01:27:45.350 --> 01:27:49.150 It'll negate itself over and over again. 01:27:49.150 --> 01:27:51.590 All right, so that's the battle sprite. 01:27:51.590 --> 01:27:56.180 Last thing we'll look at is another extremely simple class, opponent. 01:27:56.180 --> 01:27:59.370 All the opponent is is it has a party, that's it. 01:27:59.370 --> 01:28:01.370 But in a fully fleshed game, your opponent 01:28:01.370 --> 01:28:03.680 might have a like trainer sprite. 01:28:03.680 --> 01:28:06.185 A message that it says, like a full party 01:28:06.185 --> 01:28:08.810 of Pokemon, a gold value that will give you when you defeat it, 01:28:08.810 --> 01:28:09.643 all kinds of things. 01:28:09.643 --> 01:28:12.020 But it's here just as a simple illustration. 01:28:12.020 --> 01:28:12.520 Yeah? 01:28:12.520 --> 01:28:14.925 AUDIENCE: [INAUDIBLE] put a method for on defeat 01:28:14.925 --> 01:28:17.540 if you want to maybe have it kind of collapse 01:28:17.540 --> 01:28:19.266 the room or something like that. 01:28:19.266 --> 01:28:21.260 That would be another thing that you could do. 01:28:21.260 --> 01:28:22.260 SPEAKER 1: Oh, a method? 01:28:22.260 --> 01:28:26.780 Yeah, we can associate a method with an opponent called on defeat, 01:28:26.780 --> 01:28:29.959 or whatnot that will do arbitrary things, collapse the room, 01:28:29.959 --> 01:28:30.500 or otherwise. 01:28:30.500 --> 01:28:31.910 Yes, absolutely. 01:28:31.910 --> 01:28:34.250 Or even push a new state, like to like teleport 01:28:34.250 --> 01:28:36.299 us to a new location in the world map. 01:28:36.299 --> 01:28:38.090 Maybe we like cleared the elite four and we 01:28:38.090 --> 01:28:42.590 want to get teleported to like the end credits, exactly. 01:28:42.590 --> 01:28:45.150 Limitless possibility. 01:28:45.150 --> 01:28:48.860 So let's go ahead and take a look now while we have just like 20 more minutes 01:28:48.860 --> 01:28:49.390 or so left. 01:28:49.390 --> 01:28:51.764 We'll take a look at the battle state, because the battle 01:28:51.764 --> 01:28:56.930 state and the states that they're in are probably the more complicated side 01:28:56.930 --> 01:28:59.340 of how this works. 01:28:59.340 --> 01:29:03.282 So a battle state, we have a player, we have a bottom panel, the bottom panel 01:29:03.282 --> 01:29:05.240 for when we start the state just for that part, 01:29:05.240 --> 01:29:08.720 but otherwise, we're always pushing things onto it. 01:29:08.720 --> 01:29:14.200 Whether we've started the battle or not, because when we are fading in-- 01:29:14.200 --> 01:29:16.700 sorry, yeah. 01:29:16.700 --> 01:29:28.710 Because when we initialize this state, we also push a fadeout state onto it. 01:29:28.710 --> 01:29:32.930 But we don't want to trigger the tween of the Pokemon sliding 01:29:32.930 --> 01:29:35.360 from left to right until after that state gets popped. 01:29:35.360 --> 01:29:38.600 So we have a flag here, which will get set to true on the very first update 01:29:38.600 --> 01:29:39.500 iteration. 01:29:39.500 --> 01:29:41.450 And then when that gets set to true, we'll 01:29:41.450 --> 01:29:44.180 actually tween the Pokemon going left to right, 01:29:44.180 --> 01:29:46.610 and kick off all the other sort of asynchronous processes 01:29:46.610 --> 01:29:50.250 that exist thereafter. 01:29:50.250 --> 01:29:56.330 But let's look at the battle one more time just to see what's going on. 01:29:56.330 --> 01:29:58.940 So I'm going to walk until I get into a battle. 01:29:58.940 --> 01:29:59.910 OK, we got a battle. 01:29:59.910 --> 01:30:05.200 So notice here, the fade in happens as soon as the-- 01:30:05.200 --> 01:30:08.160 the slide in happens as soon as the fade starts, right, 01:30:08.160 --> 01:30:10.402 as soon as the fade finishes, I should say. 01:30:10.402 --> 01:30:12.360 We get a message popped onto the screen, right? 01:30:12.360 --> 01:30:14.550 It says a wild X appears. 01:30:14.550 --> 01:30:16.040 Right, that's the enemy Pokemon. 01:30:16.040 --> 01:30:17.370 We hit Enter. 01:30:17.370 --> 01:30:19.140 Turn this down a little bit. 01:30:19.140 --> 01:30:21.930 We hit Enter, and then we pop another-- 01:30:21.930 --> 01:30:24.600 push another state onto the stack, another battle message, which 01:30:24.600 --> 01:30:26.100 is very similar to a dialog state. 01:30:26.100 --> 01:30:30.030 Says go our Pokemon. 01:30:30.030 --> 01:30:34.080 And then we push a menu onto the screen, right? 01:30:34.080 --> 01:30:37.190 We've got a menu that says, fight or run, a selection. 01:30:37.190 --> 01:30:39.230 It's a menu, which has a selection. 01:30:39.230 --> 01:30:42.420 And then now, this is the top of the stack, right? 01:30:42.420 --> 01:30:44.470 So it's the only thing getting input. 01:30:44.470 --> 01:30:48.096 Everything else is rendering beneath it, but nothing's getting input. 01:30:48.096 --> 01:30:49.970 So we have the option to either fight or run. 01:30:49.970 --> 01:30:51.170 Let's say we fight. 01:30:51.170 --> 01:30:55.802 We fight, we got a new state now, we're in an attack state. 01:30:55.802 --> 01:30:57.010 Several things just happened. 01:30:57.010 --> 01:31:01.880 So what happens as soon as we kick off the attack state? 01:31:01.880 --> 01:31:02.380 Yeah? 01:31:02.380 --> 01:31:04.745 AUDIENCE: You get a text box saying, x attacked y. 01:31:04.745 --> 01:31:06.870 SPEAKER 1: Yep, so the first thing we have happened 01:31:06.870 --> 01:31:10.385 is, a text box that says, x attacked y, where 01:31:10.385 --> 01:31:12.510 it could be either us or the opponent, because it's 01:31:12.510 --> 01:31:14.700 based on whoever has the higher speed. 01:31:14.700 --> 01:31:16.612 And then what happens next? 01:31:16.612 --> 01:31:17.950 AUDIENCE: [INAUDIBLE]. 01:31:17.950 --> 01:31:19.140 SPEAKER 1: Well, it does. 01:31:19.140 --> 01:31:21.600 So let's take a look at it right now and tell 01:31:21.600 --> 01:31:24.750 me what exactly happens as soon as the text box pops up. 01:31:27.750 --> 01:31:30.940 So what were the pieces that happened there? 01:31:30.940 --> 01:31:31.800 AUDIENCE: Flash. 01:31:31.800 --> 01:31:34.260 SPEAKER 1: OK, so the attacker flashes white, 01:31:34.260 --> 01:31:36.220 right, which is the shader that we looked at. 01:31:36.220 --> 01:31:38.080 That's the shader blinking on and off. 01:31:38.080 --> 01:31:41.970 There's some timer that says, every 0.1 seconds, blink on or off. 01:31:41.970 --> 01:31:43.610 And then what happens? 01:31:43.610 --> 01:31:46.660 AUDIENCE: Then the damage is dealt. [INAUDIBLE].. 01:31:46.660 --> 01:31:50.220 SPEAKER 1: Well, damage is dealt, yes, but what happens visually as soon 01:31:50.220 --> 01:31:53.669 as the white blinks? 01:31:53.669 --> 01:31:54.960 AUDIENCE: The other one blinks. 01:31:54.960 --> 01:31:56.293 SPEAKER 1: The other one blinks. 01:31:56.293 --> 01:31:59.415 What's the other one blinking? 01:31:59.415 --> 01:32:00.390 AUDIENCE: I'm not sure. 01:32:00.390 --> 01:32:02.067 SPEAKER 1: So it's opacity, right? 01:32:02.067 --> 01:32:05.150 So remember, we're doing the exact same thing we just did with that white, 01:32:05.150 --> 01:32:08.900 with the blinking, but we're tweening every 0.1 seconds 01:32:08.900 --> 01:32:11.750 the opacity of the defending Pokemon. 01:32:11.750 --> 01:32:13.677 And then we take damage. 01:32:13.677 --> 01:32:15.260 Then what happens when we take damage? 01:32:15.260 --> 01:32:17.520 AUDIENCE: The reverse basically. 01:32:17.520 --> 01:32:20.510 SPEAKER 1: Well, what gets animated when the thing takes damage? 01:32:20.510 --> 01:32:22.880 We've animated the blinking, we've animated the opacity. 01:32:22.880 --> 01:32:24.550 AUDIENCE: [INAUDIBLE]. 01:32:24.550 --> 01:32:26.240 SPEAKER 1: The health bar drops, right? 01:32:26.240 --> 01:32:28.100 So we're chaining several things together. 01:32:28.100 --> 01:32:32.760 We're chaining-- first, we're doing them every 0.1 seconds for six times, 01:32:32.760 --> 01:32:34.430 blink white. 01:32:34.430 --> 01:32:37.982 Then blink the other thing opacity, right? 01:32:37.982 --> 01:32:40.190 And we're playing sound effects at the same time too, 01:32:40.190 --> 01:32:43.190 we're playing a sound effect for the attack, sound effect for the hit. 01:32:43.190 --> 01:32:46.750 And then once that's finished, tween the health bar, right? 01:32:46.750 --> 01:32:51.050 So we've modified the health of the defending Pokemon. 01:32:51.050 --> 01:32:54.856 And then what happens after the first one, after that process is finished. 01:32:57.724 --> 01:32:59.640 AUDIENCE: Repeat for the other side? 01:32:59.640 --> 01:33:04.410 SPEAKER 1: Exactly, repeat the exact same thing, but for the other side. 01:33:04.410 --> 01:33:06.530 But what are we doing in between each of those? 01:33:06.530 --> 01:33:07.530 We have to do something. 01:33:07.530 --> 01:33:08.730 AUDIENCE: Checking if somebody dies. 01:33:08.730 --> 01:33:10.646 SPEAKER 1: Checking if somebody dies, exactly. 01:33:10.646 --> 01:33:12.840 And if somebody dies-- 01:33:12.840 --> 01:33:14.890 let's say we die, what happens? 01:33:14.890 --> 01:33:16.710 AUDIENCE: [INAUDIBLE]. 01:33:16.710 --> 01:33:19.140 SPEAKER 1: Well, we yeah, we go back to the play state. 01:33:19.140 --> 01:33:22.170 We fade out to black, and then we go back to the play state. 01:33:22.170 --> 01:33:24.536 What happens if we knock out the enemy? 01:33:24.536 --> 01:33:25.894 AUDIENCE: Go to this screen. 01:33:25.894 --> 01:33:28.060 SPEAKER 1: Exactly, and what happens on this screen? 01:33:28.060 --> 01:33:29.750 So what's the first thing that happens? 01:33:29.750 --> 01:33:32.387 Well, so recall, what happened when the Pokemon died? 01:33:32.387 --> 01:33:32.970 What happened? 01:33:32.970 --> 01:33:34.678 AUDIENCE: It fell off its platform thing. 01:33:34.678 --> 01:33:39.060 SPEAKER 1: Exactly, so that's a tween probably, right, on his y value. 01:33:39.060 --> 01:33:40.550 Then what happens? 01:33:40.550 --> 01:33:42.270 AUDIENCE: [INAUDIBLE]. 01:33:42.270 --> 01:33:46.120 SPEAKER 1: Exactly, we've pushed a battle message state onto the screen. 01:33:46.120 --> 01:33:48.756 And then what happens when we press Enter? 01:33:48.756 --> 01:33:50.301 AUDIENCE: [INAUDIBLE]. 01:33:50.301 --> 01:33:52.050 SPEAKER 1: What just happened right there? 01:33:52.050 --> 01:33:53.758 AUDIENCE: [INAUDIBLE] text box that says, 01:33:53.758 --> 01:33:55.400 you earned whatever experience points. 01:33:55.400 --> 01:33:57.645 Then you get your XP goes up. 01:33:57.645 --> 01:33:59.751 And presumably, it checks if you leveled up. 01:33:59.751 --> 01:34:00.750 SPEAKER 1: Yes, correct. 01:34:00.750 --> 01:34:03.600 AUDIENCE: [INAUDIBLE] to level up. 01:34:03.600 --> 01:34:05.610 SPEAKER 1: Exactly, so when push a dialogue 01:34:05.610 --> 01:34:09.980 to the screen that says you've earned x experience points, the XP bar tweens, 01:34:09.980 --> 01:34:10.620 right? 01:34:10.620 --> 01:34:15.740 We've gone up to however our ratio of current XP to next level XP is. 01:34:15.740 --> 01:34:19.780 We animate our text bar that way, or progress bar that way. 01:34:19.780 --> 01:34:23.820 Then we push a fade in state, right, to white. 01:34:23.820 --> 01:34:27.360 And then we have to pop everything off the stack, 01:34:27.360 --> 01:34:32.417 and then push a fade out state to the top of the stack, 01:34:32.417 --> 01:34:34.000 and then we're back to the play state. 01:34:34.000 --> 01:34:41.610 But if we do level up, we need to play the right music, play the right sound, 01:34:41.610 --> 01:34:45.370 and then part of the assignment will be actually, in that exact function, 01:34:45.370 --> 01:34:48.432 you're going to need to add some behavior that will do what? 01:34:48.432 --> 01:34:50.892 AUDIENCE: [INAUDIBLE] display the change basically, 01:34:50.892 --> 01:34:51.720 and what the new one will be. 01:34:51.720 --> 01:34:53.886 SPEAKER 1: Yes, and what are we going to need to do. 01:34:53.886 --> 01:34:55.650 What will we need to do in order to? 01:34:55.650 --> 01:34:57.790 AUDIENCE: [? Explain, ?] what was it called? 01:34:57.790 --> 01:35:00.680 The selection box, but without the selection part basically. 01:35:00.680 --> 01:35:03.900 SPEAKER 1: Yes, so once we've taken-- once we've leveled up 01:35:03.900 --> 01:35:07.680 and we're in that victory state of the battle state, right, 01:35:07.680 --> 01:35:13.560 we need to push a new state, a new menu state, which 01:35:13.560 --> 01:35:17.160 has all of those stats and the amount that they've increased. 01:35:17.160 --> 01:35:19.920 And then when we press Enter, presumably, we 01:35:19.920 --> 01:35:24.090 should pop that off, and then pop everything else back to the play state, 01:35:24.090 --> 01:35:26.310 and then do the fade in as normal. 01:35:26.310 --> 01:35:29.310 And that is the battle state in a nutshell, 01:35:29.310 --> 01:35:32.850 a lot of pieces that sort of are waiting on each other and input and stuff 01:35:32.850 --> 01:35:33.660 like that. 01:35:33.660 --> 01:35:37.985 But fairly easy to understand, just because a lot of it is very simple 01:35:37.985 --> 01:35:40.110 things that are just chained together over and over 01:35:40.110 --> 01:35:42.480 again to produce this sort of interesting behavior. 01:35:45.070 --> 01:35:47.320 So here we have sprites, recall the sprites are what 01:35:47.320 --> 01:35:49.380 we're going to need to animate those. 01:35:49.380 --> 01:35:52.860 We have health bars, which are progress bars, which 01:35:52.860 --> 01:35:55.890 are just two rectangles that are-- 01:35:55.890 --> 01:35:59.520 ones a line, a black line, and ones a fill that fills beneath the line, 01:35:59.520 --> 01:36:06.000 so that we get a sense of how much is missing, right? 01:36:06.000 --> 01:36:08.290 We get the width, the height, a color. 01:36:08.290 --> 01:36:10.470 We can give our progress bar any color we want to, 01:36:10.470 --> 01:36:13.710 which is how we get the difference between, say, a health bar and an XP 01:36:13.710 --> 01:36:14.370 bar. 01:36:14.370 --> 01:36:17.619 We just make one red and one blue, and we draw them in different spots, right, 01:36:17.619 --> 01:36:20.220 but they're both equally progress bars. 01:36:20.220 --> 01:36:21.570 And then they get a value. 01:36:21.570 --> 01:36:28.050 Their value is whatever sort of determines how much of the rectangle 01:36:28.050 --> 01:36:29.130 is scaled. 01:36:29.130 --> 01:36:33.390 And the max is how much that should be divided by in order 01:36:33.390 --> 01:36:36.420 to produce a ratio for the total width-- 01:36:36.420 --> 01:36:38.640 a scaler for the total width, which will allow us 01:36:38.640 --> 01:36:41.580 to get the sense of an amount missing. 01:36:43.875 --> 01:36:45.930 And then a player circle x, opponent circle 01:36:45.930 --> 01:36:51.180 x for the ellipses, just the graphical details for the actual Pokemon, 01:36:51.180 --> 01:36:54.690 so that we can get their stats, so that we can actually do dice rolls, or not 01:36:54.690 --> 01:36:58.230 really dice rolls in this case, but so that we can add or subtract 01:36:58.230 --> 01:36:59.790 HP based on attack and defense. 01:37:03.570 --> 01:37:06.030 And so here was the update, so trigger slide in. 01:37:06.030 --> 01:37:09.470 So what trigger slide in does, is a one second tween, 01:37:09.470 --> 01:37:10.720 which you talked about, right? 01:37:10.720 --> 01:37:14.410 The Pokemon going left to right, or left to right, right to left. 01:37:14.410 --> 01:37:18.330 There x values, just tweening in over one second. 01:37:18.330 --> 01:37:22.360 As soon as that's finished, we're going to trigger starting dialogue. 01:37:22.360 --> 01:37:26.760 So the starting dialogue is push a battle message state onto the stack. 01:37:26.760 --> 01:37:30.500 The battle message state is just like a dialogue state in that it gets a string 01:37:30.500 --> 01:37:33.300 here, so a wild something appears. 01:37:33.300 --> 01:37:36.690 It gets a callback function for once we press Enter on that. 01:37:36.690 --> 01:37:41.520 And the callback function is itself another push of a battle message state 01:37:41.520 --> 01:37:43.900 that says, go, and then our Pokemon. 01:37:43.900 --> 01:37:47.460 So notice that we're referencing the self.opponent.party.pokemon there, 01:37:47.460 --> 01:37:52.560 and self.player.party.pokemon there to get the actual name. 01:37:52.560 --> 01:37:59.790 And then once we've popped that off, then we push a battle menu state here, 01:37:59.790 --> 01:38:00.660 right? 01:38:00.660 --> 01:38:02.820 So let's take a look at the battle menu state. 01:38:02.820 --> 01:38:06.660 So this is interesting, because this is where we actually define 01:38:06.660 --> 01:38:08.880 the behavior for our menu works, right? 01:38:08.880 --> 01:38:12.080 Recall, we need something to tells us what happens when we press Fight, 01:38:12.080 --> 01:38:13.950 and what happens when we click Run. 01:38:13.950 --> 01:38:16.830 So when we click Fight, notice here items, 01:38:16.830 --> 01:38:20.810 right, self.battlemenu gets menu, and menu expects items. 01:38:20.810 --> 01:38:30.180 This items key, this table gets fed right into the selection, right? 01:38:30.180 --> 01:38:33.300 And the selection, it expects remember, a text, 01:38:33.300 --> 01:38:36.179 because it has to know what to render at that index. 01:38:36.179 --> 01:38:37.470 And then an on select function. 01:38:37.470 --> 01:38:39.261 And that on select function is the callback 01:38:39.261 --> 01:38:42.990 that gets executed when you press Enter at that particular location 01:38:42.990 --> 01:38:43.960 in the menu. 01:38:43.960 --> 01:38:48.300 In this case, fight, what that does is it pops this battle menu state where 01:38:48.300 --> 01:38:51.180 we no longer need the menu, so pop it. 01:38:51.180 --> 01:38:54.120 And then push a new take turn state. 01:38:54.120 --> 01:38:58.830 And then take turn state in this game is the Pokemon fighting each other, that's 01:38:58.830 --> 01:39:00.250 what the take turn state is. 01:39:00.250 --> 01:39:03.030 And it could have been called fight state, for example, 01:39:03.030 --> 01:39:05.080 but take turn state is a little more versatile. 01:39:05.080 --> 01:39:07.850 If we wanted to maybe make, maybe one Pokemon wants to run, 01:39:07.850 --> 01:39:10.590 the enemy wants to run and we want to fight, right? 01:39:10.590 --> 01:39:13.680 But you can't always run, so they should try to run, 01:39:13.680 --> 01:39:15.480 and then we can still fight them. 01:39:15.480 --> 01:39:18.595 Or they can use an item, or we can use an item, right? 01:39:18.595 --> 01:39:20.470 There's a lot of different things you can do. 01:39:20.470 --> 01:39:24.096 Or we want to throw a Poke ball at them, and if we fail, 01:39:24.096 --> 01:39:25.470 then they should fight us, right? 01:39:25.470 --> 01:39:27.930 Take turn is just a general purpose state 01:39:27.930 --> 01:39:31.050 that we could repurpose for whatever use we 01:39:31.050 --> 01:39:35.190 want to with any interaction between us and the opponent, 01:39:35.190 --> 01:39:38.370 whether it's fighting, running away, or using items, catching them, any 01:39:38.370 --> 01:39:39.900 of these combinations of things. 01:39:39.900 --> 01:39:43.020 But in this case, for the sake of this example, for simplicity, 01:39:43.020 --> 01:39:44.940 we've only implemented fighting. 01:39:44.940 --> 01:39:49.219 The we and the opponent fight each other during this state, which 01:39:49.219 --> 01:39:51.510 is, one attacks the other, and then we check for deaths 01:39:51.510 --> 01:39:52.740 in between both of those. 01:39:52.740 --> 01:39:57.990 And then go to victory or feinting depending on which of those holds true, 01:39:57.990 --> 01:40:00.030 if either. 01:40:00.030 --> 01:40:01.930 Running is slightly different. 01:40:01.930 --> 01:40:07.890 So if we run, I've programmed it to be 100%, it will 100% of the time work. 01:40:07.890 --> 01:40:10.600 In Pokemon, you actually have a chance to run 01:40:10.600 --> 01:40:12.860 based on what the delta is between you and your enemy. 01:40:12.860 --> 01:40:16.740 So if they're stronger than you, you actually aren't guaranteed to run away. 01:40:16.740 --> 01:40:23.400 So what we do here in my implementation is, we just pop the battle menu, 01:40:23.400 --> 01:40:24.670 so it's gone. 01:40:24.670 --> 01:40:30.880 And then we push, you fled successfully to the screen, this battle message. 01:40:30.880 --> 01:40:36.870 But there's a difference here versus the other battle messages that we've shown. 01:40:36.870 --> 01:40:40.490 I mean, it's not really different, but it's something to keep in mind. 01:40:40.490 --> 01:40:43.100 So I'm going to get into a battle. 01:40:45.912 --> 01:40:48.870 And so first of all, with that message that you just saw on the screen, 01:40:48.870 --> 01:40:50.430 I had to actually press Enter, right? 01:40:50.430 --> 01:40:53.490 I discarded it explicitly by pressing Enter. 01:40:56.490 --> 01:40:58.382 And that holds true also for these messages. 01:40:58.382 --> 01:41:00.090 It won't do anything until I press Enter. 01:41:00.090 --> 01:41:03.570 So I press Enter, and then I press Enter, and it does it's thing. 01:41:03.570 --> 01:41:06.510 But notice the difference between when I hit Run. 01:41:06.510 --> 01:41:10.230 I'm going to hit Run, I fled, and it does it on its own. 01:41:10.230 --> 01:41:14.235 It's not waiting for input, right? 01:41:14.235 --> 01:41:16.159 So how have we implemented that? 01:41:19.540 --> 01:41:20.155 Yeah? 01:41:20.155 --> 01:41:24.680 AUDIENCE: Using timer, you'd automatically 01:41:24.680 --> 01:41:29.010 do it the same way you would afterwards, instead of waiting for you input, 01:41:29.010 --> 01:41:31.330 you just wait for the timer to end. 01:41:31.330 --> 01:41:34.570 SPEAKER 1: Exactly, so we use a timer, and then when the timer is finished, 01:41:34.570 --> 01:41:40.390 we pop the battle message just like we would have popped it by pressing Enter. 01:41:40.390 --> 01:41:43.080 This false flag is what allows us to do that. 01:41:43.080 --> 01:41:46.870 We press false and false is, can we input or not? 01:41:46.870 --> 01:41:47.890 And we can't. 01:41:47.890 --> 01:41:51.230 So actually, if we didn't do any timer thing after this, 01:41:51.230 --> 01:41:54.400 and we just did that false flag, the battle message would be there forever, 01:41:54.400 --> 01:41:56.400 and we could never get rid of it, ever. 01:41:56.400 --> 01:41:58.420 It would get stuck forever. 01:41:58.420 --> 01:42:03.610 So we got to be responsible and say, OK, we're going to put a timer, 01:42:03.610 --> 01:42:08.800 we're going to call timer.after 0.5 seconds immediately after that. 01:42:08.800 --> 01:42:11.110 We're going to push a fade in state. 01:42:11.110 --> 01:42:15.190 And then we're going to do these two pop operations here as soon as that fade in 01:42:15.190 --> 01:42:16.180 happens. 01:42:16.180 --> 01:42:19.960 This first pop will pop the message, right, this message here 01:42:19.960 --> 01:42:22.910 that we didn't pop through input. 01:42:22.910 --> 01:42:26.350 So this is actually garbage collecting, in a sense, for us. 01:42:26.350 --> 01:42:31.150 It's discarding the message that we couldn't discard automatically. 01:42:31.150 --> 01:42:33.940 And then we're going to pop the battle state, right? 01:42:33.940 --> 01:42:38.860 So running will push the battle message, trigger a timer tween 01:42:38.860 --> 01:42:44.440 for our timer.after five seconds, sorry, push a fade in state. 01:42:44.440 --> 01:42:48.010 And then after the fade in states done, then pop both of those states. 01:42:48.010 --> 01:42:53.420 The message and the battle state take us back to the play state. 01:42:53.420 --> 01:42:56.360 And that's where we'll be as soon as that's all done. 01:42:56.360 --> 01:43:00.880 And that's all that's in the battle menu state. 01:43:00.880 --> 01:43:04.120 Any questions as to how the battle menu works, the difference between fight 01:43:04.120 --> 01:43:08.340 and run and sort of how those operate? 01:43:08.340 --> 01:43:09.560 OK. 01:43:09.560 --> 01:43:13.730 So let's take a look then at the take turn 01:43:13.730 --> 01:43:19.700 state, which is the last piece and the largest piece I would say. 01:43:19.700 --> 01:43:24.090 This is the most relevant to the assignment. 01:43:24.090 --> 01:43:28.250 So we maintain a reference to which Pokemon is first or second to go, 01:43:28.250 --> 01:43:31.460 which sprite is first or second to go, and which progress bar is 01:43:31.460 --> 01:43:33.400 first or second to go up here. 01:43:33.400 --> 01:43:36.020 And we do that, like I said, based on speed. 01:43:36.020 --> 01:43:40.400 So whichever Pokemon is faster, and we could have also 01:43:40.400 --> 01:43:45.330 made this a little bit shorter, just by keeping the sprites and the progress 01:43:45.330 --> 01:43:49.400 bars as members of the Pokemon object, or the class, 01:43:49.400 --> 01:43:53.150 but since they're kind of separated, like we don't necessarily 01:43:53.150 --> 01:43:56.870 want a Pokemon to have a reference to it's progress bar at all times, 01:43:56.870 --> 01:43:58.025 or I mean, you could. 01:43:58.025 --> 01:43:59.900 There's nothing preventing you from doing it. 01:43:59.900 --> 01:44:04.020 It would only serve the purpose of shortening this code here. 01:44:04.020 --> 01:44:10.640 But we need to keep a reference to this so that we can call attack here, 01:44:10.640 --> 01:44:16.400 which is this large bit of code twice, without needing 01:44:16.400 --> 01:44:18.560 to duplicate all of that code twice. 01:44:18.560 --> 01:44:21.076 Does that makes sense? 01:44:21.076 --> 01:44:22.450 So Tony, did you have a question? 01:44:22.450 --> 01:44:24.800 AUDIENCE: Well, I was just thinking, you could probably 01:44:24.800 --> 01:44:26.716 put that into a helper function where you just 01:44:26.716 --> 01:44:29.260 change the order you pass it in. 01:44:29.260 --> 01:44:30.090 SPEAKER 1: Sorry? 01:44:30.090 --> 01:44:30.640 Say it again. 01:44:30.640 --> 01:44:33.870 AUDIENCE: I just kind of feel like, I guess you could take the code, 01:44:33.870 --> 01:44:36.373 and you could avoid duplicating that I guess. 01:44:36.373 --> 01:44:40.000 'Cause it's just reversed, so what you could do is you could-- 01:44:40.000 --> 01:44:44.620 if you passed into a helper function, which you would just, 01:44:44.620 --> 01:44:48.350 instead of passing it first-- 01:44:48.350 --> 01:44:50.730 instead of passing it, opponent Pokemon, player Pokemon, 01:44:50.730 --> 01:44:53.504 you would pass it, player Pokemon, opponent Pokemon. 01:44:53.504 --> 01:44:55.132 And that would probably work I think. 01:44:55.132 --> 01:44:57.590 SPEAKER 1: Well, you also have to take into consideration-- 01:44:57.590 --> 01:45:04.060 so the comment was, you could pass in the player Pokemon and the opponent 01:45:04.060 --> 01:45:08.355 Pokemon into a function, and then you reverse them in that function, 01:45:08.355 --> 01:45:10.480 I'm assuming, have reverence them and reverse them. 01:45:10.480 --> 01:45:13.780 But the sprites are decoupled from the Pokemon, 01:45:13.780 --> 01:45:17.170 and the progress bars are also decoupled from the Pokemon. 01:45:17.170 --> 01:45:27.790 So we could shorten this by making these four things here fields 01:45:27.790 --> 01:45:31.030 of the Pokemon objects, but they're not strictly 01:45:31.030 --> 01:45:34.180 pertinent to the operation of the Pokemon object. 01:45:34.180 --> 01:45:39.740 And it sort of kind of makes the Pokemon objects a little 01:45:39.740 --> 01:45:43.586 too, not basically abstract or lightweight enough, 01:45:43.586 --> 01:45:45.460 and it only serves the purpose of this point, 01:45:45.460 --> 01:45:47.660 of just shortening this bit of code. 01:45:47.660 --> 01:45:53.020 There's probably a more elegant way to do it, but it's hard to say. 01:45:53.020 --> 01:45:56.550 If this code were to get larger, maybe. 01:45:56.550 --> 01:45:58.690 But the gist of this is basically to have 01:45:58.690 --> 01:46:04.380 a pointer to whatever Pokemon, progress bars, and sprites should operate first 01:46:04.380 --> 01:46:06.790 in the attack versus what should operate second. 01:46:06.790 --> 01:46:10.730 And then the two will trade blows in order based on who's first and who 01:46:10.730 --> 01:46:12.530 second. 01:46:12.530 --> 01:46:14.560 So when we enter the take turn state, we're 01:46:14.560 --> 01:46:18.730 going to trigger that attack, here this function attack, which we'll take in 01:46:18.730 --> 01:46:22.210 first, second, first, second, first, second for the Pokemon 01:46:22.210 --> 01:46:24.760 sprite and progress bars. 01:46:24.760 --> 01:46:27.850 And then anonymous function, which get's executed as 01:46:27.850 --> 01:46:31.810 soon as the attack is finished, right? 01:46:31.810 --> 01:46:35.800 So this is a code that will pop a message that gets pushed in attack, 01:46:35.800 --> 01:46:39.040 and then this is where we actually check deaths, right? 01:46:39.040 --> 01:46:42.380 And it will determine whether we go to victory or faint screen or not. 01:46:42.380 --> 01:46:44.920 If not, and we return if so. 01:46:44.920 --> 01:46:47.186 If not, we're going to do another attack, but see, 01:46:47.186 --> 01:46:48.310 everything is reversed now. 01:46:48.310 --> 01:46:53.281 Now it's second, first, second, first, second, first. 01:46:53.281 --> 01:46:55.030 So we have the same function, self attack, 01:46:55.030 --> 01:46:57.130 which just takes in the attacker. 01:46:57.130 --> 01:47:00.310 And it's effectively, attacker, defender, attacker, defender, attacker, 01:47:00.310 --> 01:47:05.860 defender for the Pokemon sprites and progress bars. 01:47:05.860 --> 01:47:09.350 And so the attack function here first pushes a-- 01:47:09.350 --> 01:47:10.120 well, OK. 01:47:10.120 --> 01:47:11.329 What does the attack-- 01:47:11.329 --> 01:47:12.620 let's go over it one more time. 01:47:12.620 --> 01:47:18.279 What do we think the attack function does in order. 01:47:18.279 --> 01:47:20.070 We covered them just a moment ago, but what 01:47:20.070 --> 01:47:24.070 was the order that happens when something attacks another thing? 01:47:24.070 --> 01:47:25.188 Yeah? 01:47:25.188 --> 01:47:27.235 AUDIENCE: The attacker blinks white. 01:47:27.235 --> 01:47:28.645 SPEAKER 1: Attacker blinks white. 01:47:28.645 --> 01:47:33.900 AUDIENCE: Then the defender blinks opacity. 01:47:33.900 --> 01:47:36.626 SPEAKER 1: The defender toggles it's opacity. 01:47:36.626 --> 01:47:38.244 AUDIENCE: And the health bar shrinks. 01:47:38.244 --> 01:47:39.494 SPEAKER 1: Health bar shrinks. 01:47:42.850 --> 01:47:45.570 Exactly, and then that's basically it for attack, right? 01:47:45.570 --> 01:47:49.690 Blink, play a sound, blink, play a sound, shrink the bar, 01:47:49.690 --> 01:47:52.810 and also we're doing damage in that function as well. 01:47:52.810 --> 01:47:55.450 We actually have to change the status of the Pokemon. 01:47:59.590 --> 01:48:02.150 So this is effectively where it starts, right? 01:48:02.150 --> 01:48:05.557 We place a battle message state onto the stack that says, 01:48:05.557 --> 01:48:07.390 the attacker name attacks the defender name. 01:48:10.510 --> 01:48:15.490 Notice that it gets false just like the run message 01:48:15.490 --> 01:48:17.830 did, because we're not accepting input here. 01:48:17.830 --> 01:48:25.870 But it's up to us actually, it done up here at line 42 of the enter state. 01:48:25.870 --> 01:48:32.260 But we're going to after 0.5 seconds, play the attack animation. 01:48:32.260 --> 01:48:36.400 So power up sound every 0.1 second. 01:48:36.400 --> 01:48:39.340 We're going to member the blinking flag on the sprite, 01:48:39.340 --> 01:48:42.980 we're going to toggle it by setting it not to itself. 01:48:42.980 --> 01:48:46.290 So if something is not itself, if it's a truthy value, it becomes falsy, 01:48:46.290 --> 01:48:48.340 if it's falsy, it becomes truthy. 01:48:48.340 --> 01:48:51.100 So basically, toggling between true and false. 01:48:51.100 --> 01:48:53.530 Limit of six, right, because remember, every will 01:48:53.530 --> 01:48:56.200 do something every amount of time indefinitely, 01:48:56.200 --> 01:49:00.700 unless you pass in a limit of some value, in this case, a limit of six. 01:49:00.700 --> 01:49:04.870 So we're saying, only execute this code six times, only blink six times, right, 01:49:04.870 --> 01:49:07.690 only toggle six times, blink three times, right, 01:49:07.690 --> 01:49:09.800 because it has to go on and off. 01:49:09.800 --> 01:49:12.550 And then as soon as those six iterations are completed, 01:49:12.550 --> 01:49:16.360 we call the finished function on that timer object, 01:49:16.360 --> 01:49:18.156 which takes an honest function. 01:49:18.156 --> 01:49:22.542 As soon as that happens, we do the opacity bit, right? 01:49:22.542 --> 01:49:25.250 We blinked the attackers, so now we've got to blink the defender. 01:49:25.250 --> 01:49:27.760 So we play the hit sound. 01:49:27.760 --> 01:49:32.110 We do the exact same thing that we just did for the blinking, only now, 01:49:32.110 --> 01:49:37.480 every 0.1 second, we are setting its opacity to either 64 or 255, 01:49:37.480 --> 01:49:40.900 depending on what the value of its opacity is, right? 01:49:40.900 --> 01:49:43.240 So we are toggling between 64 and 255. 01:49:43.240 --> 01:49:47.050 Limit of six, take a function, calculate damage, 01:49:47.050 --> 01:49:53.210 which we've just very simply done it, attack minus defense, right, up to 1 01:49:53.210 --> 01:49:53.710 though. 01:49:53.710 --> 01:49:55.918 So if the defense is actually higher than the attack, 01:49:55.918 --> 01:49:58.000 which will still do at least one damage. 01:49:58.000 --> 01:50:03.370 And then over 0.5 seconds, we take the defenders bar, 01:50:03.370 --> 01:50:08.650 and we tween the value equal to their current HP minus damage, right? 01:50:08.650 --> 01:50:15.580 And then that will set in the bar, in the progress bar, it'll set its value. 01:50:15.580 --> 01:50:21.460 And even though the progress bar is behind state wise, 01:50:21.460 --> 01:50:24.760 right, it's on the bottom of the stack, because it's on the battle state. 01:50:24.760 --> 01:50:27.000 And we're in currently the take turn state, 01:50:27.000 --> 01:50:30.580 but because we're still manipulating the values of that state, 01:50:30.580 --> 01:50:33.640 and we're rendering every state, we're actually still manipulating 01:50:33.640 --> 01:50:37.040 that state regardless of the fact that it's not on the top of the stack. 01:50:37.040 --> 01:50:43.510 So that allows us to shrink that Pokemon's progress bar regardless of it 01:50:43.510 --> 01:50:45.360 being on the top of the stock or not. 01:50:45.360 --> 01:50:47.800 Then once that's finished, once the tween is finished, 01:50:47.800 --> 01:50:49.591 actually set the current HP to that amount, 01:50:49.591 --> 01:50:52.450 because we're only tweening the progress bar's value, which is 01:50:52.450 --> 01:50:55.277 independent from the Pokemon's value. 01:50:55.277 --> 01:50:56.860 And then that's the end of the attack. 01:50:56.860 --> 01:50:59.300 The attack is completely finished at that point. 01:50:59.300 --> 01:51:02.940 So any questions as to how the attack works? 01:51:02.940 --> 01:51:06.610 Just a chain of tweens basically. 01:51:06.610 --> 01:51:10.110 So we do an attack, then check deaths is the next function. 01:51:10.110 --> 01:51:14.400 And we're almost finished, I'm going to kind of go quickly here, it's at 7:30. 01:51:14.400 --> 01:51:18.540 Check deaths is the player Pokemon current HP less and equal to 0, 01:51:18.540 --> 01:51:21.540 or is the opponent Pokemon current HP less and equal to zero. 01:51:21.540 --> 01:51:24.750 If the former's true, we need to faint, and if the latter is true, 01:51:24.750 --> 01:51:25.860 we need to go to victory. 01:51:25.860 --> 01:51:32.880 So faint is effectively a battle state, right, when it says, you fainted. 01:51:32.880 --> 01:51:33.817 And then what? 01:51:33.817 --> 01:51:36.799 Remember what happens when we faint? 01:51:36.799 --> 01:51:41.780 AUDIENCE: [INAUDIBLE] text box, and then it leaves. 01:51:41.780 --> 01:51:44.051 SPEAKER 1: It leaves, do you remember how 01:51:44.051 --> 01:51:46.550 it leaves as it differs from like running away, for example? 01:51:46.550 --> 01:51:48.790 AUDIENCE: [INAUDIBLE]. 01:51:48.790 --> 01:51:50.672 SPEAKER 1: Well, beyond that, aesthetically, 01:51:50.672 --> 01:51:52.130 do you remember how it's different? 01:51:52.130 --> 01:51:55.119 AUDIENCE: [INAUDIBLE] differently to black, I think. 01:51:55.119 --> 01:51:55.910 SPEAKER 1: It does. 01:51:55.910 --> 01:51:57.081 It fades to black instead. 01:51:57.081 --> 01:51:59.330 So that's how we can differentiate when we're fainting 01:51:59.330 --> 01:52:00.891 versus when we're running away. 01:52:00.891 --> 01:52:02.390 And so that's what we're doing here. 01:52:02.390 --> 01:52:06.580 Notice that the fade in state RGB is zero, all of those. 01:52:06.580 --> 01:52:12.890 So it's going to fade in to 000255, as opposed to 255, 255, 255, 255. 01:52:12.890 --> 01:52:17.000 So it's going to be a black fade in versus a white fade in. 01:52:17.000 --> 01:52:18.217 And then once we've-- 01:52:18.217 --> 01:52:20.300 this it just sort of a thing that I implemented so 01:52:20.300 --> 01:52:21.883 that we can keep playing indefinitely. 01:52:21.883 --> 01:52:25.790 But once that's finished, restore the player Pokemon to full health, 01:52:25.790 --> 01:52:27.740 resume all the field music stuff. 01:52:27.740 --> 01:52:31.851 And then once we've pushed a fade out state, 000, 01:52:31.851 --> 01:52:34.910 and then we've gone back to the field, let's push. 01:52:34.910 --> 01:52:38.360 Notice that here it takes a function, right, after the fade out state's done. 01:52:38.360 --> 01:52:42.620 Once the fade out is finished-- so as soon as we're back to the play state, 01:52:42.620 --> 01:52:44.630 push a dialogue state that says, your Pokemon 01:52:44.630 --> 01:52:47.300 has been fully restored, try again. 01:52:47.300 --> 01:52:49.770 Which will take the context, and we'll [INAUDIBLE] 01:52:49.770 --> 01:52:51.374 to press Enter to get past it. 01:52:51.374 --> 01:52:52.040 That's fainting. 01:52:54.620 --> 01:52:58.070 Victory is a little bit more robust. 01:52:58.070 --> 01:53:02.748 So victory is-- do you remember what happen when we get a victory? 01:53:06.644 --> 01:53:11.027 AUDIENCE: Well, it has to check leveling up as well. 01:53:11.027 --> 01:53:17.500 It says, you've defeated your opponent, then your XP bar increases. 01:53:17.500 --> 01:53:20.212 Then if you've leveled up, it tells you that you leveled up, 01:53:20.212 --> 01:53:21.480 and then it leaves. 01:53:21.480 --> 01:53:27.850 SPEAKER 1: So it tells you you defeated your opponent, XP bar increases, 01:53:27.850 --> 01:53:30.700 checks for a level up, and then leaves. 01:53:30.700 --> 01:53:35.810 After displaying the level up message or not, it leaves. 01:53:35.810 --> 01:53:39.460 It pops everything back to the play state, exactly. 01:53:39.460 --> 01:53:42.070 So remember, the very first thing that happens 01:53:42.070 --> 01:53:46.780 though, the opponent sprite gets tweened over the course of 0.2 seconds, 01:53:46.780 --> 01:53:49.040 it's y value to virtual height, which means, 01:53:49.040 --> 01:53:50.998 all the way to the bottom of the screen, right? 01:53:50.998 --> 01:53:56.050 The typical defeated your opponent from Pokemon sort of animation. 01:53:56.050 --> 01:53:58.420 Once that's finished, play victory music, 01:53:58.420 --> 01:54:01.190 push a battle message state that says, victory, right? 01:54:01.190 --> 01:54:04.860 Once that's popped of the stack, calculate the XP, 01:54:04.860 --> 01:54:09.330 which is, I just chose arbitrarily sum all the IVs of that Pokemon times 01:54:09.330 --> 01:54:12.500 it's level, and that's the XP you got. 01:54:12.500 --> 01:54:18.340 Push a state that says, you earned x XP, right? 01:54:18.340 --> 01:54:21.985 It's false, so that means it doesn't take input. 01:54:21.985 --> 01:54:24.610 So that means it's up to us in order to pop that off the stack. 01:54:24.610 --> 01:54:29.830 So after 1.5 seconds, we play a sound, and then we tween that XP bar going up, 01:54:29.830 --> 01:54:31.120 right? 01:54:31.120 --> 01:54:34.470 So that's what's going on here, self.battleState.playerxpbar, 01:54:34.470 --> 01:54:40.210 we're tweening of the math.men, of the XP plus XP, 01:54:40.210 --> 01:54:45.850 or XP to level, because if we don't, it could go past the edge of the XP bar, 01:54:45.850 --> 01:54:49.240 because we could go over our XP to level, right? 01:54:49.240 --> 01:54:52.330 Let's say we have 10 XP till we gain a level, we could gain 20 XP. 01:54:52.330 --> 01:54:53.860 We'd be 10 XP overboard. 01:54:53.860 --> 01:54:58.450 So we don't want to tween our XP bar past the edge of the XP bar, 01:54:58.450 --> 01:55:00.110 it would be a graphical glitch. 01:55:00.110 --> 01:55:05.410 So a math.men our XP plus XP, and our XP to level, 01:55:05.410 --> 01:55:08.740 which will take the lesser of the two values. 01:55:08.740 --> 01:55:12.250 Once that's done, it's tweened, we're going to pop the message off, 01:55:12.250 --> 01:55:15.760 and then we're going to actually add the XP, level up. 01:55:15.760 --> 01:55:19.390 So this is where we level up if the XP is greater than XP to level. 01:55:19.390 --> 01:55:26.260 Play a sound, set the XP to the current XP minus our 2 level XP, 01:55:26.260 --> 01:55:30.130 which will mean that we'll have some carry over, right? 01:55:30.130 --> 01:55:32.060 And then actually call the level up function. 01:55:32.060 --> 01:55:35.230 Now here is where-- 01:55:35.230 --> 01:55:37.990 oh, and also after that, congratulations, you've leveled up. 01:55:37.990 --> 01:55:40.570 Fadeout white, which is just a white fade out here. 01:55:40.570 --> 01:55:43.360 I used it twice, so I made a function for it. 01:55:43.360 --> 01:55:46.300 Just pushes a fade in state. 01:55:46.300 --> 01:55:50.440 Stop the victory music, play the field music, pop, push a fade out state. 01:55:50.440 --> 01:55:56.110 So either way, when we've got a victory, we're going to push a fade out white, 01:55:56.110 --> 01:55:58.360 or we're going to call fade out white, correct? 01:55:58.360 --> 01:56:02.920 So push a battle message state, and then as soon 01:56:02.920 --> 01:56:06.370 as we press Enter, because we leveled up, fade out to white. 01:56:06.370 --> 01:56:08.690 And if we didn't level up, but we still got to victory, 01:56:08.690 --> 01:56:10.360 we still need to fade out white. 01:56:10.360 --> 01:56:13.280 And so this is where your assignment is, assignment 7. 01:56:13.280 --> 01:56:17.517 Assignments 7 is, notice that we have self.playerPokemon level up. 01:56:17.517 --> 01:56:19.600 The key thing that we are going to need to do here 01:56:19.600 --> 01:56:23.020 is add a menu that shows us how we leveled up. 01:56:23.020 --> 01:56:27.160 And if you recall, playerPokemon level up returns all the stats 01:56:27.160 --> 01:56:29.260 that you've increased this level. 01:56:29.260 --> 01:56:34.980 So you can show a menu that just says, your HP plus that amount, right? 01:56:34.980 --> 01:56:36.480 You're going to get all four values. 01:56:36.480 --> 01:56:38.650 It's going to explode to all four of those values. 01:56:38.650 --> 01:56:42.460 And then you're going to create a new battle-- 01:56:42.460 --> 01:56:46.330 or not new battle menu, but a new menu of whatever you want, 01:56:46.330 --> 01:56:51.760 but probably on the right side of some vertical height for items. 01:56:51.760 --> 01:56:53.890 The only difference here, the only key thing 01:56:53.890 --> 01:56:55.930 that you're going to take into consideration 01:56:55.930 --> 01:56:59.290 is, and I'll go back to the slides, because we're actually 01:56:59.290 --> 01:57:01.660 done at this point going over the code. 01:57:01.660 --> 01:57:07.180 But the selection items, you won't be able to actually select anything, 01:57:07.180 --> 01:57:09.220 it's just going to be purely visual. 01:57:09.220 --> 01:57:12.520 So you're going to need to edit selection to have the option 01:57:12.520 --> 01:57:13.504 to not have a cursor. 01:57:13.504 --> 01:57:15.670 And this is detailed in the spec, which was actually 01:57:15.670 --> 01:57:17.330 released before lecture today. 01:57:17.330 --> 01:57:18.910 So you can take a look at that. 01:57:18.910 --> 01:57:21.760 But you'll need to make a change to selection. 01:57:21.760 --> 01:57:23.070 But all the pieces are there. 01:57:23.070 --> 01:57:24.945 It should be a fairly easy assignment as long 01:57:24.945 --> 01:57:28.390 as you understand how the states work, how the menu works, 01:57:28.390 --> 01:57:33.040 and how to create a menu based on those values, 01:57:33.040 --> 01:57:35.320 and how to actually get the values from level up. 01:57:35.320 --> 01:57:38.830 So some missing features that we didn't talk about, which we didn't implement 01:57:38.830 --> 01:57:41.380 are, for example, the detailed level of screen, 01:57:41.380 --> 01:57:45.040 which is your assignment, monster catching, right? 01:57:45.040 --> 01:57:49.150 We only have a party of one Pokemon throughout this whole entire thing, 01:57:49.150 --> 01:57:53.500 but one of the arguably main appeals of the game is to be able to catch more. 01:57:53.500 --> 01:57:57.790 So that would be something to add, to prioritize probably adding to the game. 01:57:57.790 --> 01:58:00.880 A field menu so can actually look at all the Pokemon you've caught. 01:58:00.880 --> 01:58:04.390 That would be nice, so you can actually see how much HP they have. 01:58:04.390 --> 01:58:07.330 In item inventory, because the game, the regular games have items. 01:58:07.330 --> 01:58:10.420 You can use potions, you can find gold nuggets 01:58:10.420 --> 01:58:12.370 that you sell for a ton of money. 01:58:12.370 --> 01:58:15.702 Different abilities, currently we only have basically one fight operation, 01:58:15.702 --> 01:58:16.660 which is like a tackle. 01:58:16.660 --> 01:58:19.240 And the game itself, the regular game has 01:58:19.240 --> 01:58:22.270 like over 100 different moves that have elemental attributes, 01:58:22.270 --> 01:58:25.600 and do different things, and cause status effects, 01:58:25.600 --> 01:58:27.250 buff you or your opponent. 01:58:27.250 --> 01:58:30.790 So adding those is appealing, and maybe being 01:58:30.790 --> 01:58:33.814 able to represent them as data is nice to. 01:58:33.814 --> 01:58:36.730 Trainers that you can encounter in the game that have their own preset 01:58:36.730 --> 01:58:38.954 or randomized Pokemon for to fight. 01:58:38.954 --> 01:58:41.620 Monster evolution, because that's like one of the funnest things 01:58:41.620 --> 01:58:43.661 is taking a really weak Pokemon, and like raising 01:58:43.661 --> 01:58:46.850 it to become really strong, and evolving it at a certain level. 01:58:46.850 --> 01:58:52.870 Towns, routes, other levels beyond just our basic square area. 01:58:52.870 --> 01:58:55.600 Monster breeding, which is introduced in the second series, 01:58:55.600 --> 01:58:58.050 so that you can take two Pokemon and have a chance 01:58:58.050 --> 01:59:02.074 to get an egg with really good stats or a really rare Pokemon from it. 01:59:02.074 --> 01:59:04.990 And then like a day night cycle maybe where different Pokemon come out 01:59:04.990 --> 01:59:06.560 at different times of the day. 01:59:06.560 --> 01:59:11.680 So you are incentivize to play at different times 01:59:11.680 --> 01:59:14.590 of the day for that purpose. 01:59:14.590 --> 01:59:16.450 But that was it for Pokemon. 01:59:16.450 --> 01:59:19.030 Next week we'll actually be diving into Unity. 01:59:19.030 --> 01:59:23.200 So we're actually done with LOVE 2D, which is a lot of fun, 01:59:23.200 --> 01:59:26.090 but now we'll be going into how to make 3D games. 01:59:26.090 --> 01:59:28.840 So this is a screenshot from the game we'll be making next week, 01:59:28.840 --> 01:59:32.470 which is a 3D sort of side scrolling Flappy Bird esque helicopter 01:59:32.470 --> 01:59:38.590 game based on a famous web game called Helicopter Game. 01:59:38.590 --> 01:59:44.250 And it was sort of one of the early ancestors to Flappy Bird. 01:59:44.250 --> 01:59:46.990 On the Wikipedia page, it actually says that too. 01:59:46.990 --> 01:59:51.452 I remember playing, it was back in like 2007, or 2006, or something like that. 01:59:51.452 --> 01:59:54.160 But your goal in this game-- this is a modified version of that-- 01:59:54.160 --> 01:59:58.130 your goal is your-- everything is 3D, but it's a side scrolling perspective. 01:59:58.130 --> 02:00:01.570 So this is called 2.5D for that reason. 02:00:01.570 --> 02:00:04.360 You're controlling a helicopter, you're the purple helicopter. 02:00:04.360 --> 02:00:07.670 And your goal is to in an infinitely scrolling world. 02:00:07.670 --> 02:00:11.760 So we'll revisit infinite scrolling, but in 3D, avoid skyscrapers. 02:00:11.760 --> 02:00:15.880 So you can see there is a green skyscraper, crudely modeled. 02:00:15.880 --> 02:00:18.880 Collect coins, so you can see there's a coin there, it's a 3D coin, 02:00:18.880 --> 02:00:20.440 it will always be spinning. 02:00:20.440 --> 02:00:22.570 Your coins are up at the top right. 02:00:22.570 --> 02:00:24.880 You'll see a background that's infinitely scrolling. 02:00:24.880 --> 02:00:26.740 And then you'll have jets that will randomly 02:00:26.740 --> 02:00:31.090 fly above you to sort of give you another sort of layer or dimension 02:00:31.090 --> 02:00:32.950 of obstacles to watch out for. 02:00:32.950 --> 02:00:36.910 And this will teach us a lot of the basics of how unity works, 02:00:36.910 --> 02:00:41.110 so we can start getting into even more interesting things like a first person 02:00:41.110 --> 02:00:43.090 like sort of core exploration game. 02:00:43.090 --> 02:00:45.820 And then lastly, when we end the semester with Portal, 02:00:45.820 --> 02:00:48.130 we'll look at a couple of fancy things there. 02:00:48.130 --> 02:00:49.380 But that was it for Pokemon. 02:00:49.380 --> 02:00:51.255 Thanks for coming, and I'll see you guys next 02:00:51.255 --> 02:00:52.430 time.