# CS50 2D - Lecture 7 - Pokémon

## Метаданные

- **Канал:** CS50
- **YouTube:** https://www.youtube.com/watch?v=pdBhw2QirRI
- **Дата:** 28.04.2026
- **Длительность:** 1:30:02
- **Просмотры:** 6,444
- **Источник:** https://ekstraktznaniy.ru/video/49632

## Описание

In CS50 2D’s final lecture, explore the core mechanics and programming concepts behind Pokémon-inspired RPGs, including state stacks, GUI design, and turn-based battle systems. 

To take the course for a certificate, register at cs50.edx.org/2d.  

***

This is CS50, Harvard University's introduction to the intellectual enterprises of computer science and the art of programming.

***

HOW TO SUBSCRIBE

http://www.youtube.com/subscription_center?add_user=cs50tv

HOW TO TAKE CS50

edX: https://cs50.edx.org/
Harvard Extension School: https://cs50.harvard.edu/extension
Harvard Summer School: https://cs50.harvard.edu/summer
OpenCourseWare: https://cs50.harvard.edu/x

HOW TO JOIN CS50 COMMUNITIES

Bluesky: https://bsky.app/profile/cs50.harvard.edu
Discord: https://discord.gg/cs50
Ed: https://cs50.edx.org/ed
Facebook Group: https://www.facebook.com/groups/cs50/
Faceboook Page: https://www.facebook.com/cs50/
GitHub: https://github.com/cs50
Gitter: https://gitter.im/cs50/x
Instagram: https://in

## Транскрипт

### Segment 1 (00:00 - 05:00) []

Hello world. This is CS52D lecture 7, the final lecture of the course. And today we'll be looking at a game that's a big part of my childhood and sort of a culmination of some of the ideas and some new ideas with which we've been talking about in this course. And that is Pokemon stylized with this slide here by a game that I grew up playing in particular Pokemon Crystal for the Game Boy. And here's a screenshot of what Pokemon looked like. The very first Pokemon game that I ever played, which was Pokemon Red. And I remember the very first time sort of being able to play this on a handheld device back in the day, a Game Boy, and thinking just how incredible it was that you could go around while you're out, you know, on the playground in school or whatnot. And then you are playing as this character in this world going around and catching these creatures called Pokémon shown here. This is a weeping bell versus a geodude. There were 151 original Pokémon and that was a big deal. Again, a huge franchise just like Mario and Zelda. It spawned countless different various products including in anime, including trading cards, all sorts of things. Huge part of my childhood, huge part of I think many folks' childhood. They evolved over the years, much like the Pokémon themselves do. This is Gold and Silver and Crystal, which was the one that I spent probably the most time playing after Red. And then they got to the Game Boy Advance where you had titles like Fire Red, Leaf Green. And then there were games for the DS where they incorporated the dual screen where they this is a Pokemon black excerpt here where they have all the moves here that your Pokemon can use in battle were now shown all at once on the bottom and then you still have the same sort of combat screen up top. And then here's another example of Pokemon X and Y for sorry this is black and then X and Y is this version here which is a their first fora into 3D and now they've gone and spawned a bunch of new games that I can't even keep up with on the Switch and so forth. But the same core formula is the same where you have a Pokemon here shown even though it's in 3D. You still have the same dialogue. You still have the same sort of view of the front and back. And though they now have more dynamic camera movements and the like, the underlying turnbased battle structure has largely stayed the same. And we'll be taking a look at that today in addition to various other aspects that make the game work. So some of the topics we'll be looking at in addition to turn-based systems which I've just alluded to, we've been looking at state machines thus far. Current state machines are a great way to model behavior as it changes throughout time. Be that for your game or entities in the game. But today we'll be looking at a way to model states that layer on top of each other. If folks are familiar with Pokémon, you typically are out in the world as a character moving around much like in Legend of Zelda or games like Final Fantasy of old sort of these RPG turn-based RPG type tropes like Dragon Quest and so forth. But if you are to walk around in, let's say, some area of grass where there are wild Pokémon that you can encounter, you will transition to a new state, this battle sort of state where you're fighting in the screenshots that we've seen thus far, except once the battle is over, you go back to exactly where you were in the world previously. And so there's this preservation of your position. And you can certainly sort of keep that as a variable and pass it back and forth between states and whatnot. But there are many effects and many sorts of ways of modeling these transitions. Think about also pause menus and the like where you might want to render something that is a different state but on top of a state that is kind of paused in the background. And so the way that we do that is we actually start to think about our states not as a machine with a discrete individual state but rather as a stack that we can pop and push st uh states on and off of. We'll spend a b bunch of time looking at guey elements as well, graphical user interfaces today, which games like this, as you can see by the screenshots, are very sort of menu and UI driven. And so we have to take a look at how to actually compose those. And then RPG mechanics in general as we look at how the battle system, XP, things like that work to allow us to sort of build up our team of Pokemon, fight, get stronger, so on and so forth. And this is what our goal ultimately is going to look like. Here's a differential differentiable screenshot between the field state as we'll typically call it in an RPG or in Pokemon. Pokemon being a an example of an RPG, albeit quite a different example than what was common at the time. Um, and specifically a Japanese RPG or a JRPG. And so it typically will have a field state and then some kind of a battle state and then maybe other additional states with larger menus and the like which we won't necessarily have in this implementation to start with but which will be a part of the problem set. But this is a sort of core differential differentiator between the two main states that we'll be talking about. So I think it's important that we as usual take an actual look at the demo of the game and see what it looks like in practice. If we could get a volunteer to maybe come up the stage. Yeah, come on up.

### Segment 2 (05:00 - 10:00) [5:00]

And it's David. — David. Yes. Good to see you again. Thanks for calling on me. So, we're going to go ahead and run it here. — And we'll notice that we've got a little title screen here. They're Pokémon sort of like we're using this sort of open- source set of Pokémon. And so they'll they sort of per the normal game will do this in the beginning where they're transitioning back and forth. But we can press enter and that will take us to the actual field state. Notice the transition that occurred there. And so here we have the first example of an actual dialogue window which we haven't looked at yet. Now what's interesting and on the surface it might not seem this way but this is actually a state but notice we also have this other state underneath it. — But you can go ahead and press enter to dismiss the dialogue. You can now walk around. You'll notice that there's like kind of flat sort of low grass but also this like darker deeper grass. So if you spend a couple moments maybe walking through there just for a little bit and maybe if uh chance permits you might stumble randomly across an encounter. Although they seem to be a little bit scared of you right now, but there we go. So, we've transitioned now into a new state. Things are very different now. You've got a Pokémon that you've been given for free. It looks like you're fighting the same one by happen stance. But if you press enter, you'll see that you're sort of getting a set of dialogue prompts. So, press enter again. And now you've got two options. Now, if you were to use the arrow keys, you could choose. Do you want to fight or run? And so, fighting does indeed inflict some damage. You got some effects there, some graphical effects. You'll notice your sort of stats are higher than the enemy. So you did more damage. So if you can maybe do that a couple more times, you'll notice the sort of turnbased sort of like your turn then their turn. Okay. So very well. You defeated the enemy. You get some victory music. And then if you were to press enter, you might notice a little bit of XP there. — Nice. — Part of the game too is you level up over time. You fight more and more creatures. Now, if you were to try and maybe get into another example and then instead of fighting, you notice your XP and health sort of preserve from last time. But now, why don't you go ahead and run instead of fighting once we get past these first couple of prompts here. — You notice that you flee and then you come again. You don't have to fight. You don't you have that choice not to. In theory, if you were to get knocked out from, you know, fighting a Pokemon, you might go to a different state. You want to try that as well. Okay, we got an Ardor here, which is a different type. We'll see if he's strong enough to fight to knock you out if you fight him. — And my health is on the right. — Your Yep. — He's winning then. — So far, he is winning. Is he going to knock you out? Ah, he did. So, you fainted. Now, if you were to press enter, we sort of transition a little bit differently. It goes to black, but then you get kindly revived and then a little bit of a notice that says your Pokemon have been fully restored. try again. And so that's overall the gist of Pokémon. So thanks uh thanks so much for coming up to uh to try the example. So we saw a lot of pieces there. Uh certainly in order to run the full experience, we kind of had to go through a few different things there, but there are a lot of things that are happening sort of invisibly that structurally might not look all of that different than what we've done. But we had some dialogue boxes for the first time. These sort of boxes that are actually rendering a rectangle with some text. We had a menu there in the battle state which allowed us to actually choose options which then affected the game in particular ways. And this is just kind of the beginning of what guey means. Graphical user interfaces, what they can look like, how they can behave. But Pokémon is a great test bed from which we can start to implement some basic guey elements. Even the progress bars that were shown there, the health and the XP were also guey elements with their own values and their own sort of ways of rendering and behaving. And they have of course interpolated behaviors that we've been using timer. Tween and the like. Even for the transition, some of those things are repeated things, but a lot indeed new. So when I was first learning uh Lua and Love 2D a little bit more in detail many years ago, one of the things that I was looking at was this resource, how to make an RPG. com, which I learned some of the things that go into this lecture as well. And I just thought it was a great resource when I was going through it. So I encourage people to give that a look if they're curious. The sprite sheet we'll be using today, we'll actually be making use of the Zelda sprite sheet. Again, in this case, we're not using any of the monsters that we used previously, but we needed a character avatar to represent our character moving in the field. And so, we are just using this section of the same character sprite sheet that we used last time. We also are using this tile sheet here for the grass part, particularly two of the tiles here that are flat grass. Folks might have noticed that we had flat grass, but also the deeper grass. And folks might have noticed we actually are rendering two layers there. In this case, we're also rendering this thicker grass on the bottom where we're testing. Okay, as the player walking on thick grass, this is a Pokemon trope where don't go into or beware of the tall grass because that's where you'll find a Pokemon, the wild Pokemon that will try to attack you. You can then try to capture it and that's often one of the goals besides just making your Pokemon stronger why you'd want to go into the tall grass. But we are adopting the same idea whereby these tiles will uh end up giving you a chance every time

### Segment 3 (10:00 - 15:00) [10:00]

you walk uh as your character is in their walk state to trigger a wild Pokemon random encounter. So the first thing that we'll take a look at just to sort of set the stage for the new elements that we're going to look at today are guies. What they are and some basic versions thereof. So guies are just literally graphical user interfaces. They're very frequently built up of many smaller parts that com that compose in a sort of way to give us more complicated UIs. In particular, folks might have noticed we had menu sort of these panels that were relatively similarly styled for the dialogue box and for the battle message states and whatnot and even the menu that folks could choose options for within which they will render text. Then you can have things like cursors and progress bars and you can do all kinds of really fancy things with guies. And we'll keep it relatively contained today. Well, primarily just be looking at panels, text boxes, selections, and menus, uh, and the like, but folks can h there's all kinds of things you can do. You can do various wheels, various kinds of style toggles. Especially for folks familiar with web development, there are many, many different types of UI and elements and widgets that people create and build upon. And so, we'll be looking at a few examples. So, I'm going to transition right from this into a few examples that I prepared in advance that we can take a look at. gonna transition over here and sort of close out this main Pokemon source file which we will come back to 100% but I'm going to open up guey zero and I'm just going to run the code that's in here to start with and folks will see that it is somewhat underwhelming perhaps in its presentation but it is the same rectangle that folks might have noticed that appeared in the Pokémon example. This is just a panel meaning some kind of flat surface upon which we can draw something and contain something. And these can maybe be moved around and placed in different parts of the screen or whatnot. And you can use modal or you can use panels to affect certain things like modals on the screen and the like. But they're essentially just a contained canvas upon which we can draw things. And folks might notice that there's a little bit of a styling going on here just for a sort of visual flare to not just make it a plain rectangle. You can add some sort of border. And you can get really fancy with these. We're just going to essentially use two rectangles to accomplish this. But all we're really doing, it's quite simple, only 50 lines of code or so. If I come up here, we'll notice that we besides the class itself, we are creating a panel object which is going to be at 1616 XY. It's going to be 32 pixels minus the height and the width to accommodate for the 16 pixel offsets from the corners. And then we're just going to draw it and then we're going to render it as usual and update it if it so had any behaviors we would want to update. So let's go ahead and take a look at what panel itself looks like. It's going to be pretty simple, right? It's got an X, a Y, a width, and a height. whether it's visible or not, should we want to toggle it on or off with a keystroke. It's got an update function that we're not doing anything with. And then if it is visible, if it is actually set to render, we're going to first draw a white rectangle that is going to be slightly larger than the actual contents thereof. And so this we're just drawing it at its full size XY width height with this sort of pixel border radius this rounding value which is going to be how many pixels of sort of effectively beveling or rounding are going to occur at the edges of the rectangle. And this is something that you get just with love. graphics. rectangle. It's something that's also in CSS in the web world. It's very common. We can also then here set the color to sort of a grayish color, a really darkish gray color. And then we're just going to draw the same effectively rectangle but just shrunk in by two pixels on either side. And what this is going to do is make it look like we've got this two pixel border around the entirety of our rectangle. Um but we are effectively still drawing at xy width and height that same rectangle. And if I go ahead and run this one more time, we'll notice we do indeed have just effectively two rectangles drawn in and centered in the screen. So a sort of simil simulating this idea of having this border when all we're doing is just drawing two rectangles. So that's a panel. Panel is very simple. Nothing too complicated about it. The next example that I would like to bring people to see. So some folks probably saw panels in the Pokémon game. And in fact, if we just run this really quickly, folks might notice besides the intro screen. I'm going to press P to sort of pause the game here briefly. Actually, it's not necessary. The audio will still continue. But notice that it is the exact same rectangle only it's got text on the inside of it. And so that brings us to the question of okay how do we actually draw a text box or the like? And it's quite simple although there's a bit more complicated code in deciding you know if you want your text box to have this ability to make sure it contains no more than the text inside of it. We're going to have to adopt a couple of considerations for that. But I'm going to go ahead and open up guey one here. And then we'll notice that I've gone ahead and supplied some Lauram ipsom like text. This is actually a Latin excerpt here about the nature of good and bad and such forth that I found on Google from Cicero. But effectively, it's just a large block of Latin text. Notice that it looks like it doesn't quite end at the bottom of the screen.

### Segment 4 (15:00 - 20:00) [15:00]

And that's because if I press enter, we'll notice that it continues to the next section of text. So our text box is intelligent enough to know that should the text overflow the bounds of this box. We don't want to essentially keep rendering it past the border of the text box. We want it to store the section of text that it's currently rendering and what it should render gets changed on the next click of enter. If I press enter again, notice that it's still going. Quite a long excerpt here. It looks like it finally ends. And if I were to press enter, it does indeed close the text box. Therefore, representing the conclusion of the text or whatever purpose we want that to then impart onto our game. For example, maybe we go on to the next state or whether this, you know, to sort of set the stage. Maybe itself is a state that we can think of that takes input. It will sort of get rid of itself and allow us to continue to the next part of the game. But we have effectively now a relatively robust text box. If we were to look at the code here, we'll notice that not much has changed in Maine. And we do indeed still have a text box. We do still where we had the panel rather we are instantiating a text box. And it takes the same sort of arguments here. It takes a 32 in this case for the x and y and then a width and a height. A really long string for the text here. And then we're passing in also a font. So, we've allowed our text box to take in varying fonts of different sizes should we choose to want to display a larger sort of exclamatory message or something that's more like a dialogue box which has smaller font. And thankfully, Love 2D gives us the ability to depending on the font calculate what the line height is of our text. And so, with this information, we can then calculate how much to fit in a text box. So if we open up textbox here, notice that we're including panel because textbox itself includes a panel within its instantiate within its constructor here. So we are not only going to be rendering a panel as before. We're essentially building on top of this guey element that we created previously, but we're going to now start to add new things to it. We're going to take in this text and a font as additional parameters beyond what we took in with the panel. And then we can sort of preserve those. By default, we'll say, okay, we'll be a small font if we don't have a font that we got passed in. And then we're going to pass in we're going to rather we're going to initialize some variables here that are going to allow us to pad things more appropriately within our text box. So, we can provide a global padding. For example, if one were to render without any padding, if we were to set this to zero and then run this, folks will notice that it is uncomfortably close to the edges on the inside of the text box. And this is very not aesthetically pleasing. So what we've gone ahead and done is there's an actual come back here padding variable here which is going to apply to all print operations. So everything ultimately is going to be deferring to print which is what we've used so far with some helper functions we'll take a look at here in a second. But we can if we apply some padding around the edges now we have a much more palatable to our eyes sort of container for text. We have a line height we're going to get a reference to, which thankfully Love 2D gives us this ability. Every font that it has, it knows the line height of the font. In this case, if it's medium, I believe it's 16 pixels. And if it's small, it's 8 pixels. Might be 8, 12, 16, or 32. And so these pixel sizes are able to be essentially the determiner for okay if I know that the line height is 12 pixels or 16 pixels. And then I know the height of the box. Okay, I can fit that many lines of text in my box. And then if we want padding between the lines, for example, some extra line padding, we can just pass that in here as another sort of addition that applies to that multiplier per line, which then ensures that every print statement that we call is spaced out a little bit more from the surrounding print statements. And so we want to get the also the number of lines. So we're going to have to call a series of print statements. Folks might anticipate in our panel. If we imagine drawing it, we want to then render every line of text that we know will fit. And so it's going to call several print statements, one for each of those. And then we want to know how many lines can we fit. And so we're essentially going to take the height times the padding. And then we're going to divide that by the height plus the padding. So that we get that actual what's the font's full size if you were to add the line padding to it. And then that divided by what effectively is the height minus the padding because we're accounting for that because that's going to shrink effectively our renderable box. We therefore get the number of lines that we can draw, we can render into our box. And so folks might also notice this kind of interesting function here, which is this font get wrap function, which is kind of cool in that you can give it this large block of text and it knows the effectively what the width of the text will be. It effectively just sort of does a render or a simulated render of that text. It'll know the width of it. And then if you can say, okay, now I know what the box width is that I care about to render the text in, which is going to be this self. width minus 2

### Segment 5 (20:00 - 25:00) [20:00]

times the self. padding. So twice the padding taken away from the width of the box. If we know that and we know our text, well, Love 2D can just divide and figure out, okay, for every line, what would the width be? And then I can figure out, okay, I need to clamp the text to this much size per line so that it doesn't exceed the width of the panel that it's trying to render into. and through some just management of like okay how many chunks am I going to render I'm going to maintain a reference to what the start ID is get the end ID based on the number of chunks and we're going to uh add however our max lines is minus one which is going to therefore eventually give us the number of lines that we can render right now in this chunk and then preserve an offset so that on further iterations of it we will be able to just keep rendering and rendering until we are at the end of the number of lines of text this being self. ext chunks which is returned as a table from this font function. So therefore we iterate over it. It's going to be this array of various subsections of this longer text block. We will reach the end at which point we can then set end of text to true. And if end of text is true, we can then toggle should we call this next function which will occur on every pressing of enter which is you can see here in update. We will then set the panel to toggle itself and close to true. Therefore signaling that we've reached the end of that text box. And so now we have the ability no matter what the text is, font is given some padding which one could make parameterizable. You could or sort of you could make you could add parameters to this function in order to make it customizable such that the padding and such is tweakable. Folks could also just tweak it directly as a field on the object if they wanted to. And now you have this very easily stylable, customizable u within certain limitations, but sort of text box that serves I think most at least basic purposes particularly for today's RPG example. And so that is the gist behind. And again down here we have a sort of set of chunks which we're going to render. We have a set of displaying chunks we're make we're holding a reference to. Every time we call next we're getting this set of chunks of that greater table of broken apart text chunks. And then we'll just iterate over it. we'll print and we'll do some calculation based on the X and the Y and also the line height and the padding. Those get added to every Y operation that gets multiplied down the line of chunks. And so that's the gist behind how a text box works, how a customizable sort of like detectable text box works given a particular font with the methods that love 2D gives us thankfully on their font object, which is what we're dealing with every time that we have a new font. We can therefore call functions like this get wrap and get height. So that's the gist behind how a text box functions. So that's text boxes then. But you know as folks might have seen in the game you have text boxes sure for the dialogue and whatnot. And we've seen how those work and how they can you can press enter to toggle them and remove them. But folks might have noticed in the battle state, we had what looked similarly to a text box at first glance, but which was actually a menu which had a cursor and you could move options around and presumably when you click on those or press enter on them, they do a different action and could be wired up there for. And so I think it's important for us to take a look then at how we could make something like that work, which in concept might seem similar, but actually does have a fundamentally different approach to it. So, if we go ahead and close these existing files here, I'm going to open up Guey 2. And then let's go ahead and run Guey 2. So, folks might notice here I do have a menu which is sort of wired up also with the sound effect from the game as well. But notice we have four options. We have a red, a green, a blue, and then a quit option. So, as folks might guess, quit does indeed quit the game. So, I've got behavior wired up to the game. And then if I were to reopen this and then for example, folks might be able to guess what's going to happen here. If I click on red, we do indeed get red set as the overall clear color. Green and then blue and then quit. So we're affecting the world. We're affecting the game in some way based off of this menu that we've created. It's still a text box kind of and that it doesn't have a panel in this example. What we are using here is technically we're calling it a selection. And we'll define a menu as being a selection that has a panel underneath it that effectively is being rendered. Therefore, like a menu in a game might have a panel behind it. But the core of what's on top of that we might just call a selection. And that selection is going to have varying options which we can click on or select. And then on select there will be some sort of you know maybe anonymous function that we can wire up that performs some operation does something in our world that affects other things outside of the selection or the menu. So if we go ahead and look at main here and I come down here we'll see that we do indeed we have textures and sounds and whatnot that we've wired up just to get the example to be a little bit more sort

### Segment 6 (25:00 - 30:00) [25:00]

of uh visually interesting and also feedback provide some feedback. But notice that we have the selection. We're passing it in and instantiating it with a table, which again in we believe I believe we talked about this previously, but just in case, if you pass in just a table instead of instantiating with parenthesis, it's effectively the equivalent to calling a function constructor with the parenthesis and the curly brackets. So in Lua, you don't have to call if your first and only argument is a table, you don't have to pass in the parenthesis. So that's all that this means here. So, we're effectively going to pass in a table, which is a definition, which is going to have an x and a y, a width, and a height. And then it's going to take this items field, and this items field has two elements on each. One being text, so what it should render in that selection, and then one being the on select callback function, which is similar to some of the things that we've looked at previously with game objects and the like. But here we have this on select callback function which is again just an anonymous function where we're going to set some global variable BG to the table of 1 0 here for red green blue. So this is just going to be full red here for green it's going to be set to 0 1 0 for green and then blue 01. Notice that down here we can see that we are calling love. graphics. clear clear which will clear the screen fully render it with assuming nothing is being drawn on top of it with either BG should it be defined or 000 just full black which is what we started with when we ran the program. Notice that we are calling selection update and selection render. So if we go ahead and open up selection here, it takes in that items defaf or takes in a defaf rather where it can get items the x y width and height a font as well. Should we pass one in and by default it'll be just g font small which we've defined in our main. la. There's a height based on how high how tall the actual selection is and then divided by the number of items. So there will be a certain gap between things dependent on so it actually uniformly distributes the selections items within its container. And then we're just going to instantiate whatever the current selection is. We need to know which the current selection is so that we can render a cursor onto that particular item to its left. And so if we were to press up or down, we will shift the number of our cursor playing sounds as we do so. And then if we press return, we're just going to add selfite items at index self. curren current selection just call that on select function. And so whatever that does, it doesn't really matter to selection itself. It could be anything we want to, but folks might be able to therefore draw the conclusion that in Pokémon when we do the menu, for example, fighting ought to trigger. Unselect is just a function that's going to trigger some sequence of events where one Pokemon depending on their speed is going to attack another Pokemon. And then you're going to see the animation and the HPs sort of decrease. And then same thing for run. And if you were to run, it's going to trigger a transition to a different state back to the field state, but through a different sort of operation. And it's the same exact logic that happens there. It's happening here in selection. Just we're changing the background color with that function instead of doing something a bit more grandiose. And so we can render it just by simply iterating over all the items, figuring out where the Y should be based on the gap height, and then draw the cursor should we be at I being self. curren selection in our loop. And then we'll just draw the text as well. And that's the gist behind what a selection is. Text being drawn, a cursor, or some visual indicator. You could certainly highlight the text in a different color, which we did a similar version of this implemented a little bit less robustly for something like breakout at the title screen where you had start game and the high scores. You could go between the two of them. And then that would effectively accomplish the same thing as this. Uh only those were not as implemented in as sort of customizable a way. looking to the future for other guies. This is meant to be a replacement or a drop-in widget that you can incorporate into any sort of piece of your game to accomplish the ability to select things and have those selections affect the game state. And so lastly, that was the panel. We looked at then a text box and then a selection. I'll say that a menu is essentially just a selection on top of a panel. So, we won't have to necessarily look at a an actual example for something like that. But the last remaining gooey piece is, as folks saw in the battle, a progress bar. And progress bars are omniresent in the web and things like that, especially for loading indicators and such, but they're also used for things like HP and for just overall stats and things that go down and that you want to be paying attention to in a game. They can be used for all sorts of things. We'll be using it for HP and XP. XP being experience points or sort of this value that represents how close you are to gaining a level, which means if you're level five, you go to level six and then

### Segment 7 (30:00 - 35:00) [30:00]

you'll get stronger. And then in the actual Pokémon game, when you get to like level 16 or 32 or something, depending on which Pokémon it is, you will evolve and turn into some more powerful, typically larger, more fierce looking or more sophisticated looking Pokemon. We won't have evolution implemented in this problem set, but we do want to look at what a progress bar looks like. And so I'm going to go to main. la in guey 3. And I'm going to close all other examples here. I'm just going to run this. And we'll see that we start with this sort of gray background with a dark progress bar sort of simply filled. And if I were to press right, notice that it fills from left to right in green going from zero effectively zero to one. And then if I were to press left again from one to zero, we have a the progress bar now going in the opposite direction. And if we just think about a progress bar as having a max value and an actual value, then we can determine whether from zero to that value, how far we should render maybe this inner rectangle. So if we imagine having this outer rectangle being again another sort of like border radius rectangle that we're drawing just line rectangle and then a fill rectangle inside of it that is drawn with its x sort of direction or its x its width scaled based on whatever that max or current value happens to be. We can then as folks might be able to anticipate use something like timer. tween to tween that width to sort of up to the value of one times that multiplier of whatever the max value is to give us this transition over time rather than hard setting maybe the progress bar. Typically progress bars are more fun when they animate versus when they just are there. So this gives us the ability to do just that. So let's take a look at what the progress bar itself actually looks like. If we come up here, we'll notice that we are defining a progress bar as taking again this table definition much like all the other guey examples we looked at. XY width and height a value to start with. So this will be whatever the actual value of the progress bar is a max value. So we'll just say we're going between zero and one, but this could be zero and any value that we want. If we're dealing with Pokémon that have 30 HP, then you'd want this max to be 30. Or if we had an XP that you need to level up, this might be maybe you need 150 XP before you level up. So this will be set to 150. Then a color. We can make it whatever color we want to. So folks might have noticed we used red for HP. You could use green for HP. Different RPGs might use blue to represent magic points or mana. And then they might use in our example, we used a we used blue for uh XP, but you could use any color. You could use gray. You could use whatever color you want to. they typically will have a different semantic purpose. So we'll offer the ability to customize that color here and then a text and a font should we want to render things like that uh label and so on. So if we are animating and this is the gist of this main. la here this is where essentially we're going to kick off based on whether we're pressing key left or right to trigger a tween from min to the max value or from max or from whatever the actual value is to its max value which is what we do. But we pass in PB in this tween syntax which we've seen before. Over 1 second PB's value we'll set that to one and to zero if we press right or left successively. And then because the max value we defined as one that'll have the effect of transitioning the actual when we render it if assuming that we're rendering the value based on the max value. We'll look at the actual progress bar to see how it gets rendered here. But that'll have the effect of rendering a portion of it and tweening that value over time. You'll notice that we have the render width, which is right here. It's the value over max times width. So that will just ultimately be some sort of multiplier between 0 and one. So if it's 0 over one, it'll be zero. And if our value is actually one, it will be sort of one. It'll be just a multiplier on width and it'll fill the progress bar. Then we'll set the color here to uh the actual color that we set in the progress bar and then fill the rectangle based on that render width. And we'll also curve it just a little bit in addition to the actual uh line rectangle we want to draw around the bar itself. And that's the overall gist. The actual init function here, as you can see, isn't all that interesting. It's just a initialization function. It just takes whatever the definition is and set those as member fields here. But then we also have a set max and a set value function just as a couple of setters should we wish to use those. And that's the gist between that's the gist on how progress bars work in our game. And that overall is all of the core guey components that we will use in today's lecture. But I thought it would be fun to do a little bit more than that which we'll take a look at in just a second. But first we want to take a look I think at state stacks because this will make the example clear. And this is also the other big element in today's lecture

### Segment 8 (35:00 - 40:00) [35:00]

that we want to talk about. A state stack being so far we've talked about state machines, which is just a way of representing some state that we're in has a transition to some other state based on behavior. So if we're Mario and we're ducking and we press spacebar or we let go of the key down, we jump. Or and if we're idle and we set, you know, we press left or right, we start walking. And those are different states. transitions between states, but we can only be in one state at a time in that model. So in a state machine, you you're only ever in one state. You're not in multiple states. You're not walking and idle at the same time. They're mutually exclusive states of existence. Same thing for the game so far, the game states that we've looked at. You're either in the play state or the serve state or whatever state. You're not in both of them at the same time, which wouldn't really make a lot of sense. But games are unique in that you often are sort of putting certain states on hold. And for example, folks might think of like pressing enter or spacebar or escape. You pause the game. And often it's the case that you see a menu, but you can also kind of see what you were doing in the game in the background. And that's not really possible if we envision this model where you have a state machine that's transitioning from one to another state. And recall they were all like being spun up and instantiated in these anonymous functions that were only being held in one reference to one state at a time in our state machine. And so how do we go about accomplishing this idea of having for example a pause state that's different from the play state but which can render on top of the play state while the play state doesn't do anything. It doesn't move. It's like stays paused. We accomplish that via what's called a state stack instead. So if we just think about actually taking a state and then stacking a pause state for example on top of a play state directly, well now we've got two states. And if we were to just only update one state, let's say the pause state, recall anything only moves if we're actually updating with delta time. So if we're not actually updating the play state, we could hold it in memory and nothing's going to change. Nothing's going to update. And then we can instead focus only on the pause state, which might move. It might have a menu. menu of resume game or options and quit and so on and so forth that we can move back and forth between and select options and still see that g that play state in the background. And so what we can do if we just layer on this new state only update that state but render all of the states in order that they were pushed onto this stack. Well, now simply you can see all states as they exist while being only able to update you know maybe the top state, maybe multiple states if you want to have a couple of states that still move. Maybe certain parts of underlying states can move independently. We won't get that sophisticated today. We'll only show a relatively simple implementation of this. But with this one tool, we can now do a lot more sophisticated rendering of UI and game states in a way that feels more robust and true to what most games typically do. So with that, let's take a look at what state stacks are and what they look like, how they're implemented, and then look at a fun implementation example. And this is going to be in stack. So before I run stack, I'm going to first show what a state stack looks like. And it's quite simple. It's very similar to a state machine, at least the state machine class that we used previously. Notice that though we now have instead of whatever the current state is, we now have a states table which is going to have multiple states that we can store inside of it. We'll have an update function. So if we don't have any states, we don't want to try to update anything. But assuming that we do, we want to just render whatever is at the end of states. Meaning whatever we insert into the table is going to go to the very end. And this is how we're going to approximate a stack. based behavior. So when you insert a new thing into a table, it's going to add it to the end and then when you remove something from a table or pop it off of a stack is the term uh independent of Lua, it will remove it from that same endpoint. So whatever you add in will be removed out on the next iteration. First in first out, in other words, FIFO, which is how stacks behave. And so what we can do is if we just set it to only update whatever at number of self. states states is in that self. states thing. Well, now we can even if we have a bunch of states in all the indices up till that last index and we don't update them, they won't change. They'll stay in the exact state we left them in. And so we can sort of think ahead in terms of how that might allow us to do things like pause screens and the like. Same thing with process AI, which isn't all that dissimilar to the update function which we used previously. But notice the difference, the key difference here is that rather than rendering just the end state now, which wouldn't be all that different from the previous state machine, although it would allow us to maybe have the preservation of prior states, is that we're rendering the entirety of our stack in order from the start to the end, from the oldest to the newest. Meaning that if we start on a play state, we open up a menu and that's its own state, it's going to

### Segment 9 (40:00 - 45:00) [40:00]

render on top of whatever was below it if we're in the field, for example, or battle. And so if we that's the only one updating that gives the effect of the menu is going to update but the background will stay frozen which might be exactly what we want. And again it might not be exactly what you want depending on the game. You could get more sophisticated and have certain states flaggable as being updatable even in a stack and then you could do some more sophisticated logic here and update rather than just rendering only or updating only the last one. But for today's example just to illustrate the concept we're going to do a simple implementation. And so pushing will indeed insert whatever that stack whatever the state is that we care about. Notice it takes a state. So we'll just be able to instantiate and pass in a raw state. It'll push it to self. states call enter on it. And then we're going to pop by just doing the exact same thing essentially calling exit on whatever is there at the end and then removing it from our self. states. And so with that example, now we can sort of entertainingly I'm going to run this code and we'll see what we can accomplish with this. This might take folks to some eras of uh perhaps the '9s or 2000s on the internet if they were to sort of not be careful with their browsing. You might see something that looks something like this or perhaps a computer of somebody who accidentally stumbled upon a virus or the like. And what's kind of fun about this is that these are actually all states. These are a hundred states that are being instantiated onto the screen. They're all being rendered, but only one at a given time is actually being updated. So notice that we've included a label at the top left to show us just how many stack states we have currently. We have stack size of 100. And so we're using Lauram Ipsum text here. If I press enter, we'll notice that one of them gets updated, right? Until finally it's going to close and then end. And then it gets popped off and notice that now we have 99. And so, you know, I could sort of almost fruitlessly depending on the virus, you know, you might have more states that are kind of being added to this so quickly that you can't even close them, right? But this is kind of the trope for I think of old Windows XP or Windows 98 or the like. But this is a nice effective illustration of just how robust you can get certain interesting visuals and updated mechanics in your game now not just being this mutually exclusive place where you only have one state at a time. Now you can have as much memory as your computer holds worth of states effectively. Now typically in practice you probably won't have more than a few. You might have a play state or a field state and then a menu and that menu might pop on up some additional menus and maybe you'll have a depth of 10 to 20 at max. Typically you won't go to 100 but now you could very easily do that and you could implement very robust UIs in this way that have sort of this ordered priority of rendering. And again you could implement more sophisticated ways of rendering and updating multiple states at the same time rather than just updating whatever is on top of the stack. But here for right now we're just focusing on whatever is at the top of the stack. So if we go into here we'll notice that we have created a state stack here. Now instead of a state machine we'll call it g state stack. We'll say we have a cap of 100 states and then we're going to create this little function here that's going to if we're less than the cap if we call it spawn popup. We'll go ahead and we'll push new pop-up state. We're going to instantiate a new pop-up state onto the G state stack directly. increment our count and then every 0. 05 seconds here. Again, a great use of timer. Which we've seen before, we will then pass a reference to that function spawn pop-up. So again, you can use either anonymous functions or you and we could have just done that directly in line and you can also define them as a function somewhere with a name and then pass the name in just like this. And what that effectively is going to do assuming that we then call very similarly to previously this instead of calling G state machine update we're calling G stateack update and then G stateack render and then some additional logic here just to make sure that we uh display the number of states that are on the screen. This new pop-up state does exactly as you might expect. We're going to essentially define this sort of random set of lipom texts that I found in a table. It'll choose between any one of them any number of times between two and five. It's going to add that as a it's going to concat concatenate that as a string rather using table. conat which takes a table and then for every element it'll concat all of its members to be uh with this separator in this case a space. So we can then just define a text box with this text random laurum and then xy width height with that text as usual stuff we've looked at with text box. And then what's kind of neat here too, which gives us the ability to actually remove these states from this stack to allow us to get rid of a text box, is going to be when the text box is actually closed, which the text box has an update function just like any of these other GUI elements, which sets closed to true if we were to press spacebar and close it. At that point, we

### Segment 10 (45:00 - 50:00) [45:00]

will then pop whatever the highest state is going to be, which in this case is going to be this new pop-up state. And so therefore, we can pop ourselves off depending on how you want to look at your code. If you're going to pop a bunch of states or push as we look at in the actual Pokemon source code uh our Pokemon source repo main repo, there's going to be lots of examples of this, but this is an illustration of how you can sort of get this pushing and popping in order to affect changes and to move from one state to another even in this stackbased model. And so therefore, not just render one menu or one state, but rather now we can render hundreds, thousands if we wanted to of these little essentially micro states now and sort of break our game up into pieces as a kind of fortunate byproduct. So with that, we've essentially looked at all of the new topics that are primarily of interest to us right now, at least in terms of primarily the new code related things. Although we do need to take a look at, for example, the RPG mechanics and the overall turnbased structure of Pokémon that is unlike some of the things we've looked at before, as well as do a general look at some of the code that is in the main repo itself, the main actual part of the lecture and problem set. I'm going to go ahead and close all these examples and then let's open up Pokemon again. And not much in here of main. lua Aloa is going to be that different. Although folks will notice we do have a state stack and we are pushing a start stack onto the stack. And so this model is different slightly than what folks are used to probably in the examples thus far where we have gstate machine change to this sort of like toggle operation between one state and another. are always pushing stack state rather uh states onto the stack and popping them off whenever we are trying to transition back to something else and so it's just a slightly different mental model but altogether everything is relatively the same in here everything is just being deferred to the state machine and the state stack rather we are still using state machines for entities and the like because those are still ultimately these sort of mutually exclusive states we don't need to have multiple states of an entity certainly you could do something like that if you had an entity with various parts that might behave in particular ways or layer on top of each other and still ultimately have some kind of a behavior or a graphic that needs to render. But we don't do anything like that in this example. We will still be using state machines just for those. We won't spend a ton of time looking at the specifics of that. But if we look at the start state, if I go over to our states here, everything is still in game. We'll notice that there are quite a lot more states this time and we'll take a look at these. But the start state is ultimately still just a regular state. We have an intro music. Folks might remember if I go ahead and start this up and play this. We've got this sort of this is characteristic of the I think this was used in several iterations. Certainly it was used in red and blue, which was what I grew up playing. Uh and I don't think it was used in gold and silver, but red and blue for sure, where you have these Pokemon moving left and right. And then this is sort of what the start state is. And then to walk through it just really quickly, notice that we do a fade to white, then a fade out from white to the field state. Notice we have a dialogue here at the start. This is its own state. So we press enter to dismiss it, which pops off the stack. And then now we're in the field. If we move through the field here, we're just moving. And then an interesting thing to note too, and this is a part of what makes a JRPG sort of this might have been common even as far back as Ultima, though I believe Ultima was smooth in some of its iterations, but certainly its first early ones were grid- based. But JRPGs tend to be grid- based movement as opposed to continuous movement, which is what we looked at previously in most of our other examples. But if you go to like Final Fantasy or Dragon Quest, these old school Japanese RPGs or Pokemon, you'll notice that if I move up, for example, I'm just going to press the arrow key once, and he continues to move in this sort of discrete motion. And this is not uncommon. The world is sort of conceived of and thought of as grid more so than it's thought of as this continuous sort of and this probably has to do with early hardware limitations but it became a sort of traditional facet of JRPGs which is that at least in classical style JRPGs you move in a very fixed grid-based fashion and so if I move this way you'll see the character does indeed move and so what we can do is we can essentially just say okay if you press left right up or down tween your position be this animation But don't stop and don't take input. Don't treat input until you've arrived at what is that tiles offset times whatever the or rather whatever the XY of that grid tile is times whatever its pixel value um whatever the tile size ought to be to get its pixel value transitioning it translating it to zero based pixels. And so if I walk through the grass

### Segment 11 (50:00 - 55:00) [50:00]

we'll notice eventually, and this is random, just a random chance. We pop another fade state. And then we have a again another state here with a couple of dialogues. These are battle messages, battle message states. We have a menu state here. So if I hit fight, we then go into the attack, the take turn state, which is kind of like a an attack or a fight state. So in the take turn state, we'll see that a couple of operations happen. These are sort of like timer based operations. So after a certain set of time, do this animation, blink a certain number of times, do another animation, blink a set of times, choose whichever goes first, whichever goes second. And so once that's finished, then we pop back off or back into the And then we pop another menu state back onto the stack. And then we just do this over and over again until eventually the goal is that should we I'll illustrate it here. Should be able to win this fight. It looks favorable for me. Oh, just right at the right at the cusp there. Okay. So, we pass a me put a message onto the stack and then we're going to do a transition after well an X. We're going to do the XP first cuz we won. And then we're going to essentially it's hidden. It's sort of invisible, but what we're doing is we're fading and then we do several pops off the stack because we have the battle state, we had that message state, we've got a fade state that's on the stack at that point in time. And so we have to do several pops there. But if we do pops of all of those states, we get back ultimately to where we were before we left. We're in the same tile that we were there previously. This hasn't changed. We're not reset. For example, when we instantiated it to start with, we had the dialogue that was there. So, we're preserving where we were, but we have to think of things a little bit differently. We can't just change from field to battle or battle to field or attack to not attack. Things have to be popped and pushed off. And so, we have to mentally keep track. Where are we in the stack at this point in time? And especially when we deal with sort of these asynchronous things happening, it can be a little bit of a balancing act. And you have to make sure there's no bugs in your code when you're doing this cuz if you were to accidentally overpop a state, there's not going to be any states left. the field state. Once the field state's gone, you're essentially finished in the game. You have nothing left in the game. No more states in the stack and you just see a black screen. And so if that happens to you, if you just have a black screen, you might have over popped. And if you're stuck in a state in a way that you feel like doesn't make sense, like it's waiting for something to happen, you might have underpopped states as well or over popped in a different context. And so that's the only different differentiating factor here that can be a little bit tricky to fully get used to, which is this idea of asynchronous state popping based on time, which is common in a game like this in an RPG where you have animations taking place that have to exist that have to once they're finished resolve and then maybe you knock out your opponent or they knock you out and you have to go to a different place. Make sure that these things after a set of span of time occur in a very well-managed, very organized way. So the start state here is such that every 3 seconds here we're just animating some characters back and forth on the screen. These sort of fake Pokemon which are taken from a an open- source version of Pokemon. Folks might notice that there is a Pokemon defs constant table here with some ids. If we go ahead and open that up, I've titled it Pokemon defs here in the source code, which is again datadriven design. We talked about this before. We don't want to necessarily think about the specifics of this when we're loading in a data set, especially now that we are actually using these values in the game for a meaningful way that's not just rendering related. We have the name of whatever that fake Pokemon ought to be. Sprite for its front and its back cuz recall in battle we have the back view. We see the front view for our opponent. the start state. And then we have these actual sort of base stat values which will be where that Pokemon begins with its values. There are these things called stats in an RPG that determine how much damage do I do against an opponent that has a certain defense. I have an attack. They have a defense. There's some math involved that calculates what the damage result should be. Should the attack go against the defense value, there's going to be a resultant value, and it should no be no less than one. We should at least be able to do one point of damage to an opponent. And then we have these things here which are called IVs which we haven't talked about which are actually part of Pokemon which are these sort of individual values as they're called which are essentially just a reflection of your Pokemon's almost DNA in the sense that it reflects how it's going to over time level up and change. It's going to essentially be this value that we test against randomly and should we randomly generate a number that is less than that number it's going to evolve it. it's going to increase its damage. And so the higher the value of these IVs is, the more that stat in particular is

### Segment 12 (55:00 - 60:00) [55:00]

inclined to level up throughout all of its level ups and inclined to increase per level up. And so this is often a thing that people that play Pokémon like to do. They like to find Pokémon that have particularly good IVs for their Pokémon and then evolve them or grow them over time so that they relative to another of that same Pokemon will be stronger at some level in the future. And that's effectively what we've modeled here. And we've done it in data. We don't have to worry about that in our source code. We can just say, okay, here take this definition and then when we instantiate an actual Pokemon, we can look, okay, what are its base uh stats? What level should it be? Okay, we're going to multiply its level times the IV calculation to get its final stats. And then therefore, every time you level up, that same uh operation will take place. And then over time, that's how you get leveling up and getting stronger and stronger. and then that core loop of going through an RPG and being able to defeat and surmount higher and higher difficulty obstacles. So in the start state, we have that being used here just for the sprite itself, but this will actually uh accommodate the instantiation of the actual Pokemon as well. So what we're doing here is we're pushing a fade in state when they press enter. There's not really a whole lot going on besides the animation. And there's a tween occurring of the Pokémon going left to right or rather right to center then center to left and then that just allows you to see this sort of like slideshow of some of the species that are in the game. But what we want to do if they press enter is previously we had this idea in other games and we started it with match three where you have this rectangle on the screen in whatever state it is that you want to transition to some other state. And while that worked and it was fine, should we decide, okay, I want to transition this state to maybe a different state with a different color or I don't want to do this kind of a transition. Having a coupling of your state of your transition states to your actual, you know, be it the title screen or be it a play state or whatnot isn't as ideal as maybe being able to think of that transition as its own state. We can think of rendering the underlying state, the underlying title screen, and then pushing a transition actually on top of that state, existing state. So we'll look at fade in and fade out real quick. And here we're using the semantic of fade in as in fade a color in to full from zero. So if we have some RGB color that we want to fade into, fade into red, fade into white, we're going to essentially define it in this instantiator in the actual constructor. And then over some period of time, we'll just do this tween operation. And then notice we're just calling pop. It will pop itself off using that finish function, which takes the anonymous function. And then it will call this on fade complete function. And this is a very common theme in this kind of programming where you just have lots of callbacks and this is common in web as well. You have lots of callbacks and guey programming is very callback driven. Um very famously event and callback driven. So we'll pop our this state off from the stack assuming that we'll always sort of assume that this is the topmost state and then we will call on fade complete afterwards. So we can pass in if we look back at our actual last file which was the start state. Notice that it takes in this function. So we have a time that we want this to take place over the it's going a second. But then we have this function where after we fade in, we're going to stop the music where we're going to after we fade into white rather. So we're going to be at zero opacity. We're going to fade into white. So there's going to be completely white screen in this new state on the stack. And then we're going to remove the tween operation that was in this file for the Pokemon themselves so that we don't reference it and have a crash later. We're going to then pop the start state itself off the stack. So there will no longer be a start state, but we're going to push now the play state. So we've essentially accomplished the transition between the start state and the play state by just popping the ladder and pushing the former. And then as well notice that we had the dialogue state when we started the game and only game. We're doing that here by pushing this new dialogue state which I will pause it is just simply a wrapper over a text box that has the same enter button the same toggle operation that we saw previously. And then lastly, if we want to fade out that white color to opaca like to zero opacity, that's remember we popped that ourselves in the actual fade in state. So we created another state called fade out state which given this RGB here will over 1 second fade itself out and pop itself off after the stack after 1 second has gone by. So we preserve that appearance as if we were fading to white and then fading back out towards the new state towards this dialogue state being on top of this play state that is then ready to take input from the user. And so all that to illustrate now the paradigm within which

### Segment 13 (60:00 - 65:00) [1:00:00]

we're now working which is the stackbased approach and transitioning states back and forth to each other. So in the actual play state we'll notice we've got a level and this level is essentially just a tile map. Nothing too fancy that we haven't looked at yet. And then there's going to be dialogues that can be opened depending on if we faint. And so what we want to do is or rather if we press P to heal our Pokemon, which we didn't take a look at, you can actually heal your Pokemon for debugging purposes, but also just to illustrate having a uh having an actual dialogue state that we can pop ourselves back onto the play state from within it. You can press P, that will open a dialogue, and then therefore you'll be able to heal yourself and also test dialogues. But it's a pretty simple state altogether. We're going to go ahead and take a look at level. And here's also an example of something we haven't done yet before, which is we have not had multiple tile maps rendering. But folks might have recalled, and I'll in fact rerender it just to show you. But if I test exactly what I just described, we'll notice that we do have a couple of tile maps rendering. So, it might not be obvious at first glance because the colors kind of blend together, but we have the green tile map of sort of light grass up top and then we're actually rendering two tile maps such that the tall grass is rendering on top of in its own map the lower underlying grass. And the reason for that, if we were to look at the graphics here, we'll see, open up graphics here to our sheet, we'll notice that the tall grass doesn't have an underlying color. And that's probably by design such that you could choose if you wanted to maybe render this grass on top of sand or something or some other texture that might not necessarily be this specific grass. And so sometimes it's better to often have these transparent sort of tiles/obstacles that might be the same pixel width as the rest of your things. But if you're rendering a tile map and there's only one map, then this opacity obviously isn't going to be great. It's not going to show through. It's going to look like black if anything. And so what we do is we essentially just render a full tile map of regular grass, randomized grass between two different tiles. There's a couple different variants here. and then an additional map that then renders that very grass, that very tall grass, which we can then test for when we're walking around. And so if we go to play state, rather level again, which I should have still open here, we will have two layers, a base layer and a grass layer. And so you can render as many tile maps as you want to achieve varying effects. This is common. You could achieve depth this way too if you have a if you don't want a mask necessarily like we showed last lecture and you instead want to have or rather in uh in the Zelda lecture and you want to instead have a texture that just or a map that renders over wherever your player is like some big archway or something that you know the player is always going to be underneath in the game. You could just render that on top of the player and just have the player be rendered between two different tile map layers. That's another approach that works quite well for a situation like this. But notice that we do have a player with a state machine, a walk state, and an idle state. We then create the tile maps with random IDs given we want two different variants potentially of the grass. And then we just render the base layer and the grass layer. And a tile map is essentially just a very lightweight XY rendering of a two-dimensional tile grid. Nothing that we haven't really seen thus far. A tile is essentially the same thing. has an XY and an ID. Renders itself at tiles at ID. All sort of just like nice and cleanly encapsulated as classes here. So, we're going to close all these examples since there's quite a lot currently opened. And then we'll go back to the play state here or rather sorry, let's go back to level. So, what's important here is when the player is moving around, this is the point at which we want to transition. This is the mechanism by which we want to transition to the other main part of the game which is the battle sort of state, the battle overall system. And to do that, recall is whenever we're moving through tall grass. And so if we're moving through regular grass, it's fine, whatever. We can walk forever. If we're walking through tall grass, there's some random chance that we will trigger an encounter, a random encounter at which point, and it's just some number every time we take a step. So math. random calculation. Should we trigger an encounter? Well, then we have some states that again that we're going to want to push onto the stack and then render and then start to transition. So, let's go ahead and look at the player walk state is where we're in particular going to want to look at. And the player again, it inherits some entity behavior. So, if we look at entity walk state for example, there's left, right, up, down movement. We're going to have a 2x and a 2 y we're going to try to move to. It's going to get calculated based on the pixel size times our actual x and y uh the tile size times the x and y minus one. So that we know pixel wise where we

### Segment 14 (65:00 - 70:00) [1:05:00]

want to move to. We're going to transition there. And then if we are here pressing left, right, up or down at the time that this finishes this sort of tween of our X and Y, which is where that smooth grid based movement takes place. Notice that we then detect if we're still pressing a key and then we can smoothly move around. If we're not, we'll just change state to idle, which is totally fine. But this isn't where we actually detect for encounters. That's going to be in the because all entities, there might be NPCs that walk around. We don't want NPCs to do that. Um, even though right now we're we have all of the input detected inside entity walk state. The player walk state is where we're going to actually take the actual logic for, okay, are we triggering an encounter? Should we transition to the battle state, which is where the encounter begins? And so we're going to do the same attempt move as we do an entity where we actually do the tween operation except if we're the player we're going to at the time that we enter the walk state which will recall be anytime we transition from as the same logic that we've used in prior lectures if we transition from idle to walking in the same way that we did in Mario and Zelda and so forth. Right at the beginning we're going to run this function check for encounter. And so what that's going to do is essentially determine where we are on the X and a Y. And then we're going to see is there at the actual grass layer a tall grass ID in that that's the second layer. There's the base layer and the grass layer. Is there an actual grass ID there at that XY that we're trying to move to? And then is there a one in we'll do a 1 in 10 chance. Did we get chance being equal to one? And if we did, that's our 10% chance to trigger an encounter every footstep. We'll then set our entity to idle, change the music, and then here's the same code that we saw before. We're just going to push this new fade in state to white. We're going to then once that's finished, do the battle state and a fade out state. So all the same code that we did to transition from the start state to the play state, only here we're doing a battle state. We're not pushing two states before the fade. We're just passing in the battle state and the entity. And so that brings us to okay, well, what does the battle state look like? So if we open up battle state here, and so some of this will skim over because some of it is relatively repetitive, but just at a high level, we have an opponent that we're going to be facing. Now, this in the actual game, Pokemon might be a single Pokemon where you're just fighting one wild Pokemon in the grass, but there are also trainers that you can come across, other Pokemon trainers. you yourself are a trainer, a Pokemon trainer in the game, you have up to six Pokemon on your person at any one time. Part of the problem set will be implementing that feature. But you can also come across other people, other not real people, although you can fight with real people through certain mechanisms. But in the actual game itself, as you're walking from place to place, you will come across you will cross the gaze of the line of sight of another Pokémon trainer perhaps out in the wild. They will challenge you to a duel. they will themselves have one to six Pokemon and you will see who can knock out all of the other players entities or characters uh Pokemon. And so that's what we're essentially modeling here. We have an opponent, they have a party. In this case, we're just modeling an opponent that has one Pokemon and we don't have an actual opponent as a trainer as a separate creature or character that gets modeled. That could be something you very well could do should you choose to. For simplicity, we have a single opponent who's got a party of just one Pokemon, which takes a constructor. It's going to get a random deaf from that deaf file that we saw before. And then it's going to make it be between level two and six. It's going to do some math. It's going to figure out, okay, this should be have these stats based on its level, based on its IVs that we saw before. And then now we're ready to fight it. We create two battle sprites, those being images that come in from left to right, and we'll reflect what our Pokémon look like as they're fighting each other. And the things that will actually blink, recall that one would blink, one would turn sort of flash white when we when it triggers an attack. One will blink opaque and not opaque to signal that it got hit. And those are what we do for that. We have progress bars being used here. We have a progress bar with a width and a height in particular locations so that it can be rendered as the sort of trainer's progress bar for its health versus our progress bar for our health and our XP. So notice that we have the players bar being rendered at a particular height and width and a particular X and Y close to the bottom of the screen. The actual progress bar of the opponent is going to be at the top left. This is common. This is standard for the game itself. It takes in different a particular color. Again, we saw all of this before. It takes a value and a max. And notice that these values are not hard-coded anymore. These are actually based on whatever the current HP is of whatever the Pokemon is. In this case, hardcoded to one, but this could be for whatever current index of Pokemon in the party of the player or the opponent. In this case, both are

### Segment 15 (70:00 - 75:00) [1:10:00]

only going to have one Pokemon. Part of the problem set will be able to catch and have a higher number of Pokemon in your party. You're going to want to be able to take that into consideration. The value is going to be whatever the current HP is, which can decrease. The max or the regular HP, the actual max HP will always be static, which is why we set it to max here. And then notice the same thing here for the XP bar. We do the same thing only we're using XP to level for max and current XP which is an actual changing value that accumulates here for the actual value. And so we have various other flags and whatnot that can trigger whether the progress bars should render depending on whether the creatures have slide slid in all the way. And then we have just all the same rendering code that we saw previously here. again trigger slide in we actually are going to slide in the characters trigger starting dialogue is what's going to actually trigger that like go x Pokemon do all these things sort of giving a highle view here because most of this is relatively the same and relatively just large this is kind of a byproduct of guey based callback based programming you get code that's not all that complicated or sophisticated when you know how the pieces work but it does get quite large 150 lines here because we've got so many things happening we've got all these gooey elements ments that all have values that need to get set. We've got all these messages that have to go onto the screen. We've got all these things that have to animate. It's timer tween. It's the state machine, the state stack pushing things, progress bars and menus and panels. But ultimately, it's quite simple at the end of the day. It's really just a set of UI elements and sort of behavior that we expect to run. So the very end here, the last part that allows us to get out of the battle state and move on to the battle menu state, which is where we can actually derive some of our core behavior, is we pass a battle message state, which says a wild X appeared, which you might want to conditionally change to if you're fighting a trainer. We then at its call back, recall this will function after we finish with the battle message state, we're going to push another battle message state, which then says go X. And then we're going to finally ultimately push after we press enter and close out this battle message state another last state which is the next core functionality based state. No longer doing just visual things the battle menu state which is going to be able to have a reference to the current actual battle state so that we know what the opponent is and we can keep track of what the values are between us and the opponent. We keep a reference to it in the battle state and it will stay there until we pop the battle state. So, we have a reference to either we have and we can therefore uh do various things that affect the currently held player and opponent. But let's open up battle menu real quick. And then notice that the battle menu is the exact same thing as we saw with the selection only now it's called menu. It's essentially just a selection on top of a panel. But it is the exact same thing as we saw with selection where you have an XY width and height. Sure, as is normal for all of these elements, but then you have an items that takes in again text and then these on select callback functions. And this is where the core sort of being able to affect the game takes place. This is where the actual gameplay occurs. Albeit simplistically, ultimately you're just making one of two choices. And but it gets more complicated in the actual game itself where you have multiple moves. They all have different types. save different numbers of times with these this stat called PP for each of them uh for power points that you can allow yourself to actually cast a certain use a certain move maybe 5 10 20 times before you have to go heal your Pokemon again so on and so forth we're just essentially modeling one fight where they just fight each other with their attack and defense stats and their speed affecting which goes first and then run which also is in Pokemon which again in the actual game might be random if you come across some really aggressive really dangerous Pokemon. Maybe you can't run and you're sort of out of luck and maybe you should not go to that place because you risk sort of uh having all your Pokemon faint. Pokemon don't die in Pokemon. They faint and then that you wake up sort of at the nearest Pokemon center where you can heal up all your Pokemon. A lot of information about the game itself to sort of I guess set the stage. Um but a lot of some of these ideas are going to be part of the problem set. Some of them are going to be mentioned later and are, you know, games like this, RPGs in general tend to be very complicated. They have a lot of pieces. But with this foundation, you could certainly run with it and do all sorts of things here. But notice if we were to select the fight option, we're going to pop this actual menu state and then we're going to push a take turn state which takes in the battle state so that it has a reference to the opponent and the player. And so therefore, this is how we transition to whatever this next state is. Every sort of change in behavior can be modeled by a state effectively. If we run, we'll play a sound. We'll pop the menu again. And then we're going to pop them. We're going to push a message. We pass this flag false that we can't actually close it with any input. This is an input disabling flag. Folks can look at the battle message state to see that after. 5 seconds, we're then going to and notice

### Segment 16 (75:00 - 80:00) [1:15:00]

also we're using timer all over the place. This is kind of a great point where we can see so many ideas that we've talked about come together to provide this very interactive experience. But we're going to then do another fade to white here. The call back that's going to occur is going to take us back to the field. We're going to resume the field music. We're going to pop the message and then the battle state which are still on the stack. Again, stack management very important when you're dealing with a state stack versus a state machine. You kind of have to keep this keep aware of what is currently possibly pushed onto the stack or what is uh if you guarantee a particular flow that is one single flow, just keep track of what they are. And then we're going to do a fade out state. Ultimately, this is going to take us back to the field state that we left off on previously. The core just ultimately of what we want to look at and the last sort of big piece of Pokemon that we want to take a look at and is core to the problem set is going to be that take turn state. So take turn state is probably the more complicated part of all of these different states that we're looking at, particularly in the battle state. But we'll notice if we come up to the very top that the first thing we want to do is effectively keep track of whoever should be the attacker and the defender in any sort of attack. And this is determined in our implementation via a speed stat. So whoever is faster is the attacker versus the defender or rather they are the first both of them will exchange blows but one of them will go first the other will go second. And so we determine this by comparing their speed. And then we're going to set a pointer to first and second Pokemon. And then that's going to allow us to simplify how we call code later because when we call enter, notice that we call this function called attack. So attack will trigger. This is going to be the instantiator or the initializer will run, then enter will run. And then so selfatt attack is this function that takes in an attacker and a defender or rather a first and a second Pokemon and then the sprites for them as well and then their their progress bars. And so what's going to happen is it's going to remove sort of the message that got pushed onto the stack about who XY attacked. So actually let's take a look at attack so we can see what happens there exactly. When we call attack, attack is going to perform one of the two attacks. So two attacks need to occur. Pokemon A and then Pokemon B. A being the faster, B being the slower. It could be either the opponent or the player, vice versa. The attack means A will attack B. It will tri it will flash, trigger a hit. That hit will cause some flickering. Their HP will get subtracted. It will tween to that value. That's the end of an attack. But we want to do two attacks. We want to do AS B and then B will attack A. This is how Pokémon works. This isn't necessarily how all RPGs work, but in Pokemon, both entities trade blows at the same time. And so, we're going to trigger attack once, and then it a second time. But in the one invocation, or in each invocation of attack, we're going to push a message state first that says, "Okay, X Pokemon attacked Y Pokemon. " Then after. 5 seconds, we're going to sort of play like a little powerup sound, which is going to be like the flashing white. So whichever one's attacking is going to flash white, hit the other Pokemon, and it's going to set this sort of like blinking flag on that sprite every 0. 1 seconds for six times, limited to six times. This is a new method on the timer class, which we haven't looked at, which timer. Normally is just infinite, but you can set it to be capped to a certain number of invocations. in this case six times which will result in the thing flickering or seeming to flicker three times. It'll go from normal to the flickering state to normal to flickering and back. So that'll result in six uh invocations and therefore three flashes and then limit can then be paired with finish. So after six invocations of timer every of that callback function, we will then do a same operation on the whatever other opponent got hit. but now with their opacity. So we'll set their opacity equal to either 64 over 255, so close to zero or one, which will have the result of them sort of phasing in and out six times. And then their damage will be figured out whatever the attacker's attack minus the defense. So whatever the difference is of that, should it go negative, should it go zero, we're going to make sure that it's at least one with math. mmax. And then finally we're going to call at the very end here this on end function which will tell whatever the calling code was that we did finish our take not our take turn state rather we finished this attack this first attack. And so if we come back to take turn state attack notice that we do have on end being this sort of last parameter here. If we come up here to where we

### Segment 17 (80:00 - 85:00) [1:20:00]

called it here we'll see self. attack does all of these. It has all these parameters here and then this function is the last parameter. This is the onend function. So this is another way that we can sort of pass in a call back that gets triggered once something finishes. In this case, once attack finishes, we want there to be some operation that occurs. For the first attack, we want the second attack to take place. For the second attack, we want some sort of like resolving thing to happen or to go back to the battle menu. So, what we're going to do is we're going to pop whatever the message is on the stack, which was the sort of X attacks Y message we saw before. We're then going to see, okay, were there any deaths? Did either of them? And technically, Pokemon don't die, which I just said, but we're calling it check deaths or check for fainting. We're going to see is that true? Okay, well, what is check deaths look like? Check deaths down here is just going to see, okay, is the player Pokémon's HP less than or equal to zero? If so, then we have fainted. we need to sort of perform whatever logic that is, which is to usually in the game you would respawn at the Pokemon center and it's not as good of a thing. It's not you don't get a victory or anything like that. In Pokemon, you get a victory song if you were to win defeat the enemy Pokémon. And so we want to call a function called self victory if our H if it's the opponent's Pokemon is less than or equal to zero. Otherwise we call faint on oursel and then either of these will return true else we'll return false so that we can tell our calling code which of the two branches we ended up or which of whether we actually took one of these branches or whether we didn't and then therefore we should go back to the battle menu state. If we come up here back to attack which is what we were just looking at. Notice that we are going to sorry this is attack. We're going to look again at the enter state of take turn, which we did the one attack. We're going to check deaths. If it's true, meaning that we either fainted or there was a victory, we're going to pop whatever the current state is on the stack. And then we're going to call uh we're going to return because now both of them are done. We don't want the battle menu on the stack. We want to instead just have a essentially whatever the faint or the victory logic is going to be, it's going to take care of that for us. It's going to if we're going to faint, which we'll take a look at, it's going to fade to black. If it's a victory, we don't want to fade to black. We want the opponent's sprite to essentially fall off the screen and then say start the victory song and say, "Oh, you gained XP. " Then trigger some XP to go along on the bar. So, uh, but otherwise, that's if it that if that happens after attack A, then we'll do that. But then we still do need to do attack B before that even can occur necessarily if assuming both are still alive. And so what we're going to do is remove the message here and essentially do the exact same thing. Check deaths on the opposite hit, the opposite attack. And then should we still be in a state where we are not fainted or in a victory, then we want to pass or we want to remove the attack state off the stack, which we're currently in, and then push back onto the state the battle menu state. So, we go back to this loop of like, okay, now we can choose to attack again or we can run if it doesn't look like the battle is in our favor. So, let's take a look lastly down here at faint. So, faint is essentially just our sprite goes down below the bottom of the screen, we fade to black, we go back to the field state. So, that's what we do here. Our sprite goes down to the bottom of the screen. Once it's finished, battle message state, you faint it. And then we push a fade in state to black, RGB zero. And then we're going to heal our Pokemon back up to full health, change the music, and then a fade out state and a dialogue state. A dialogue state we're pushing so that when we go back to the field, we have this, oh, you passed out, but your Pokemon has been fully restored. Should we have a victory instead? And this part is relevant for the problem set because part of the problem set is going to be add an actual victory menu to show you where your stats increased if you were to level up during a victory. We want to bring the opponent sprite down and instead we're going to start the victory music, a battle message state that says victory. After which we want to once we press enter, we're going to calculate what our XP is. We're just going to sum all the IVs of the opponent and multiply it by their level, which is going to give us some XP value that is a scaled measure of that Pokemon's overall like power and its level as well. There's a ton of different ways you could look at doing XP modeling and XP curves are a very important thing for balance. We're doing something relatively naive, but it works fairly well in that it does ultimately represent a scaled sort of approach to uh XP based on your opponent's skill or your opponent's uh strength. But we're going to pass another battle message onto the stack. And then after 1. 5 seconds, we're going to render the XP itself tweening in the progress bar below our health as we sort of alluded to previously. And that's what we're

### Segment 18 (85:00 - 90:00) [1:25:00]

doing here. We're essentially just going to make sure to sort of put it at the very end of the XP bar and no further using math. min so it doesn't exceed the bounds of our XP bar. And then we're going to pop that message off, actually set it on our Pokemon, which is important. And then should it exceed the sort of XP cap, the max level cap for our Pokemon, we're going to then trigger a sound effect and then call this function called level up, which is going to effect effectively just do some math on its IVs, improve all of its stats, at which point you can then pass a battle message state says congratulations, you leveled up, fade out to white, which is just a utility function that we wrote here, which does the fade in to white and then fade back out to opaque. So, we go back to whatever our previous state was, presumably our play state. And that's overall the gist behind how the Pokemon turn-based system works. And there's a lot more that we could certainly do with it, but that overall represents the core underlying most turn-based systems, most RPG loops, and it would be up to you to potentially change some of those behaviors. So, some of the missing features that we talked about, you know, detailed level up screen, that's essentially part of the problem set. Monster catching is a huge part of the problem set uh as well. That is a huge part of the game itself, which is that, you know, you have one Pokémon, but you got to catch them all is the phrase, and there were 150 to start with, and I think there's now like 800 or something of them in the newest iteration. So, it's a lot harder these days to catch all of them. But, this is going to be part of the problem set. You notice that there were multiple different kinds of Pokémon. There's I think five or six in the example. And so by going through the wild grass and just like letting the random number generator do its thing, actually implement the ability to catch some wild Pokémon, part of the problem set, which we'll see in the next slide. So right now, field menu for browsing, that would be great to have. We don't really have a way to see what our Pokémon are, what they look like. What about items? You know, in RPGs, it's very common that you would have maybe potions or some other item. Pokeballs are the things that you use to actually throw at Pokemon to catch them. And that's kind of an important detail needed for catching Pokemon if you want to make it a sort of limited resource-based thing or constrained thing and not just be able to unlimited catch them for free. We didn't have anything beyond just attacking with sheer attack versus defense, but different attacks, different abilities, different ways to manipulate the state of the actual battle itself with different weather effects and various things like that. Pokemon gets very complicated the more you do and RPGs in general, but trainers as we mentioned, monster evolution, which we've mentioned, being able to evolve. Uh, we don't have anything really like towns or routes, which are common in Pokémon in our example, but we did talk a little bit about, for example, Zelda based dungeon generation. You could seek to implement something similar for yourself in a world, an overworld, or you could by hand create an actual fully fleshed out world with routes and with blocked off areas and the like. And then in the uh starting in gold and silver, you could actually take two Pokemon and breed Pokemon and get eggs that you could then cultivate and then raise and then grow Pokemon and get certain kinds that were only available during that. And then something like a day night cycle. During the daytime, certain Pokemon come out. During the night time, certain Pokemon come out and you tie it to your physical device. I remember that as a kid in Gold and Silver. That was one of my favorite features that they had added. And so for assignment seven, some of those ideas will utilize to provide a I think cool and robust problem set for folks to take on. When you level up, display a menu with all of your stat increases so that you don't know just that you leveled up, but like, oh, now I'm two points more attack, I've got two points more defense, or whatever. Uh when you're in the field, if you could press a key to open up a menu and actually see what are the Pokemon that I have in my inventory and how much HP do they have, what are their stats, what level are they? And then have a ability to catch them as well, which ties into that second point, which is to have some sort of third menu option in the game perhaps, or the ability to have an item that lets you do it. But certainly just for the problem set, have a catch Pokemon option. Should you get the Pokemon to be 25% HP or less, then that's typically I mean there's different Pokemon have different attributes. Some are just legendary and impossible to catch almost at any amount of HP, but typically the weaker the Pokemon is that you fight, assuming it's not a trainer. You can't catch trainers Pokemon, but assuming it's wild, you can throw the Pokeball at it at 25% or less. It'll catch it potentially, hopefully, if you're lucky. And then lastly, make sure that you can only catch six and that they're part of your party. It's common in Pokemon that you can only catch six Pokémon. That's the max size that you and all trainers can have. And so that'll be the requirement for the problem set. And so that ultimately concludes CS52D. We ran the gamut of games and genres throughout history, starting with more humble beginnings like Pong and the like through more modern titles, even mobile games. And we've learned the principles of 2D game development such that you could go and develop any of your own types of 2D games and certainly begin to take your steps even into the world of 3D game development. This was CS50 2D.
