1 00:00:00,000 --> 00:00:00,500 2 00:00:00,500 --> 00:00:04,374 [MUSIC PLAYING] 3 00:00:04,374 --> 00:00:16,540 4 00:00:16,540 --> 00:00:19,690 COLTON OGDEN: All right, welcome to GD50, Lecture 5. 5 00:00:19,690 --> 00:00:23,320 Today's topic is The Legend of Zelda, as you can see on the screen there. 6 00:00:23,320 --> 00:00:25,030 A very iconic game. 7 00:00:25,030 --> 00:00:28,660 Last week we did Super Mario Bros, which is arguably the most iconic video game 8 00:00:28,660 --> 00:00:29,200 of all time. 9 00:00:29,200 --> 00:00:31,162 Legend of Zelda is a close contender. 10 00:00:31,162 --> 00:00:34,120 Even now, just like with Mario, they're producing very wonderful games. 11 00:00:34,120 --> 00:00:39,250 I think last year Breath of the Wild took all the, I forget which 12 00:00:39,250 --> 00:00:41,830 ceremony it was, or award sort of show. 13 00:00:41,830 --> 00:00:44,470 But it took like every award possible. 14 00:00:44,470 --> 00:00:46,960 Just last year, the latest Zelda, the Breath of the Wild. 15 00:00:46,960 --> 00:00:50,650 So it feels sort of apropos to talk about Legend of Zelda in that context 16 00:00:50,650 --> 00:00:51,724 as well. 17 00:00:51,724 --> 00:00:53,890 Here's a screenshot of the original Legend of Zelda. 18 00:00:53,890 --> 00:00:57,386 It was an NES title, just like Super Mario Bros-- 19 00:00:57,386 --> 00:00:59,260 just like most games of its time, tile based. 20 00:00:59,260 --> 00:01:04,269 You can sort of see how the surroundings are sort of layered tiles bit by bit. 21 00:01:04,269 --> 00:01:08,470 The goal of the game overall was to sort of explore this open world, which 22 00:01:08,470 --> 00:01:11,112 is kind of a first of its kind. 23 00:01:11,112 --> 00:01:13,650 You controlled Link, shown at the very bottom there. 24 00:01:13,650 --> 00:01:16,360 You had a sword, yo had bombs, you had arrows. 25 00:01:16,360 --> 00:01:19,030 You want to go find rubies, you went through dungeons. 26 00:01:19,030 --> 00:01:22,120 You slayed monsters and bosses, and then ultimately the goal 27 00:01:22,120 --> 00:01:25,930 was to obtain the Triforce which is shown at the very top left and right 28 00:01:25,930 --> 00:01:27,690 of the slide here. 29 00:01:27,690 --> 00:01:30,190 Here's a screenshot, another screen shot of Legend of Zelda, 30 00:01:30,190 --> 00:01:32,770 inside an actual dungeon where you can see at the very top, 31 00:01:32,770 --> 00:01:34,420 there's got like a map layout. 32 00:01:34,420 --> 00:01:36,340 Maps are sort of arranged in a grid. 33 00:01:36,340 --> 00:01:40,960 And you could go in a room by room, whereby each room was the entire width 34 00:01:40,960 --> 00:01:45,160 and height of the screen, looking for, solving puzzles, looking for items, 35 00:01:45,160 --> 00:01:46,390 that sort of thing. 36 00:01:46,390 --> 00:01:47,890 You can see there's a monster there. 37 00:01:47,890 --> 00:01:49,473 You have hearts at the very top right. 38 00:01:49,473 --> 00:01:51,880 So when you take damage, hearts sort of decrement. 39 00:01:51,880 --> 00:01:55,990 Will see both of these, the hearts and the dungeon aspect of the game, 40 00:01:55,990 --> 00:02:00,460 today in lecture, as well as the width and height of the room 41 00:02:00,460 --> 00:02:01,630 being a dungeon tile. 42 00:02:01,630 --> 00:02:02,789 And controlling an avatar. 43 00:02:02,789 --> 00:02:05,080 But this is sort of a representative screenshot of what 44 00:02:05,080 --> 00:02:07,515 the game looked like back in the day. 45 00:02:07,515 --> 00:02:09,639 Some topics today that we'll be discussing in order 46 00:02:09,639 --> 00:02:12,760 to implement sort of the foundation for what a game engine like this 47 00:02:12,760 --> 00:02:15,500 might look like are things like top down perspective. 48 00:02:15,500 --> 00:02:17,410 So as you can see, in this screenshot, we're 49 00:02:17,410 --> 00:02:20,650 looking at Link from the very top in a bird's eye view, as opposed 50 00:02:20,650 --> 00:02:24,880 to how we used to look at Mario, from the side, where 51 00:02:24,880 --> 00:02:28,360 it was sort of like a side scroller. 52 00:02:28,360 --> 00:02:31,040 Here we're actually looking at things from the top down. 53 00:02:31,040 --> 00:02:36,850 So we have a view of the room in a sort of a different perspective. 54 00:02:36,850 --> 00:02:39,155 There's not really a z axis, technically speaking. 55 00:02:39,155 --> 00:02:40,030 But there sort of is. 56 00:02:40,030 --> 00:02:42,970 You can implement things like gravity in a game engine like this 57 00:02:42,970 --> 00:02:44,992 by jumping over holes and things like that. 58 00:02:44,992 --> 00:02:47,200 But there's no gravity like there was in Super Mario, 59 00:02:47,200 --> 00:02:49,390 where you walk left to right, you jump over gaps, 60 00:02:49,390 --> 00:02:51,950 and it's very easy to see in that sense. 61 00:02:51,950 --> 00:02:54,860 We'll be talking about infinite dungeon generation. 62 00:02:54,860 --> 00:02:57,700 So in the context of today's example, we'll 63 00:02:57,700 --> 00:03:00,985 see how we can go about implementing a dungeon that sort of you 64 00:03:00,985 --> 00:03:03,901 can go through forever and ever, and how to sort of model that 65 00:03:03,901 --> 00:03:07,150 and make it look as if you're traveling through a dungeon over and over again. 66 00:03:07,150 --> 00:03:10,400 And going through different screens in different rooms that are all different. 67 00:03:10,400 --> 00:03:13,210 But in reality, we'll see it's actually just an illusion like we've 68 00:03:13,210 --> 00:03:15,280 seen before in prior lectures. 69 00:03:15,280 --> 00:03:17,470 Well talk about hitboxes and hurtboxes, and what 70 00:03:17,470 --> 00:03:18,960 the difference is between the two. 71 00:03:18,960 --> 00:03:22,660 Hitboxes being rectangles on the screen that inflict damage 72 00:03:22,660 --> 00:03:25,630 upon other entities in your game world, and hurtboxes 73 00:03:25,630 --> 00:03:29,020 sort of being the rectangle that models where your player, 74 00:03:29,020 --> 00:03:33,750 or where an entity in the game can be hurt by other hit boxes. 75 00:03:33,750 --> 00:03:34,820 Well look at events. 76 00:03:34,820 --> 00:03:39,610 So events are a way of broadcasting some key message that tells 77 00:03:39,610 --> 00:03:41,650 the game world oh this thing happened. 78 00:03:41,650 --> 00:03:46,610 And let me register a function to call when that event is processed. 79 00:03:46,610 --> 00:03:50,170 So on some event, dispatch an event, and then 80 00:03:50,170 --> 00:03:53,210 upon that event being received by whatever is listening for it, 81 00:03:53,210 --> 00:03:54,400 perform this chunk of code. 82 00:03:54,400 --> 00:03:56,740 It allows you to sort of decouple aspects of your game 83 00:03:56,740 --> 00:03:59,710 engine a little bit, and makes for a little bit more readable code. 84 00:03:59,710 --> 00:04:02,334 And allows you to do some interesting things with achievements, 85 00:04:02,334 --> 00:04:05,740 for example, where you don't necessarily want to pull every single frame. 86 00:04:05,740 --> 00:04:09,250 Oh, did I do this sort of arbitrary list of things this frame? 87 00:04:09,250 --> 00:04:12,070 Rather, you can just process all of that with an event, 88 00:04:12,070 --> 00:04:16,990 and have a listener and a function that every time you broadcast pick up coin, 89 00:04:16,990 --> 00:04:19,839 maybe I have an achievement that's like oh, 90 00:04:19,839 --> 00:04:23,170 how I picked up 50 coins in this level. 91 00:04:23,170 --> 00:04:28,440 Your achievement callback function in your event can then look for that, 92 00:04:28,440 --> 00:04:31,130 and in your game loop, you don't have to say every frame, 93 00:04:31,130 --> 00:04:34,690 if a player has 850 coins, and you sort of 94 00:04:34,690 --> 00:04:39,010 take out bloat that would exist in your sort of overall game loop that way. 95 00:04:39,010 --> 00:04:41,979 And we'll see an example of how we use that in today's lecture. 96 00:04:41,979 --> 00:04:43,270 We'll look at screen scrolling. 97 00:04:43,270 --> 00:04:47,230 So a very iconic aspect of Legend of Zelda 98 00:04:47,230 --> 00:04:49,720 is when you're going from one screen to another, 99 00:04:49,720 --> 00:04:53,500 there is a sort of transition period as one screen loads and the other screen 100 00:04:53,500 --> 00:04:54,730 goes away. 101 00:04:54,730 --> 00:04:59,620 In hardware, in the NES, this was sort of the only way 102 00:04:59,620 --> 00:05:04,840 you could actually render more than a screen width of tiles. 103 00:05:04,840 --> 00:05:07,180 You actually had to dynamically load in tiles and sort 104 00:05:07,180 --> 00:05:09,790 of overwrite tiles that existed before that in memory. 105 00:05:09,790 --> 00:05:12,220 But today, we'll see how we can sort of create 106 00:05:12,220 --> 00:05:15,340 the illusion of doing that by just drawing a room 107 00:05:15,340 --> 00:05:18,240 and then having our main room, and then just sort of tweening over, 108 00:05:18,240 --> 00:05:21,360 and then setting everything back to the origin at 0.0. 109 00:05:21,360 --> 00:05:24,120 And it makes it look as if we're moving back and forth between all 110 00:05:24,120 --> 00:05:26,911 these rooms, when in reality all we're doing is just doing a shift, 111 00:05:26,911 --> 00:05:28,680 and then putting everything back to 0.0. 112 00:05:28,680 --> 00:05:32,655 So I'll illustrate that on the screen, if I can. 113 00:05:32,655 --> 00:05:35,280 And one of the last things we'll look at is data driven design. 114 00:05:35,280 --> 00:05:39,240 In the context of a lot of types of games, particularly RPGs and action 115 00:05:39,240 --> 00:05:44,010 games, it's often very valuable to be able to model all of your items, 116 00:05:44,010 --> 00:05:46,440 entities, sort of abilities, anything you really 117 00:05:46,440 --> 00:05:51,780 can, as data rather than logic, in order to make it easier for you to write one. 118 00:05:51,780 --> 00:05:55,530 And two, for you to sort of allocate the design aspect of your game 119 00:05:55,530 --> 00:05:57,630 to other people, not just programmers. 120 00:05:57,630 --> 00:05:59,670 And have an engine that's very versatile. 121 00:05:59,670 --> 00:06:02,370 And model and we'll take a look at how we implement 122 00:06:02,370 --> 00:06:05,410 sort of a foundation for that later on. 123 00:06:05,410 --> 00:06:09,540 But first I'd like to illustrate a demo for today's lecture, 124 00:06:09,540 --> 00:06:11,982 a sort of implementation of Legend of Zelda. 125 00:06:11,982 --> 00:06:14,940 Is there anybody that would like to come up and sort of demo this today 126 00:06:14,940 --> 00:06:15,480 in class? 127 00:06:15,480 --> 00:06:19,232 128 00:06:19,232 --> 00:06:21,580 Awesome. 129 00:06:21,580 --> 00:06:24,460 Thank you so much. 130 00:06:24,460 --> 00:06:29,274 So whenever you're ready, go ahead and press the Return key there. 131 00:06:29,274 --> 00:06:30,770 [MUSIC PLAYING] 132 00:06:30,770 --> 00:06:34,560 And so we see on the screen, Legend of 50, which is our Legend of Zelda 133 00:06:34,560 --> 00:06:35,370 you rip off. 134 00:06:35,370 --> 00:06:36,720 So you press Enter. 135 00:06:36,720 --> 00:06:39,000 You go into, this is the play state of the game. 136 00:06:39,000 --> 00:06:40,880 So you control an avatar. 137 00:06:40,880 --> 00:06:42,040 You can walk around. 138 00:06:42,040 --> 00:06:44,520 He can interact with switches, as we saw here. 139 00:06:44,520 --> 00:06:47,240 When he presses a switch, the doors open. 140 00:06:47,240 --> 00:06:51,000 And once the doors are open, you can walk through them 141 00:06:51,000 --> 00:06:54,720 and it does, as I alluded to before, it transitions the screen, one 142 00:06:54,720 --> 00:06:59,320 entire screen height or width, depending on the direction, up above and below. 143 00:06:59,320 --> 00:07:02,790 We see here now where we're pressing spacebar to actually swing our sword. 144 00:07:02,790 --> 00:07:05,830 It's destroying the entities in the game space. 145 00:07:05,830 --> 00:07:10,170 So there's a hitbox triggering when you press the space bar that collides 146 00:07:10,170 --> 00:07:11,940 with other entities in the game world. 147 00:07:11,940 --> 00:07:15,720 If that hitbox hits their hurtbox, then they are flagged as dead, 148 00:07:15,720 --> 00:07:17,890 and they disappear from the game world. 149 00:07:17,890 --> 00:07:19,510 And so this goes on ad infinitum. 150 00:07:19,510 --> 00:07:20,760 It's just an infinite dungeon. 151 00:07:20,760 --> 00:07:24,600 So he can go in-between as many floors as we want to. 152 00:07:24,600 --> 00:07:27,667 All we're doing is every time we go through a doorway, spawn a new room, 153 00:07:27,667 --> 00:07:30,500 delete the old one, and just keep going forever, and ever, and ever. 154 00:07:30,500 --> 00:07:33,333 In a game like Legend of Zelda, it typically doesn't work like this. 155 00:07:33,333 --> 00:07:38,220 There is a hard set number of rooms, and they all exist in sort of a 2D array. 156 00:07:38,220 --> 00:07:40,590 And when you generate your dungeon, you sort of 157 00:07:40,590 --> 00:07:43,460 have to take into consideration things like where do I put the keys? 158 00:07:43,460 --> 00:07:44,460 Where do I put the boss? 159 00:07:44,460 --> 00:07:45,590 Where do I put treasure? 160 00:07:45,590 --> 00:07:46,381 That sort of thing. 161 00:07:46,381 --> 00:07:51,000 We won't get too in-depth as to how we can implement a complex algorithm like. 162 00:07:51,000 --> 00:07:54,120 But we'll touch on it a little bit, and talk about maybe some ideas 163 00:07:54,120 --> 00:07:55,230 that we have. 164 00:07:55,230 --> 00:07:58,150 And then lastly, if we just-- if we want to demo-- 165 00:07:58,150 --> 00:08:00,540 if we can see the top left, we have hearts there, 166 00:08:00,540 --> 00:08:02,580 which is iconic sort of Zelda. 167 00:08:02,580 --> 00:08:05,810 When we do take damage from an enemy, notice that we flicker a little bit. 168 00:08:05,810 --> 00:08:07,800 So there's some rendering behavior triggering, 169 00:08:07,800 --> 00:08:09,759 and we become invulnerable when we take damage. 170 00:08:09,759 --> 00:08:11,883 And then lastly, when we finally take the last hit, 171 00:08:11,883 --> 00:08:14,190 we get a little game over screen, using the Zelda font. 172 00:08:14,190 --> 00:08:15,320 And that's the game in a nutshell. 173 00:08:15,320 --> 00:08:16,780 We press Enter and loop back. 174 00:08:16,780 --> 00:08:19,364 So pretty simple altogether, but there's a lot of pieces 175 00:08:19,364 --> 00:08:21,030 here that we haven't really seen before. 176 00:08:21,030 --> 00:08:24,910 So thank you very much for coming up to demo the game. 177 00:08:24,910 --> 00:08:25,410 All right. 178 00:08:25,410 --> 00:08:31,320 So that was a demo of Legend of 50, Legend of Zelda. 179 00:08:31,320 --> 00:08:33,419 It has a lot of the pieces that Zelda has. 180 00:08:33,419 --> 00:08:35,220 It's not as fully fleshed out, of course, 181 00:08:35,220 --> 00:08:38,368 as a full game like Zelda, which would be monstrously large. 182 00:08:38,368 --> 00:08:40,409 And there's a lot of things we need to factor in. 183 00:08:40,409 --> 00:08:42,210 But the foundation is there. 184 00:08:42,210 --> 00:08:46,290 We have the dungeon foundation upon which we can build an actual generator, 185 00:08:46,290 --> 00:08:47,370 if we wanted to. 186 00:08:47,370 --> 00:08:48,240 We have entities. 187 00:08:48,240 --> 00:08:49,140 We have hit boxes. 188 00:08:49,140 --> 00:08:51,970 We could easily model, because we have switches in the game, 189 00:08:51,970 --> 00:08:53,995 we could model things like treasure chests that 190 00:08:53,995 --> 00:08:57,120 open that have different states, just like the switch had different states. 191 00:08:57,120 --> 00:09:00,690 And have different objects in our game space interact with other objects. 192 00:09:00,690 --> 00:09:04,270 We have a lot here, and we'll talk about all of it today. 193 00:09:04,270 --> 00:09:07,440 So here's a few screenshots just to show what we just looked at. 194 00:09:07,440 --> 00:09:10,170 Our goal mainly is the second screen shot, 195 00:09:10,170 --> 00:09:12,690 on the top right, which is the play state, which has 196 00:09:12,690 --> 00:09:14,560 all of the little pieces we just saw. 197 00:09:14,560 --> 00:09:17,429 But just to tie it all together, we do have a start state here, 198 00:09:17,429 --> 00:09:19,470 and a Game Over state which is relevant in regard 199 00:09:19,470 --> 00:09:22,390 to the hearts on the top left. 200 00:09:22,390 --> 00:09:27,300 So the first thing that I'll talk about as we sort of get the engine built up 201 00:09:27,300 --> 00:09:30,970 is, where do we go for getting our assets into the game? 202 00:09:30,970 --> 00:09:33,960 And just like in prior lectures, prior to today, 203 00:09:33,960 --> 00:09:36,210 we just have a sprite sheet, like we did with Mario, 204 00:09:36,210 --> 00:09:40,560 where everything is laid out in a fairly even sequence of tile segments. 205 00:09:40,560 --> 00:09:43,710 In this case, the segments are 16 by 16 pixels. 206 00:09:43,710 --> 00:09:48,270 Here, I've overlaid a grid just to show that the picture is indeed perfectly 16 207 00:09:48,270 --> 00:09:48,930 by 16. 208 00:09:48,930 --> 00:09:51,790 And this is something that you should take into consideration. 209 00:09:51,790 --> 00:09:54,439 And consciously do when you're building your game assets. 210 00:09:54,439 --> 00:09:56,230 Make it easy to chop up into little pieces, 211 00:09:56,230 --> 00:10:01,800 so you can then index into this sprite via some table of quads. 212 00:10:01,800 --> 00:10:04,260 And then assign an ID to whatever object, 213 00:10:04,260 --> 00:10:07,410 or tile you want to render to the screen. 214 00:10:07,410 --> 00:10:11,130 And so we see if you look here, things like the doors, 215 00:10:11,130 --> 00:10:14,640 they're not perfectly modeled by one tile. 216 00:10:14,640 --> 00:10:18,270 And so when you do have things that are larger than 16 by 16, 217 00:10:18,270 --> 00:10:23,820 it's not quite as easy as oh have an entity or an object with this frame ID, 218 00:10:23,820 --> 00:10:25,110 and draw it to the screen. 219 00:10:25,110 --> 00:10:27,776 You actually need to a little bit more complicated render logic. 220 00:10:27,776 --> 00:10:30,150 So just offhand, if I wanted to draw a door, 221 00:10:30,150 --> 00:10:32,780 does anybody have any suggestions as to how I would model that? 222 00:10:32,780 --> 00:10:33,988 And or draw it to the screen? 223 00:10:33,988 --> 00:10:39,310 224 00:10:39,310 --> 00:10:49,870 So if we have a door that's not perfectly a 16 x 16 pixel tile, 225 00:10:49,870 --> 00:10:54,540 offhand, what we need to do is just basically store all four 226 00:10:54,540 --> 00:10:57,810 of those tiles in this case, or at least keep track of however many tiles 227 00:10:57,810 --> 00:11:01,260 your object is. 228 00:11:01,260 --> 00:11:03,290 And then just draw them based on some offset. 229 00:11:03,290 --> 00:11:06,940 Have an xy that represents the top left of that object. 230 00:11:06,940 --> 00:11:09,870 Place it in the right position, and instead of drawing just one tile, 231 00:11:09,870 --> 00:11:11,430 we draw four tiles. 232 00:11:11,430 --> 00:11:15,831 And then instead of having just one collision boss that's 16 by 16 tiles, 233 00:11:15,831 --> 00:11:17,080 you can do a couple of things. 234 00:11:17,080 --> 00:11:20,340 You can either check collision on all four of these tiles, 235 00:11:20,340 --> 00:11:24,180 or at least all two of these door tiles, or model your own custom hit 236 00:11:24,180 --> 00:11:28,230 box that then maybe that object that represents a doorway has control of. 237 00:11:28,230 --> 00:11:31,860 So you can say doorway collides player, and then the doorway 238 00:11:31,860 --> 00:11:37,890 has a height and width of however many pixels it is wide by tall here. 239 00:11:37,890 --> 00:11:39,030 Just this door part. 240 00:11:39,030 --> 00:11:44,310 And then, you are able to then build upon not just having one tile that 241 00:11:44,310 --> 00:11:46,710 models an object or entity in your game space, 242 00:11:46,710 --> 00:11:48,700 but now you have more artistic flexibility. 243 00:11:48,700 --> 00:11:52,710 You can do things like have doorways that are more than one pixel wide. 244 00:11:52,710 --> 00:11:55,699 And sort of have a more convincing gameworld as a result of that. 245 00:11:55,699 --> 00:11:57,990 You'll see a lot of things like that in games like RPGs 246 00:11:57,990 --> 00:12:02,880 where you have full houses that are obviously not just one tile. 247 00:12:02,880 --> 00:12:06,360 You can model things as one tile if you want to, 248 00:12:06,360 --> 00:12:10,540 but from an artistic perspective, and from just a game engine perspective, 249 00:12:10,540 --> 00:12:13,020 it's a little bit easier to programmatically 250 00:12:13,020 --> 00:12:18,190 be able to cut up all your assets into tiles and draw them as such. 251 00:12:18,190 --> 00:12:22,500 So being able to build upon just the single sprite 252 00:12:22,500 --> 00:12:24,930 and be able to do multiple sprites represent 253 00:12:24,930 --> 00:12:30,480 an object is the key to things like houses, things like big trees, 254 00:12:30,480 --> 00:12:34,710 things that are just more complicated than single tiles as we see here. 255 00:12:34,710 --> 00:12:39,160 The character sprite sheet is, as you can see, a little bit more complicated. 256 00:12:39,160 --> 00:12:42,000 So this is an example of a sprite sheet that has padding. 257 00:12:42,000 --> 00:12:45,630 Sometimes you will get sprite sheets that aren't neatly divided 258 00:12:45,630 --> 00:12:46,657 into even segments. 259 00:12:46,657 --> 00:12:47,490 And for good reason. 260 00:12:47,490 --> 00:12:50,850 Because sometimes you have tiles that are not perfectly 261 00:12:50,850 --> 00:12:53,850 the width and height of whatever your game engine's tiles are. 262 00:12:53,850 --> 00:12:57,692 In this case, the player is actually 20 pixels tall, and 16 pixels wide. 263 00:12:57,692 --> 00:13:00,150 And on top of that, he's got different frames of animation. 264 00:13:00,150 --> 00:13:03,330 We can see here at the bottom left, he's got a sword swinging animation. 265 00:13:03,330 --> 00:13:06,930 The sword swing animation is actually stored in a 32 by 32 pixel frame, 266 00:13:06,930 --> 00:13:10,590 because sometimes depending on which angle he's looking at, 267 00:13:10,590 --> 00:13:12,820 his sprite can get a little larger or smaller. 268 00:13:12,820 --> 00:13:16,350 So when you have a sprite with padding, what's sort of a way 269 00:13:16,350 --> 00:13:19,740 that we can draw this to the screen reliably? 270 00:13:19,740 --> 00:13:22,170 How do we take this into consideration? 271 00:13:22,170 --> 00:13:24,360 How would we render a screen sprite with padding? 272 00:13:24,360 --> 00:13:28,150 273 00:13:28,150 --> 00:13:32,560 So let's say this sprite here, our character swinging a sword, is in a 32 274 00:13:32,560 --> 00:13:34,670 by 32 pixel box. 275 00:13:34,670 --> 00:13:35,200 Right? 276 00:13:35,200 --> 00:13:37,810 This sort of box around here, this white space. 277 00:13:37,810 --> 00:13:40,810 But he's only still maybe 16 pixels wide by 20 pixels tall. 278 00:13:40,810 --> 00:13:43,994 Or maybe he is some amount similar to that. 279 00:13:43,994 --> 00:13:46,910 In order to draw him to the screen, which you can look at in the code, 280 00:13:46,910 --> 00:13:50,170 all we really need to do is assign that sprite an offset. 281 00:13:50,170 --> 00:13:52,315 Just say, OK, this sprite's offset x and offset 282 00:13:52,315 --> 00:13:57,670 y are some value that basically lets us draw the sprite 283 00:13:57,670 --> 00:14:00,940 to a negative x and a negative y value. 284 00:14:00,940 --> 00:14:03,910 And that'll shift the sprite up, such that it aligns perfectly 285 00:14:03,910 --> 00:14:05,650 with wherever his xy are. 286 00:14:05,650 --> 00:14:09,490 And you can take a look at the code to see exactly how that works. 287 00:14:09,490 --> 00:14:13,079 Lastly the actual entities for our game world are different creatures. 288 00:14:13,079 --> 00:14:16,120 And this is a sprite sheet-- this is a more ideal sprite where everything 289 00:14:16,120 --> 00:14:18,792 is 16 by 16 pixels wide and tall. 290 00:14:18,792 --> 00:14:21,250 And all we really did here was just divide the sprite sheet 291 00:14:21,250 --> 00:14:26,470 using the regular utility function generate quads by 16 16. 292 00:14:26,470 --> 00:14:30,640 We don't have to worry about separate widths and heights for everything, 293 00:14:30,640 --> 00:14:34,570 and we can create animations very simply because of this. 294 00:14:34,570 --> 00:14:38,260 As a side note, something that I like to do, when I'm parsing 295 00:14:38,260 --> 00:14:42,870 or when I'm piecing apart a sprite sheet that's got a lot of individual frames, 296 00:14:42,870 --> 00:14:45,130 particularly if I'm creating animations, or I just 297 00:14:45,130 --> 00:14:49,120 need to know for a tile, a particular tile to draw to the screen. 298 00:14:49,120 --> 00:14:52,311 It's kind of a pain to manually look through each and every tile, one 299 00:14:52,311 --> 00:14:52,810 by one. 300 00:14:52,810 --> 00:14:54,580 And say OK, this is one but OK. 301 00:14:54,580 --> 00:14:57,040 But if I want to find out which one the slime is, 302 00:14:57,040 --> 00:14:59,630 I got a count, OK how many pixels wide does this? 303 00:14:59,630 --> 00:15:02,330 OK, and then it's times 4, it's 12. 304 00:15:02,330 --> 00:15:07,030 And then it's on the fifth row, so 12 times 4 plus 1 will give me, OK. 305 00:15:07,030 --> 00:15:09,520 So it's at index 49. 306 00:15:09,520 --> 00:15:12,940 So I've spent a non-trivial amount of time sort of hand 307 00:15:12,940 --> 00:15:14,920 calculating what all these do. 308 00:15:14,920 --> 00:15:18,820 I wrote a simple Python script that will just go over a file, 309 00:15:18,820 --> 00:15:23,290 and just add a digit to each individual quad, 310 00:15:23,290 --> 00:15:26,650 to just show you at a glance what each sprite is. 311 00:15:26,650 --> 00:15:30,460 And this is including the distro, so you can see what it looks like. 312 00:15:30,460 --> 00:15:31,660 Saves a lot of time. 313 00:15:31,660 --> 00:15:34,840 And I recommend trying, when you're sort of working with assets 314 00:15:34,840 --> 00:15:37,484 and you find yourself doing something that takes a long time, 315 00:15:37,484 --> 00:15:39,400 and it's sort of tedious and mechanical, maybe 316 00:15:39,400 --> 00:15:41,691 try to find a way to sort of automate that, or at least 317 00:15:41,691 --> 00:15:43,420 make it easier to do things at a glance. 318 00:15:43,420 --> 00:15:47,187 In this case, just simply imposing a numerical grid solves that problem. 319 00:15:47,187 --> 00:15:49,270 I don't have to spend a significant amount of time 320 00:15:49,270 --> 00:15:52,930 figuring out which frames of animation the ghost facing left is. 321 00:15:52,930 --> 00:15:58,120 I know instantly it's 67, 68 and 69, and allows me to just crank things 322 00:15:58,120 --> 00:16:00,350 up that much faster. 323 00:16:00,350 --> 00:16:04,870 So the first thing we'll take a look at is sort of top down perspective. 324 00:16:04,870 --> 00:16:07,840 And we mostly talked about this before, earlier. 325 00:16:07,840 --> 00:16:12,500 But all it really is is a tile map, which we've seen before. 326 00:16:12,500 --> 00:16:16,120 The only difference is now, instead of looking at things from the side, 327 00:16:16,120 --> 00:16:18,290 we're just looking at things from up above. 328 00:16:18,290 --> 00:16:21,880 So what's probably the most obvious consideration 329 00:16:21,880 --> 00:16:27,460 when designing a top down perspective versus a sort of side scrolling 330 00:16:27,460 --> 00:16:29,860 point of view? 331 00:16:29,860 --> 00:16:32,620 Looking at particularly at how the tiles are drawn? 332 00:16:32,620 --> 00:16:33,696 What stands out? 333 00:16:33,696 --> 00:16:37,030 334 00:16:37,030 --> 00:16:39,250 So the thing that stands out to me is that we 335 00:16:39,250 --> 00:16:42,790 have things like shadows on walls here. 336 00:16:42,790 --> 00:16:46,960 We have also corners, and things altogether 337 00:16:46,960 --> 00:16:51,220 are skewed such that they are almost like rotated slightly as if they're 338 00:16:51,220 --> 00:16:56,890 simulating an angle of rotation relative to the camera facing from up above. 339 00:16:56,890 --> 00:16:58,970 You can see this on the player, for example. 340 00:16:58,970 --> 00:17:01,960 It looks like you're looking at him from backwards and up. 341 00:17:01,960 --> 00:17:07,150 When you're modeling your assets that way, it's more convincing. 342 00:17:07,150 --> 00:17:10,030 And Zelda has always done this, to make your assets look 343 00:17:10,030 --> 00:17:13,004 as if they are slightly tilted, and that you're looking up above. 344 00:17:13,004 --> 00:17:14,920 So when you're designing a top down game, just 345 00:17:14,920 --> 00:17:20,200 for convincing the sake of being more convincing, try and emulate that. 346 00:17:20,200 --> 00:17:23,650 The entities here, like the skeleton, and such, 347 00:17:23,650 --> 00:17:25,690 are a little bit more straight on. 348 00:17:25,690 --> 00:17:28,259 The bats and slimes and whatnot, even though they still 349 00:17:28,259 --> 00:17:29,800 have a little bit of that appearance. 350 00:17:29,800 --> 00:17:33,250 Like the spider it sort of looks as if it's from the top back. 351 00:17:33,250 --> 00:17:37,600 But modeling your assets from a top down perspective, mainly the thing. 352 00:17:37,600 --> 00:17:39,910 Pay attention to shadows and highlights, which 353 00:17:39,910 --> 00:17:43,930 adds a lot in terms of convincing us that we're in this room with lighting. 354 00:17:43,930 --> 00:17:48,850 And also make sure that you're doing things like corners and stuff 355 00:17:48,850 --> 00:17:54,490 and making, it look as if things are slightly skewed rotation wise. 356 00:17:54,490 --> 00:17:58,090 The first thing that we're going to look at in terms of the code in the distro 357 00:17:58,090 --> 00:18:00,170 is Dungeon Generation. 358 00:18:00,170 --> 00:18:05,180 So in Legend of Zelda, dungeons are fixed. 359 00:18:05,180 --> 00:18:08,500 They're completely set in advance by the designers. 360 00:18:08,500 --> 00:18:10,960 And in most games, this is actually the case. 361 00:18:10,960 --> 00:18:13,600 In our example, and in a couple of other examples, 362 00:18:13,600 --> 00:18:16,210 a primary example of them being that I can think of, 363 00:18:16,210 --> 00:18:19,750 that I have in the slides, a famous game called The Binding of Isaac, 364 00:18:19,750 --> 00:18:23,000 dungeons can also be generated. 365 00:18:23,000 --> 00:18:27,280 So what's the sort of like the main unit of a dungeon? 366 00:18:27,280 --> 00:18:29,080 At least in the context of Legend of Zelda? 367 00:18:29,080 --> 00:18:32,350 If you had to distill what comprises a dungeon, 368 00:18:32,350 --> 00:18:34,000 what's the most fundamental unit? 369 00:18:34,000 --> 00:18:36,811 370 00:18:36,811 --> 00:18:37,311 Tony. 371 00:18:37,311 --> 00:18:37,811 A room. 372 00:18:37,811 --> 00:18:38,500 Yes. 373 00:18:38,500 --> 00:18:39,680 A room. 374 00:18:39,680 --> 00:18:43,940 So we can almost look at this, if we picture it in terms of a 2D array, 375 00:18:43,940 --> 00:18:44,570 right? 376 00:18:44,570 --> 00:18:47,650 We have, assuming that this is like index 1.1 377 00:18:47,650 --> 00:18:52,580 in Lua, 0.0 in other languages, going left to right, top to bottom. 378 00:18:52,580 --> 00:18:56,100 Basically we have on or off, relative to each of these. 379 00:18:56,100 --> 00:18:59,030 Off, on, off, off, off. 380 00:18:59,030 --> 00:19:03,320 Each of the indexes in this 2D array holds a room. 381 00:19:03,320 --> 00:19:08,810 And so the room has connections implicitly between the other rooms. 382 00:19:08,810 --> 00:19:12,290 If you wanted to go, let's say, from this room here to the room 383 00:19:12,290 --> 00:19:16,670 up above it, what's the offset, in terms of the 2D array? 384 00:19:16,670 --> 00:19:18,860 How are we going from this room up to this room? 385 00:19:18,860 --> 00:19:23,420 386 00:19:23,420 --> 00:19:25,490 So we're just going up a y level, right? 387 00:19:25,490 --> 00:19:27,920 So this is x level 3, y level 3. 388 00:19:27,920 --> 00:19:31,636 If we wanted to go up to the next room, we need to load in. 389 00:19:31,636 --> 00:19:33,260 If we're doing it the Zelda way, right? 390 00:19:33,260 --> 00:19:34,310 And we're just going-- 391 00:19:34,310 --> 00:19:36,500 we're doing a transition between one room 392 00:19:36,500 --> 00:19:42,410 to another, what we need to do is load in the room at this room, 393 00:19:42,410 --> 00:19:45,809 minus one on the y, and then perform the transition. 394 00:19:45,809 --> 00:19:47,600 And then set that to the current room, such 395 00:19:47,600 --> 00:19:51,200 that now we know we're at y level 2, x level 3. 396 00:19:51,200 --> 00:19:52,220 That's our dungeon. 397 00:19:52,220 --> 00:19:56,810 In the context of 2D dungeons in The Legend of Zelda, 398 00:19:56,810 --> 00:19:58,430 that's as simple as it really is. 399 00:19:58,430 --> 00:20:00,980 You have a 2D grid of dungeon rooms. 400 00:20:00,980 --> 00:20:04,100 Each room has its own collection of entities and objects 401 00:20:04,100 --> 00:20:06,650 and connections to other rooms. 402 00:20:06,650 --> 00:20:12,020 But really, all you do to fill a dungeon is fill an array in a smart way 403 00:20:12,020 --> 00:20:15,372 such that there is no rooms that are, for example, left by themselves. 404 00:20:15,372 --> 00:20:18,080 Notice that every room in the dungeon has at least one connection 405 00:20:18,080 --> 00:20:21,110 to another room. 406 00:20:21,110 --> 00:20:23,690 And that when you're maybe doing your algorithm 407 00:20:23,690 --> 00:20:27,470 to create a convincing dungeon, let's say this room here has 408 00:20:27,470 --> 00:20:31,710 a door on the right, that has a lock. 409 00:20:31,710 --> 00:20:32,870 Right? 410 00:20:32,870 --> 00:20:36,312 We want to make sure that the key isn't in that room. 411 00:20:36,312 --> 00:20:38,020 Because if it is, we're never going to be 412 00:20:38,020 --> 00:20:41,010 able to get to it, assuming that we come from another direction. 413 00:20:41,010 --> 00:20:43,880 So when you're designing dungeons procedurally, 414 00:20:43,880 --> 00:20:46,350 you want to take these sort of things into consideration. 415 00:20:46,350 --> 00:20:47,850 And then for example, the boss room. 416 00:20:47,850 --> 00:20:49,880 Let's say this is the boss room, the boss room 417 00:20:49,880 --> 00:20:52,970 should have maybe a boss key, or something like that. 418 00:20:52,970 --> 00:20:57,300 But the boss key should not be, obviously, in that room. 419 00:20:57,300 --> 00:21:01,840 It should be somewhere maybe where there's a couple of rooms before it 420 00:21:01,840 --> 00:21:06,260 that have a lock or a key, so that you know there's some sort of challenge 421 00:21:06,260 --> 00:21:07,520 involved in your dungeon. 422 00:21:07,520 --> 00:21:11,460 It's not just random as we've done before. 423 00:21:11,460 --> 00:21:14,960 There has to be a little bit of sort of conscious design on behalf 424 00:21:14,960 --> 00:21:16,640 of your algorithms. 425 00:21:16,640 --> 00:21:19,370 Today we're doing things completely random 426 00:21:19,370 --> 00:21:22,760 for illustration, just because a system like this is fairly robust and complex. 427 00:21:22,760 --> 00:21:26,504 But with some effort, you could create a simple dungeon generator just using 428 00:21:26,504 --> 00:21:27,170 those mechanics. 429 00:21:27,170 --> 00:21:29,140 Just make sure that you have locked doors. 430 00:21:29,140 --> 00:21:31,265 The locked doors can only open when you have a key. 431 00:21:31,265 --> 00:21:33,800 Make sure the key exists in a place that's accessible, 432 00:21:33,800 --> 00:21:38,090 and sort of create a chain of a control flow. 433 00:21:38,090 --> 00:21:42,830 Model maybe via graph of some kind that represents your dungeon, 434 00:21:42,830 --> 00:21:45,950 and the progression thereof. 435 00:21:45,950 --> 00:21:48,600 So that's what a Zelda dungeon looks like. 436 00:21:48,600 --> 00:21:52,430 That's what a 2D dungeon in this sort of perspective looks like. 437 00:21:52,430 --> 00:21:55,490 And it looks-- it will look similar to this in other game engines. 438 00:21:55,490 --> 00:21:57,890 It doesn't necessarily have to be perfectly modeled 439 00:21:57,890 --> 00:22:01,860 as a screen width, screen height room going into another screen width, screen 440 00:22:01,860 --> 00:22:02,360 wide room. 441 00:22:02,360 --> 00:22:07,610 You can have arbitrarily complex rooms that have arbitrarily complex sizes 442 00:22:07,610 --> 00:22:10,590 and shapes. 443 00:22:10,590 --> 00:22:14,180 But you still need to make sure that the connections going out of the rooms, 444 00:22:14,180 --> 00:22:18,110 like if you can still model left, right, up, down, if you want to. 445 00:22:18,110 --> 00:22:21,140 You can model arbitrary numbers of connections between rooms. 446 00:22:21,140 --> 00:22:24,230 Just make sure that you have puzzles that can be solved. 447 00:22:24,230 --> 00:22:28,610 That's the main sort of obstacle in generating your dungeons. 448 00:22:28,610 --> 00:22:32,360 Here's a game that I really like that uses the old Legend of Zelda formula 449 00:22:32,360 --> 00:22:33,890 to very good effect now. 450 00:22:33,890 --> 00:22:35,300 It's called The Binding of Isaac. 451 00:22:35,300 --> 00:22:38,840 Notice already we can instantly see that it's top-down perspective. 452 00:22:38,840 --> 00:22:42,740 It's the entire width and height of the room is the dungeon of-- 453 00:22:42,740 --> 00:22:46,700 the entire width and height of the screen is the dungeon room. 454 00:22:46,700 --> 00:22:51,140 You have a map up here that shows you, OK, I'm in this room right here. 455 00:22:51,140 --> 00:22:52,850 I can go up, I can go left. 456 00:22:52,850 --> 00:22:54,590 I can go right, I can go down. 457 00:22:54,590 --> 00:22:56,680 This room up here with the yellow crown, that's 458 00:22:56,680 --> 00:22:58,880 going to be locked behind some door with a key. 459 00:22:58,880 --> 00:23:02,840 So we need to have keys that spawn in any of these rooms that 460 00:23:02,840 --> 00:23:05,635 are just blindly accessible. 461 00:23:05,635 --> 00:23:07,760 And Isaac does things a little bit differently also 462 00:23:07,760 --> 00:23:09,980 in that it generates keys and bombs randomly, 463 00:23:09,980 --> 00:23:11,600 so that you can actually get-- 464 00:23:11,600 --> 00:23:15,860 you don't necessarily have to plant your keys in very specific locations, 465 00:23:15,860 --> 00:23:19,100 if your algorithm is sufficiently accommodating and complex enough. 466 00:23:19,100 --> 00:23:22,970 You can just at, the end of every room, have a chance to spawn a key randomly. 467 00:23:22,970 --> 00:23:25,520 And if you're lucky, or if you're not lucky, and assuming 468 00:23:25,520 --> 00:23:29,540 that the end of the dungeon doesn't exist behind your locked doors. 469 00:23:29,540 --> 00:23:33,500 You have the opportunity to stall and lock those doors, or not. 470 00:23:33,500 --> 00:23:36,570 And just go on through your dungeon as needed. 471 00:23:36,570 --> 00:23:39,260 In this case, they don't lock the boss doors. 472 00:23:39,260 --> 00:23:42,500 So you can go through the boss door regardless of whether you have a key. 473 00:23:42,500 --> 00:23:45,980 So they've accommodated for this purely random approach, 474 00:23:45,980 --> 00:23:49,940 and that just goes to illustrate how you can still take randomisation 475 00:23:49,940 --> 00:23:53,240 using very complex principles, and produce games 476 00:23:53,240 --> 00:23:55,520 that are extremely addicting and fun. 477 00:23:55,520 --> 00:24:00,380 And you don't necessarily need to be super elaborate. 478 00:24:00,380 --> 00:24:01,700 The first thing, OK. 479 00:24:01,700 --> 00:24:03,840 So hitboxes and hurtboxes will be the next topic. 480 00:24:03,840 --> 00:24:07,430 So I want to touch on, in the code, how we sort of do dungeon 481 00:24:07,430 --> 00:24:09,610 generation in the game engine here. 482 00:24:09,610 --> 00:24:11,000 So I'm going to open up-- 483 00:24:11,000 --> 00:24:12,110 there's a few files. 484 00:24:12,110 --> 00:24:17,580 So doorway, notice in the source distro, there's a World folder. 485 00:24:17,580 --> 00:24:20,120 We've sort of categorized all of the files that 486 00:24:20,120 --> 00:24:24,410 have to do with world generation within that World folder. 487 00:24:24,410 --> 00:24:29,500 We have a doorway file, we have a dungeon file, and we have a room file. 488 00:24:29,500 --> 00:24:34,030 So the dungeon file models the dungeon. 489 00:24:34,030 --> 00:24:38,740 All of the rooms that form our dungeon, just as a very high, level top 490 00:24:38,740 --> 00:24:39,850 level, data structure. 491 00:24:39,850 --> 00:24:42,100 It's actually very simple. 492 00:24:42,100 --> 00:24:46,120 The room is, as we saw before, the individual unit of the dungeon. 493 00:24:46,120 --> 00:24:49,900 So a dungeon is effectively like a table of rooms. 494 00:24:49,900 --> 00:24:55,086 And then it holds the code for how we can transition between them. 495 00:24:55,086 --> 00:24:56,960 But that's sort of how we can think about it. 496 00:24:56,960 --> 00:24:59,890 When you a game level in general, in this case dungeon 497 00:24:59,890 --> 00:25:01,510 is sort of our game level. 498 00:25:01,510 --> 00:25:04,210 You can model the different subset aspects 499 00:25:04,210 --> 00:25:06,187 of your level via some data structure. 500 00:25:06,187 --> 00:25:08,020 In this case, we've decided to make it room. 501 00:25:08,020 --> 00:25:09,728 But if you have just a platform or level, 502 00:25:09,728 --> 00:25:12,460 maybe you have regions or zones, or anything. 503 00:25:12,460 --> 00:25:16,120 Just little subsegments of your level that you can transition between. 504 00:25:16,120 --> 00:25:19,150 It's useful to think in terms of that, because from an efficiency 505 00:25:19,150 --> 00:25:22,840 and performance standpoint, you want to dynamically probably load 506 00:25:22,840 --> 00:25:24,760 certain levels one at a time. 507 00:25:24,760 --> 00:25:29,500 Certain aspects, certain components, sub areas of your level, one at a time, 508 00:25:29,500 --> 00:25:31,540 rather than just the entire level at once, 509 00:25:31,540 --> 00:25:35,170 because depending on how sufficiently complex and large your level is, 510 00:25:35,170 --> 00:25:38,650 you can get to exercising your computer's memory constraints. 511 00:25:38,650 --> 00:25:40,550 So don't want to do that. 512 00:25:40,550 --> 00:25:45,160 So in this case, our algorithm is we have a dungeon, we have rooms. 513 00:25:45,160 --> 00:25:48,130 We have one active room that's only visible at one time that's 514 00:25:48,130 --> 00:25:49,300 loaded in memory. 515 00:25:49,300 --> 00:25:51,580 And then whenever we transition between rooms, 516 00:25:51,580 --> 00:25:55,280 we want to have another room that gets temporarily loaded. 517 00:25:55,280 --> 00:25:57,670 So let's look at the dungeon class here. 518 00:25:57,670 --> 00:25:59,290 Dungeon.lua. 519 00:25:59,290 --> 00:26:03,200 So 14 self-taught rooms, empty table. 520 00:26:03,200 --> 00:26:06,130 We're going to fill that with rooms, just room objects. 521 00:26:06,130 --> 00:26:07,550 Self.currentroom. 522 00:26:07,550 --> 00:26:11,230 Room, and we're going to pass it in the player. 523 00:26:11,230 --> 00:26:15,760 So that the player has access to all the entities and objects therein, 524 00:26:15,760 --> 00:26:19,630 and can do things like collision detection, which is very important. 525 00:26:19,630 --> 00:26:26,680 And also so that the entities in the room can look at the player 526 00:26:26,680 --> 00:26:30,370 and then decide what they want to do with their AI, which 527 00:26:30,370 --> 00:26:34,270 you can model arbitrarily complex. 528 00:26:34,270 --> 00:26:39,140 The whole init function of room.lua is going, we're going to show it here. 529 00:26:39,140 --> 00:26:42,590 So in room.lua, in that same world folder, 530 00:26:42,590 --> 00:26:44,680 we've instantiated the dungeon at a high level. 531 00:26:44,680 --> 00:26:47,860 We know the dungeons, it's basically a table of rooms. 532 00:26:47,860 --> 00:26:51,190 So what's a room look like? 533 00:26:51,190 --> 00:26:54,130 Well a room, as we saw before, what are the pieces 534 00:26:54,130 --> 00:26:56,595 that a room needs in order to function? 535 00:26:56,595 --> 00:26:58,720 What does the room have to sort of keep control of? 536 00:26:58,720 --> 00:27:02,064 537 00:27:02,064 --> 00:27:02,730 AUDIENCE: Doors. 538 00:27:02,730 --> 00:27:03,563 COLTON OGDEN: Doors. 539 00:27:03,563 --> 00:27:06,287 540 00:27:06,287 --> 00:27:06,870 Anything else? 541 00:27:06,870 --> 00:27:09,640 542 00:27:09,640 --> 00:27:11,620 So doors it has to keep track of, right? 543 00:27:11,620 --> 00:27:14,590 Because when we touch a door, we should transition to the next room. 544 00:27:14,590 --> 00:27:16,720 It should keep track of the player. 545 00:27:16,720 --> 00:27:18,330 So the player can update. 546 00:27:18,330 --> 00:27:21,500 It should keep track of objects in the room like switches, 547 00:27:21,500 --> 00:27:25,556 as we saw in the example, such that they can update those. 548 00:27:25,556 --> 00:27:27,430 And see has the player stepped on the switch? 549 00:27:27,430 --> 00:27:30,070 If he has, open the doors. 550 00:27:30,070 --> 00:27:31,830 And then entities, right? 551 00:27:31,830 --> 00:27:34,750 It should keep track of all of the creatures in the room 552 00:27:34,750 --> 00:27:37,240 so that they can update, they can interact with each other. 553 00:27:37,240 --> 00:27:40,660 The player can hit them, or they can hit the player. 554 00:27:40,660 --> 00:27:44,890 And you can model whatever interactions you want to. 555 00:27:44,890 --> 00:27:45,820 So we can see here. 556 00:27:45,820 --> 00:27:47,190 Oh, and another thing too. 557 00:27:47,190 --> 00:27:50,830 Probably one of the more important visual aspects of it, 558 00:27:50,830 --> 00:27:54,640 we need to also have a set of tiles that model what the room looks like. 559 00:27:54,640 --> 00:27:55,850 It's a container. 560 00:27:55,850 --> 00:28:00,550 So we're going to draw, we have a corner, a corner, a corner, a corner. 561 00:28:00,550 --> 00:28:01,630 Walls on the sides. 562 00:28:01,630 --> 00:28:02,830 Walls on the top and bottom. 563 00:28:02,830 --> 00:28:03,910 And then a floor. 564 00:28:03,910 --> 00:28:06,040 And so we need to obviously draw the room 565 00:28:06,040 --> 00:28:09,039 before we draw all of the other things, and update all the other things. 566 00:28:09,039 --> 00:28:14,550 So tiles, doorways, entities, and objects. 567 00:28:14,550 --> 00:28:16,151 So we can see here. 568 00:28:16,151 --> 00:28:18,400 You have tiles, soft-lit tiles against an empty table. 569 00:28:18,400 --> 00:28:21,040 We have a function called Generate Walls And Floors. 570 00:28:21,040 --> 00:28:22,330 Entities, empty table. 571 00:28:22,330 --> 00:28:24,520 We have a function called Generate Entities. 572 00:28:24,520 --> 00:28:26,425 And then objects equals empty table. 573 00:28:26,425 --> 00:28:28,720 We have a function called Generate Objects. 574 00:28:28,720 --> 00:28:29,980 And lastly, doorways. 575 00:28:29,980 --> 00:28:33,100 And then here because it's not necessarily 576 00:28:33,100 --> 00:28:38,740 as complex as we need for a entire function, we just have four doorways. 577 00:28:38,740 --> 00:28:40,090 And this is static. 578 00:28:40,090 --> 00:28:43,300 I've chosen in this example to have all the doorways always 579 00:28:43,300 --> 00:28:46,210 be in the same place, and sort of behave in the same way. 580 00:28:46,210 --> 00:28:50,710 But you could create a more complex system, whereby especially 581 00:28:50,710 --> 00:28:54,310 if you have an algorithm that generates a dungeon dynamically, 582 00:28:54,310 --> 00:28:56,660 and maybe your rooms aren't necessarily hard set. 583 00:28:56,660 --> 00:28:58,660 Maybe you have a broom, right? 584 00:28:58,660 --> 00:29:02,162 If we go back to our slides earlier. 585 00:29:02,162 --> 00:29:05,120 And let's say we're looking at this room right here in the very center. 586 00:29:05,120 --> 00:29:08,470 We can see it has a doorway on the left, a doorway up top, 587 00:29:08,470 --> 00:29:10,000 and a doorway to the right. 588 00:29:10,000 --> 00:29:13,510 But there's no doorway on the bottom. 589 00:29:13,510 --> 00:29:17,200 And that looks like an arbitrary design decision on behalf of the designers. 590 00:29:17,200 --> 00:29:21,820 But if we look at this room up top here, we 591 00:29:21,820 --> 00:29:24,286 can see that it sort of behaves in the same way. 592 00:29:24,286 --> 00:29:26,410 There's a doorway going into this room to the left. 593 00:29:26,410 --> 00:29:28,780 There's doorway going to this room down below. 594 00:29:28,780 --> 00:29:31,446 But it doesn't have a doorway up top and a doorway on the right, 595 00:29:31,446 --> 00:29:35,390 because there are no rooms going between that room and those directions. 596 00:29:35,390 --> 00:29:38,770 So when you have a 2D array of dungeon rooms, 597 00:29:38,770 --> 00:29:42,220 and you want to model your doorways, it can be as simple 598 00:29:42,220 --> 00:29:45,130 as is there room in that direction? 599 00:29:45,130 --> 00:29:48,160 If there is, and you will have your data structures sort of 600 00:29:48,160 --> 00:29:53,420 laid out in advance before you generate these doorways, if it does not exist, 601 00:29:53,420 --> 00:29:54,250 don't make a door. 602 00:29:54,250 --> 00:29:56,710 If it does exist, make a door. 603 00:29:56,710 --> 00:29:59,350 And then make sure that when you transition 604 00:29:59,350 --> 00:30:05,140 between from the right to the left, or from the bottom to the top, 605 00:30:05,140 --> 00:30:11,770 that you go to the correct rooms at the correct indices in your 2D room array. 606 00:30:11,770 --> 00:30:12,834 Does that make sense? 607 00:30:12,834 --> 00:30:16,000 Anybody have any questions so far as to like how this works at a high level? 608 00:30:16,000 --> 00:30:18,660 609 00:30:18,660 --> 00:30:19,530 OK? 610 00:30:19,530 --> 00:30:20,380 Awesome. 611 00:30:20,380 --> 00:30:23,300 So these doorways here are all because of this dungeon 612 00:30:23,300 --> 00:30:29,000 is completely random, and every time it always has doorways going top, bottom, 613 00:30:29,000 --> 00:30:29,726 left and right. 614 00:30:29,726 --> 00:30:31,600 We're always just going to put four doorways, 615 00:30:31,600 --> 00:30:32,900 going top, bottom, left and right. 616 00:30:32,900 --> 00:30:34,691 Note that they take a string denoting which 617 00:30:34,691 --> 00:30:36,820 direction they are, and this will become important 618 00:30:36,820 --> 00:30:40,390 later on in the doorway class, which we see here 619 00:30:40,390 --> 00:30:42,880 is modeled as a separate class. 620 00:30:42,880 --> 00:30:45,160 False here just means is the door open? 621 00:30:45,160 --> 00:30:48,310 So by default, we're going to close the door. 622 00:30:48,310 --> 00:30:51,790 And then self, so that we have access to the room from the doorway. 623 00:30:51,790 --> 00:30:54,632 624 00:30:54,632 --> 00:30:56,590 The room should have a reference to the player, 625 00:30:56,590 --> 00:31:00,940 so that it can model interactions between the entities and the player, 626 00:31:00,940 --> 00:31:04,030 as well as the objects and the player. 627 00:31:04,030 --> 00:31:05,890 Notice that it has a render offset. 628 00:31:05,890 --> 00:31:14,230 So if we look at the game here, the tiles 629 00:31:14,230 --> 00:31:17,920 don't completely match up to the width and height of the screen. 630 00:31:17,920 --> 00:31:21,340 And that's mainly a function of the virtual height 631 00:31:21,340 --> 00:31:26,710 not mapping perfectly to 16 tiles, divided evenly by 16 tiles. 632 00:31:26,710 --> 00:31:29,750 So what I've done is I've made the dungeon a little bit smaller. 633 00:31:29,750 --> 00:31:36,160 And also the fact that the doorways take up a couple of extra tiles of padding 634 00:31:36,160 --> 00:31:39,610 on their sides, it's like sort of blank space up here. 635 00:31:39,610 --> 00:31:41,830 We've shifted everything inwards a little bit. 636 00:31:41,830 --> 00:31:47,410 We've made the dungeon two tiles smaller width and height wise than the screen. 637 00:31:47,410 --> 00:31:50,080 And then we've just rendered offset by a certain amount 638 00:31:50,080 --> 00:31:51,640 such that it's completely centered. 639 00:31:51,640 --> 00:31:56,890 We calculate how much padding exists between the fully rendered dungeon 640 00:31:56,890 --> 00:32:00,190 and whatever blank space is left, and just shift by half of that amount, 641 00:32:00,190 --> 00:32:01,780 and that's our render offset. 642 00:32:01,780 --> 00:32:05,164 So that's why render offset is important in this case. 643 00:32:05,164 --> 00:32:07,330 When you're trying to center anything, you typically 644 00:32:07,330 --> 00:32:08,852 do it just by calculating an offset. 645 00:32:08,852 --> 00:32:11,560 Calculate the width and height of whatever you're trying to draw, 646 00:32:11,560 --> 00:32:14,920 calculate whatever your width and height of your screen is minus that, 647 00:32:14,920 --> 00:32:18,040 divide it by 2, that's your render offset. 648 00:32:18,040 --> 00:32:22,570 And then these two fields here are interesting. self.adjacentoffsetX, 649 00:32:22,570 --> 00:32:24,610 self.adjectentoffsetY. 650 00:32:24,610 --> 00:32:30,284 Does anybody have a guess as to what this is used for? 651 00:32:30,284 --> 00:32:31,226 Yeah. 652 00:32:31,226 --> 00:32:33,110 Drawing itself when it's the adjacent room. 653 00:32:33,110 --> 00:32:34,550 Yes, exactly. 654 00:32:34,550 --> 00:32:37,160 So drawing itself when it's the adjacent room. 655 00:32:37,160 --> 00:32:39,950 So when you load the next room, you're going 656 00:32:39,950 --> 00:32:41,900 to instantiate a room just like this. 657 00:32:41,900 --> 00:32:44,790 But by default it's going to draw at 0.0. 658 00:32:44,790 --> 00:32:49,049 However, if we want that room to draw not right where we are. 659 00:32:49,049 --> 00:32:50,840 Obviously, if we're in the current room, we 660 00:32:50,840 --> 00:32:52,220 don't want the next room drawing right on top 661 00:32:52,220 --> 00:32:54,724 of where we are, because then it's just going to layer right 662 00:32:54,724 --> 00:32:55,890 on top of the room we're in. 663 00:32:55,890 --> 00:32:56,960 And we want to draw it-- 664 00:32:56,960 --> 00:32:59,450 if we're going to the right, we want to draw a screen width to the right. 665 00:32:59,450 --> 00:33:02,870 If we're drawing it to the left, we want to draw it a screen width to the left. 666 00:33:02,870 --> 00:33:04,700 And same thing on the y-axis. 667 00:33:04,700 --> 00:33:06,480 A screen height above, or below it. 668 00:33:06,480 --> 00:33:10,790 So adjacentoffsetX or y, we just add to when we draw the room. 669 00:33:10,790 --> 00:33:16,210 And that'll have the effect of rendering it separately from the room 670 00:33:16,210 --> 00:33:17,210 that we're currently in. 671 00:33:17,210 --> 00:33:19,140 I can try and draw an illustration here. 672 00:33:19,140 --> 00:33:24,080 So if we have our room here, this is our current room. 673 00:33:24,080 --> 00:33:25,310 So self.currentroom. 674 00:33:25,310 --> 00:33:32,040 675 00:33:32,040 --> 00:33:35,741 And let's say we have a doorway here. 676 00:33:35,741 --> 00:33:36,240 Right? 677 00:33:36,240 --> 00:33:38,520 That's a doorway object, the player is here. 678 00:33:38,520 --> 00:33:40,230 He collides with that object. 679 00:33:40,230 --> 00:33:43,480 It's going to trigger a transition to a room up above. 680 00:33:43,480 --> 00:33:46,980 So what we do is we load in a new room right away. 681 00:33:46,980 --> 00:33:53,460 We always have a pointer called self.nextroom. 682 00:33:53,460 --> 00:33:56,850 And this is all kept track of in the dungeod.lua file. 683 00:33:56,850 --> 00:34:01,740 But self.nextroom by default is going to be nil. 684 00:34:01,740 --> 00:34:06,810 But when we transition from the current room to the next room, right? 685 00:34:06,810 --> 00:34:08,460 We should set that to something. 686 00:34:08,460 --> 00:34:12,909 So self.currentroom is going to be the same. 687 00:34:12,909 --> 00:34:19,230 But when we trigger this collision, self.nextroom, 688 00:34:19,230 --> 00:34:24,090 this is going to be equal to just a new room. 689 00:34:24,090 --> 00:34:26,310 And then we get which doorway we're in. 690 00:34:26,310 --> 00:34:27,159 We figure it out. 691 00:34:27,159 --> 00:34:29,940 We figure out which direction we're moving in, technically. 692 00:34:29,940 --> 00:34:35,150 And then if we're moving up, then we just pass in a-- 693 00:34:35,150 --> 00:34:41,790 we said it's adjacent offset y in this case, to negative screen height. 694 00:34:41,790 --> 00:34:45,080 If it's below, we set it to positive screen height. 695 00:34:45,080 --> 00:34:50,580 If we go here, it's going to be negative screen with the adjacent x, 696 00:34:50,580 --> 00:34:52,260 will be negative screen width. 697 00:34:52,260 --> 00:34:56,909 And then positive screen width on the x if we're moving to the right. 698 00:34:56,909 --> 00:35:04,710 And so this sort of adjacent we could see, if do xy, 699 00:35:04,710 --> 00:35:07,810 it will be that's basically the adjacent offset. 700 00:35:07,810 --> 00:35:14,955 And so we end up when we draw our transition going from bottom to 701 00:35:14,955 --> 00:35:21,160 up in this case, we just tween the camera to this value. 702 00:35:21,160 --> 00:35:23,550 So we have a camera, right? 703 00:35:23,550 --> 00:35:24,750 This is our camera. 704 00:35:24,750 --> 00:35:30,390 And it's going to be looking here by default. So camera x and camera y, 705 00:35:30,390 --> 00:35:33,600 those are values in our code as well. 706 00:35:33,600 --> 00:35:37,080 When we trigger this collision on the doorway, 707 00:35:37,080 --> 00:35:40,110 and we have current room here, which is at 0.0, 708 00:35:40,110 --> 00:35:45,870 and then we have this room here, which is at 0 plus our adjacent 709 00:35:45,870 --> 00:35:48,120 offset y, which is negative screen height. 710 00:35:48,120 --> 00:35:53,790 So it has the effect of making it negative screen height on the y. 711 00:35:53,790 --> 00:35:57,840 Our camera x recall love.graphics.Translate is our camera. 712 00:35:57,840 --> 00:35:59,580 So all we do is we just tween that. 713 00:35:59,580 --> 00:36:00,970 We say, OK. 714 00:36:00,970 --> 00:36:05,020 Here's our Cam x is going to be here. 715 00:36:05,020 --> 00:36:07,210 And Cam y, it's getting a little bit messy. 716 00:36:07,210 --> 00:36:07,920 I apologize. 717 00:36:07,920 --> 00:36:10,230 But our camera x and y are here. 718 00:36:10,230 --> 00:36:17,070 And then over time, we're going to tween that up into the next rooms 719 00:36:17,070 --> 00:36:23,790 x and y, which is a just x plus adjacent offset x, y plus adjacent offset y. 720 00:36:23,790 --> 00:36:29,040 And then once this camera has shifted from here up to here, 721 00:36:29,040 --> 00:36:32,620 or whichever direction we're going, whether it's up, down, left or right. 722 00:36:32,620 --> 00:36:39,090 Once we've completed that, we can normalize everything again back to 0.0 723 00:36:39,090 --> 00:36:45,210 by doing self.currentroom equals, what do we need to do, 724 00:36:45,210 --> 00:36:48,570 if we're going to put everything back to? 725 00:36:48,570 --> 00:36:51,505 Let's say I want to make this room the new current room. 726 00:36:51,505 --> 00:36:52,380 What do I need to do? 727 00:36:52,380 --> 00:36:55,840 728 00:36:55,840 --> 00:36:58,870 So we have current room, and we have next room. 729 00:36:58,870 --> 00:37:01,600 If I want the current room to become the next room, 730 00:37:01,600 --> 00:37:08,440 all I need to do is say self.currentroom equals self.nextroom, right? 731 00:37:08,440 --> 00:37:12,610 732 00:37:12,610 --> 00:37:16,300 And then once that happens, what happens to the adjacent 733 00:37:16,300 --> 00:37:18,190 offset x and y of the next room? 734 00:37:18,190 --> 00:37:22,200 735 00:37:22,200 --> 00:37:23,830 They get set to 0, right? 736 00:37:23,830 --> 00:37:27,157 I want to take this room that we've offset up here, 737 00:37:27,157 --> 00:37:29,740 and I just want to make it the center of the game world again. 738 00:37:29,740 --> 00:37:34,360 I want to just put it as 0.0, so we can do this exact same calculation 739 00:37:34,360 --> 00:37:39,230 by just setting adjacent offset x or y to a negative or positive screen height 740 00:37:39,230 --> 00:37:41,770 or screen width relative to 0.9. 741 00:37:41,770 --> 00:37:45,910 So what I'm going to do is just set the adjacent offset 742 00:37:45,910 --> 00:37:50,600 of x and y of the next room, which is now current room, to 0. 743 00:37:50,600 --> 00:37:53,320 And it's going to draw it right back at 0.0. 744 00:37:53,320 --> 00:37:57,430 And then camera x and camera y are also going to be set to 0.0. 745 00:37:57,430 --> 00:38:00,700 And this is going to have the effect of looking as if we're going up 746 00:38:00,700 --> 00:38:01,720 and staying there. 747 00:38:01,720 --> 00:38:03,880 But in reality, we're just going up, and then 748 00:38:03,880 --> 00:38:05,710 instantly shifting everything back to 0.0, 749 00:38:05,710 --> 00:38:09,370 including the player, entities, and switches of that room. 750 00:38:09,370 --> 00:38:11,020 So it's purely an illusion. 751 00:38:11,020 --> 00:38:15,755 But it allows us to simulate this sort of infinite exploring a dungeon effect. 752 00:38:15,755 --> 00:38:16,630 Does that make sense? 753 00:38:16,630 --> 00:38:20,110 Does the overall flow of how this works makes sense? 754 00:38:20,110 --> 00:38:20,656 OK. 755 00:38:20,656 --> 00:38:22,030 So it's a little bit messy there. 756 00:38:22,030 --> 00:38:27,250 Hopefully I was able to illustrate the overall algorithm for how 757 00:38:27,250 --> 00:38:29,230 the infinite dungeon generator works. 758 00:38:29,230 --> 00:38:32,050 759 00:38:32,050 --> 00:38:33,610 Where did we leave off? 760 00:38:33,610 --> 00:38:37,460 We were in the init function of the room. 761 00:38:37,460 --> 00:38:42,160 So let's take a look at a few of the functions that comprise that. 762 00:38:42,160 --> 00:38:45,180 So generate walls and floors. 763 00:38:45,180 --> 00:38:47,560 This is very similar to what we've looked 764 00:38:47,560 --> 00:38:52,360 at before with tile maps in Mario for example, where we just go from y to x. 765 00:38:52,360 --> 00:38:55,210 And then we just pick a random ID, or our random ID. 766 00:38:55,210 --> 00:38:56,800 Well, it is random ID for some of it. 767 00:38:56,800 --> 00:38:58,760 But sometimes we need an explicit ID. 768 00:38:58,760 --> 00:39:04,960 So remind me, what does the ID actually map to when 769 00:39:04,960 --> 00:39:07,700 we're you drawing tiles to the screen? 770 00:39:07,700 --> 00:39:11,178 If we want to give a tile an ID, what does that, what should that map to? 771 00:39:11,178 --> 00:39:12,146 Yeah? 772 00:39:12,146 --> 00:39:14,570 AUDIENCE: The frame in the sprite sheet. 773 00:39:14,570 --> 00:39:17,590 COLTON OGDEN: The frame in the sprite sheet, that's correct. 774 00:39:17,590 --> 00:39:20,770 It doesn't have to for all game engines, for all implementations. 775 00:39:20,770 --> 00:39:24,580 But it's the easiest thing to do, is just to give your tile an ID 776 00:39:24,580 --> 00:39:26,740 that you can then just draw, you can index 777 00:39:26,740 --> 00:39:29,560 into your sprite sheet at that ID. 778 00:39:29,560 --> 00:39:32,680 It's just very, very simple, lightweight clean approach to modeling. 779 00:39:32,680 --> 00:39:36,250 And we can see here, ID gets ID. 780 00:39:36,250 --> 00:39:39,520 After we've figured out what ID we want, now how 781 00:39:39,520 --> 00:39:43,030 do we determine like let's say I want to draw-- 782 00:39:43,030 --> 00:39:49,430 783 00:39:49,430 --> 00:39:52,736 let's say, for example, like this tile here. 784 00:39:52,736 --> 00:39:56,660 Notice it's a corner tile. 785 00:39:56,660 --> 00:39:59,080 What do I need to do to basically assign-- 786 00:39:59,080 --> 00:40:02,810 I'm going to die before I even have the chance to show you. 787 00:40:02,810 --> 00:40:08,020 While I avoid enemies, if I wanted to draw that top left corner, 788 00:40:08,020 --> 00:40:09,270 what am I sort of looking for? 789 00:40:09,270 --> 00:40:12,620 I'm still taking damage anyway. 790 00:40:12,620 --> 00:40:14,480 Relative to x and y, what am I looking for? 791 00:40:14,480 --> 00:40:17,770 792 00:40:17,770 --> 00:40:21,300 What x and y does that tile need, assuming 793 00:40:21,300 --> 00:40:24,240 everything starts 1.1 on the top left, and goes down 794 00:40:24,240 --> 00:40:27,257 to height and width of the overall dungeon? 795 00:40:27,257 --> 00:40:29,340 What is the xy need to be of that top left corner? 796 00:40:29,340 --> 00:40:33,920 797 00:40:33,920 --> 00:40:35,060 It needs to be 1, right? 798 00:40:35,060 --> 00:40:38,060 So if that's 1.1, basically the top left corner, 799 00:40:38,060 --> 00:40:41,080 that ID should be equal to the corner sprite. 800 00:40:41,080 --> 00:40:42,815 The top left corner sprite, specifically. 801 00:40:42,815 --> 00:40:44,440 What about the top right corner sprite? 802 00:40:44,440 --> 00:40:47,295 803 00:40:47,295 --> 00:40:48,170 What should the x be? 804 00:40:48,170 --> 00:40:50,920 805 00:40:50,920 --> 00:40:51,595 Sorry? 806 00:40:51,595 --> 00:40:52,010 AUDIENCE: Width. 807 00:40:52,010 --> 00:40:52,850 COLTON OGDEN: Yes, width. 808 00:40:52,850 --> 00:40:53,370 Exactly. 809 00:40:53,370 --> 00:40:56,000 What's the y? 810 00:40:56,000 --> 00:40:56,890 Still going to be 1. 811 00:40:56,890 --> 00:40:58,015 What about the bottom left? 812 00:40:58,015 --> 00:41:00,327 813 00:41:00,327 --> 00:41:01,160 Width, comma height. 814 00:41:01,160 --> 00:41:02,243 And then the bottom right? 815 00:41:02,243 --> 00:41:04,800 816 00:41:04,800 --> 00:41:08,560 AUDIENCE: But it's [INAUDIBLE] 817 00:41:08,560 --> 00:41:11,270 COLTON OGDEN: Sorry, bottom left should be 1, comma height. 818 00:41:11,270 --> 00:41:16,310 Bottom right should be width, height. 819 00:41:16,310 --> 00:41:20,390 And so basically checking the position of each tile 820 00:41:20,390 --> 00:41:24,721 is how we can infer its ID, which is what we're doing in the source code 821 00:41:24,721 --> 00:41:25,220 here. 822 00:41:25,220 --> 00:41:28,370 If x is 1 and y is 1, OK, top left corner. 823 00:41:28,370 --> 00:41:30,590 And notice that we've put these into constants, 824 00:41:30,590 --> 00:41:33,380 that we've put in the constant.lua, just for readability. 825 00:41:33,380 --> 00:41:37,100 So we can instantly see OK, I should set ID tile top left 826 00:41:37,100 --> 00:41:40,820 corner, not some arbitrary number that's our index into the tile sheet. 827 00:41:40,820 --> 00:41:43,370 At maybe like 40 something, or whatever it is. 828 00:41:43,370 --> 00:41:46,820 Bottom left is 1 and height. 829 00:41:46,820 --> 00:41:53,280 Top right is width and 1, and then bottom right is width and height. 830 00:41:53,280 --> 00:41:54,560 And we can see, it's readable. 831 00:41:54,560 --> 00:41:57,684 We can sort of see at a glance what we're doing, where you're conditionally 832 00:41:57,684 --> 00:41:58,970 generating all of our tiles. 833 00:41:58,970 --> 00:42:02,480 834 00:42:02,480 --> 00:42:09,890 If none of those are true, and then x is 1, what's that tile? 835 00:42:09,890 --> 00:42:11,450 If x is 1, but it's not a corner? 836 00:42:11,450 --> 00:42:19,230 837 00:42:19,230 --> 00:42:20,950 It's a left hand wall. 838 00:42:20,950 --> 00:42:24,450 And the same thing is if it's the width, it's a right hand wall. 839 00:42:24,450 --> 00:42:27,300 And if y is 1, it's a top wall. 840 00:42:27,300 --> 00:42:29,580 If y is height, it's a bottom wall. 841 00:42:29,580 --> 00:42:36,240 And then if it's none of those, it's got to be a floor, exactly. 842 00:42:36,240 --> 00:42:39,060 So that's basically how we generate the overall-- 843 00:42:39,060 --> 00:42:43,770 it's a very easy, simple generation algorithm. 844 00:42:43,770 --> 00:42:48,180 What I've done is for randomization here, 845 00:42:48,180 --> 00:42:52,860 we have actually a table of potential left walls, potential right walls, 846 00:42:52,860 --> 00:42:54,240 potential top and bottom. 847 00:42:54,240 --> 00:42:58,500 And then we just ascribe it a random value within there, 848 00:42:58,500 --> 00:43:00,300 based on however large that is. 849 00:43:00,300 --> 00:43:02,700 And that gives us variable, we can see it. 850 00:43:02,700 --> 00:43:06,630 We have random-- every time I generate it. 851 00:43:06,630 --> 00:43:08,894 So take note of maybe some of the tiles visually 852 00:43:08,894 --> 00:43:10,310 that you can see there on the map. 853 00:43:10,310 --> 00:43:13,750 854 00:43:13,750 --> 00:43:15,200 Notice that they change. 855 00:43:15,200 --> 00:43:18,270 Notice that the switch has also changed. 856 00:43:18,270 --> 00:43:19,780 Notice that they changed again. 857 00:43:19,780 --> 00:43:21,230 So everything is variable. 858 00:43:21,230 --> 00:43:22,380 We have a little bit of visual variety. 859 00:43:22,380 --> 00:43:24,254 This is what we did, essentially, with Mario. 860 00:43:24,254 --> 00:43:26,594 We changed the tile set, and the topper set. 861 00:43:26,594 --> 00:43:29,010 Only now we're just changing, we have only one tile sheet, 862 00:43:29,010 --> 00:43:31,470 but several variations at the same tile they're in. 863 00:43:31,470 --> 00:43:34,560 So all we need to do is pick a random variation of whatever tile. 864 00:43:34,560 --> 00:43:36,870 And that involves us looking at the sprite sheet, 865 00:43:36,870 --> 00:43:40,890 picking out which individual tiles, which separate tiles, 866 00:43:40,890 --> 00:43:45,780 map to the specific type of tile, and then just picking a random value 867 00:43:45,780 --> 00:43:47,580 from that table 868 00:43:47,580 --> 00:43:49,210 That's how that works. 869 00:43:49,210 --> 00:43:54,570 So a couple of things, I think, left to show relative 870 00:43:54,570 --> 00:43:56,510 to the dungeon generation. 871 00:43:56,510 --> 00:44:02,010 So 48, we have generate entities. 872 00:44:02,010 --> 00:44:04,950 So entities are here. 873 00:44:04,950 --> 00:44:07,800 We have their names, right? 874 00:44:07,800 --> 00:44:12,930 Some of the entities we saw, skeletons, bats, slimes, ghosts, spiders. 875 00:44:12,930 --> 00:44:16,560 It's a very lightweight function. 876 00:44:16,560 --> 00:44:19,380 It's not like 15 or 20 lines, but we're generating 877 00:44:19,380 --> 00:44:21,780 a bunch of different kinds of entities. 878 00:44:21,780 --> 00:44:24,900 Because what we've done, we take, we basically 879 00:44:24,900 --> 00:44:27,270 take a random type from that table. 880 00:44:27,270 --> 00:44:30,930 We create an entity, and then using what we've 881 00:44:30,930 --> 00:44:34,740 defined in a global table called Entity Defs, 882 00:44:34,740 --> 00:44:37,980 we take out what sort of matters in terms 883 00:44:37,980 --> 00:44:41,490 of generating each individual entity, the characteristics thereof, 884 00:44:41,490 --> 00:44:43,620 and we just put it in simple data form. 885 00:44:43,620 --> 00:44:49,530 This is sort of like the segue into data driven design for your game. 886 00:44:49,530 --> 00:44:54,990 If you look at Entity Defs here, we can just see that all of our entities 887 00:44:54,990 --> 00:44:56,730 are a sequence of data. 888 00:44:56,730 --> 00:44:59,490 So up here we have player, on line 10. 889 00:44:59,490 --> 00:45:01,140 Player gets a table. 890 00:45:01,140 --> 00:45:02,670 We give him walk speed. 891 00:45:02,670 --> 00:45:04,590 We have a table of animations. 892 00:45:04,590 --> 00:45:07,020 So he's got a walk left animation, a walk right animation, 893 00:45:07,020 --> 00:45:08,550 a walk down animation. 894 00:45:08,550 --> 00:45:11,840 All of those have their frames, their interval, their texture, everything 895 00:45:11,840 --> 00:45:14,850 is just clean data, right? 896 00:45:14,850 --> 00:45:16,740 There's no logic here, really. 897 00:45:16,740 --> 00:45:20,430 It's just flags, or values, simple things. 898 00:45:20,430 --> 00:45:25,380 You could give anybody who has sort of the basic knowledge of what we're 899 00:45:25,380 --> 00:45:29,470 doing this file, and maybe some textures, and say, hey, 900 00:45:29,470 --> 00:45:30,840 I want you to design-- 901 00:45:30,840 --> 00:45:33,150 I want you to lay out basically all of that's 902 00:45:33,150 --> 00:45:38,220 involved in what makes a skeleton render to the screen. 903 00:45:38,220 --> 00:45:40,770 Create all the animations for them. 904 00:45:40,770 --> 00:45:43,530 Give those animations their timing. 905 00:45:43,530 --> 00:45:44,900 Give them the exact frames. 906 00:45:44,900 --> 00:45:48,600 Maybe skeletons should have health, and maybe health should be equal to 10 907 00:45:48,600 --> 00:45:50,620 on a skeleton, or something like that. 908 00:45:50,620 --> 00:45:53,484 There's not really any programming going on here. 909 00:45:53,484 --> 00:45:55,650 But we're describing everything in our game as data. 910 00:45:55,650 --> 00:46:01,500 And that's important thing in complex games that have fairly complex systems, 911 00:46:01,500 --> 00:46:04,440 but that can be modeled via some attributes. 912 00:46:04,440 --> 00:46:07,890 You can just ascribe your entities and data, and then let your engine parse 913 00:46:07,890 --> 00:46:12,720 this information, and then create your entities programmatically. 914 00:46:12,720 --> 00:46:17,400 You shift the burden from the programmer to the designer, a little bit. 915 00:46:17,400 --> 00:46:21,540 And you afford your design team, you and maybe other people 916 00:46:21,540 --> 00:46:23,400 who aren't as comfortable with programming, 917 00:46:23,400 --> 00:46:27,326 the ability to modify the game engine, add things to the game, 918 00:46:27,326 --> 00:46:29,700 without having to go through the bulk of your engine code 919 00:46:29,700 --> 00:46:31,107 and do anything too fancy. 920 00:46:31,107 --> 00:46:32,190 In this case, it's simple. 921 00:46:32,190 --> 00:46:37,662 All we're doing is just we're creating animations, and assigning a texture 922 00:46:37,662 --> 00:46:39,120 to each of these individual things. 923 00:46:39,120 --> 00:46:41,340 But I alluded to this last week. 924 00:46:41,340 --> 00:46:44,190 You can have a file that maybe describes something like a goblin. 925 00:46:44,190 --> 00:46:47,280 We'll see this at the end of a lecture, which has maybe like a flag 926 00:46:47,280 --> 00:46:48,412 for is it flammable? 927 00:46:48,412 --> 00:46:49,620 How much health does it have? 928 00:46:49,620 --> 00:46:51,510 What are its animations? 929 00:46:51,510 --> 00:46:53,516 What skills does it have? 930 00:46:53,516 --> 00:46:54,640 What's its attack strength? 931 00:46:54,640 --> 00:46:55,470 What's its defense? 932 00:46:55,470 --> 00:46:58,232 Where does it spawn typically? 933 00:46:58,232 --> 00:47:01,440 By putting all these attributes together and having your engine sort of parse 934 00:47:01,440 --> 00:47:04,950 this, you can create, depending on how many fields you have, 935 00:47:04,950 --> 00:47:12,169 you can create very complex potential list of things in your game. 936 00:47:12,169 --> 00:47:15,210 Whether they're entities, whether they're weapons, whether they're items, 937 00:47:15,210 --> 00:47:16,135 abilities. 938 00:47:16,135 --> 00:47:17,010 Anything you want to. 939 00:47:17,010 --> 00:47:20,970 Whether they're levels, even. 940 00:47:20,970 --> 00:47:23,020 Based solely on just data. 941 00:47:23,020 --> 00:47:26,800 So this is a holy grail of design and development 942 00:47:26,800 --> 00:47:30,180 when you get into especially very complex games like RPGs, 943 00:47:30,180 --> 00:47:34,647 where you can have skills that have particle effects 944 00:47:34,647 --> 00:47:36,480 and do different damage to different things. 945 00:47:36,480 --> 00:47:39,600 And you have entities that are-- maybe you want them some to set on fire, 946 00:47:39,600 --> 00:47:40,620 some to be electrocuted. 947 00:47:40,620 --> 00:47:41,760 Maybe some you don't. 948 00:47:41,760 --> 00:47:45,570 Maybe some melt when they touch something. 949 00:47:45,570 --> 00:47:47,670 Create a bunch of flags, create a function 950 00:47:47,670 --> 00:47:50,970 that parses this, and generates entities as a result. 951 00:47:50,970 --> 00:47:55,710 And you just allow yourself an incredible boost in productivity. 952 00:47:55,710 --> 00:48:02,650 No longer do you need to create a spider class, a ghost class, a bat class. 953 00:48:02,650 --> 00:48:04,110 It's all unnecessary. 954 00:48:04,110 --> 00:48:07,854 All you need to do is define what sort of attributes does a bat have? 955 00:48:07,854 --> 00:48:09,270 What attributes does a ghost have? 956 00:48:09,270 --> 00:48:12,030 What attributes does a skeleton have? 957 00:48:12,030 --> 00:48:16,460 And anybody can therefore mod your game as a result of this. 958 00:48:16,460 --> 00:48:20,360 All they need to do is know what attributes a potential entity can have. 959 00:48:20,360 --> 00:48:24,330 And your design team is all the more productive as a result. 960 00:48:24,330 --> 00:48:28,580 So that's a spiel on why this is relevant. 961 00:48:28,580 --> 00:48:30,560 We've implemented a very basic version of this 962 00:48:30,560 --> 00:48:33,120 just for the sake of modeling animations. 963 00:48:33,120 --> 00:48:36,751 But we don't need a separate class for all the different entities in our game 964 00:48:36,751 --> 00:48:37,250 world. 965 00:48:37,250 --> 00:48:41,180 We just need, basically, and in the context of this game, 966 00:48:41,180 --> 00:48:43,640 what are their animations? 967 00:48:43,640 --> 00:48:46,490 So that's entity defs, that's how it's working if we're 968 00:48:46,490 --> 00:48:51,450 looking at room.lua at line 48. 969 00:48:51,450 --> 00:48:53,510 All its doing is getting animations. 970 00:48:53,510 --> 00:48:56,840 This is, by the way, your function that takes in these definitions 971 00:48:56,840 --> 00:48:58,670 and creates your entities. 972 00:48:58,670 --> 00:49:00,560 They should be looking for-- 973 00:49:00,560 --> 00:49:01,790 looking into that. 974 00:49:01,790 --> 00:49:03,920 They pull that definition and then just parse out 975 00:49:03,920 --> 00:49:07,100 each individual relevant piece of data. 976 00:49:07,100 --> 00:49:09,980 And then just construct some relevant information 977 00:49:09,980 --> 00:49:13,640 or attach a relevant flag to that entity that your game engine can then later 978 00:49:13,640 --> 00:49:15,560 parse. 979 00:49:15,560 --> 00:49:19,850 The flammable example, if you do an attack and that attack is of type fire, 980 00:49:19,850 --> 00:49:24,410 and it collides with an entity, and that entity.flammable is true, 981 00:49:24,410 --> 00:49:25,940 that should trigger some behavior. 982 00:49:25,940 --> 00:49:28,065 But you don't need to do anything terribly complex. 983 00:49:28,065 --> 00:49:33,420 And you can assign this to any arbitrary entity thereafter. 984 00:49:33,420 --> 00:49:37,910 So just a simple way of getting very complex behavior for your game 985 00:49:37,910 --> 00:49:40,520 objects, entities, whatever you want. 986 00:49:40,520 --> 00:49:45,980 Modeling them as data rather than thinking about it in terms of classes. 987 00:49:45,980 --> 00:49:47,060 So that's that. 988 00:49:47,060 --> 00:49:49,768 Does anybody have any questions just like sort of how that works, 989 00:49:49,768 --> 00:49:50,889 or why it's viable? 990 00:49:50,889 --> 00:49:51,680 Or why it's useful? 991 00:49:51,680 --> 00:49:55,550 992 00:49:55,550 --> 00:49:56,897 OK. 993 00:49:56,897 --> 00:49:59,230 Couple of last things we'll look at really fast in room. 994 00:49:59,230 --> 00:50:02,680 So online 82. 995 00:50:02,680 --> 00:50:04,060 Generate objects. 996 00:50:04,060 --> 00:50:07,510 So we did this very, very similarly last week. 997 00:50:07,510 --> 00:50:09,990 Where we just had a game object class. 998 00:50:09,990 --> 00:50:13,660 Notice that it takes itself a definition for a switch. 999 00:50:13,660 --> 00:50:17,040 That definition is in gameobjects.lua. 1000 00:50:17,040 --> 00:50:18,380 Switch. 1001 00:50:18,380 --> 00:50:22,140 Here's a little bit more sort of data modeling something like a switch. 1002 00:50:22,140 --> 00:50:27,820 It's got a type of switch, frame is 2 by default. So width and height of 16. 1003 00:50:27,820 --> 00:50:28,720 It's not solid. 1004 00:50:28,720 --> 00:50:30,280 Player can walk over it. 1005 00:50:30,280 --> 00:50:31,930 Its default state is upressed. 1006 00:50:31,930 --> 00:50:34,840 So when it gets spawned into the game, it's unpressed. 1007 00:50:34,840 --> 00:50:37,960 And it's got two potential states, unprecedented and pressed. 1008 00:50:37,960 --> 00:50:39,940 And each of those states have a frame. 1009 00:50:39,940 --> 00:50:43,330 So all we need to do to render it is say, what's its current state? 1010 00:50:43,330 --> 00:50:45,380 Render this state.frame. 1011 00:50:45,380 --> 00:50:47,260 And then now, we don't need to do anything-- 1012 00:50:47,260 --> 00:50:50,590 that's basically all we need to do in order to render it at the right point. 1013 00:50:50,590 --> 00:50:54,010 Your game engine, therefore, needs to look at your object, 1014 00:50:54,010 --> 00:50:59,290 and look at its state and look at its potential states, index into that state 1015 00:50:59,290 --> 00:51:02,709 and then pull the frame from that. 1016 00:51:02,709 --> 00:51:04,750 But it forwards you sort of infinite flexibility. 1017 00:51:04,750 --> 00:51:09,010 You can now have maybe of a glowing state, 1018 00:51:09,010 --> 00:51:12,744 and maybe there's a frame in that sprite sheet that allows it to glow. 1019 00:51:12,744 --> 00:51:15,160 And you could just change it to glowing whenever you want, 1020 00:51:15,160 --> 00:51:17,080 and it'll just render appropriately. 1021 00:51:17,080 --> 00:51:22,610 So very flexible approach to modeling data. 1022 00:51:22,610 --> 00:51:24,100 149 in room. 1023 00:51:24,100 --> 00:51:25,960 So we're almost done with the dungeon here. 1024 00:51:25,960 --> 00:51:30,760 So 149 is our update function. 1025 00:51:30,760 --> 00:51:34,180 All it does basically is iterate through everything 1026 00:51:34,180 --> 00:51:38,990 and update it, including basically all the entities. 1027 00:51:38,990 --> 00:51:45,670 So for every entity if its health is less than or equal to 0, it's dead. 1028 00:51:45,670 --> 00:51:50,630 If it's dead, then don't render it, which we see down in render. 1029 00:51:50,630 --> 00:51:57,510 But if it's not dead, and self.player player collides with it, 1030 00:51:57,510 --> 00:52:01,930 and the player's not vulnerable, then we should damage the player, 1031 00:52:01,930 --> 00:52:03,370 go invulnerable. 1032 00:52:03,370 --> 00:52:06,110 And if the player's health is zero, change to game over. 1033 00:52:06,110 --> 00:52:09,070 So notice how readable this is. 1034 00:52:09,070 --> 00:52:12,970 When you model your entities like this as well, all you really need to do 1035 00:52:12,970 --> 00:52:15,160 is just check for certain flags or functions, 1036 00:52:15,160 --> 00:52:18,190 and you can do arbitrarily complex tests like this. 1037 00:52:18,190 --> 00:52:20,500 Because entities can be dead, or not. 1038 00:52:20,500 --> 00:52:23,800 Because entities can be invulnerable, or not. 1039 00:52:23,800 --> 00:52:28,690 And then because entities are all xy, with height based things in our game, 1040 00:52:28,690 --> 00:52:32,440 and collide just expects them to have that. 1041 00:52:32,440 --> 00:52:35,800 All we just do is play sound, damage the player. 1042 00:52:35,800 --> 00:52:38,160 What does damage do offhand? 1043 00:52:38,160 --> 00:52:39,265 What do you think it does? 1044 00:52:39,265 --> 00:52:41,740 AUDIENCE: I'll take a wild guess and say subtracts from your health. 1045 00:52:41,740 --> 00:52:42,440 COLTON OGDEN: Exactly. 1046 00:52:42,440 --> 00:52:44,190 Just take a wild guess and say it subtracts from health. 1047 00:52:44,190 --> 00:52:44,950 It does. 1048 00:52:44,950 --> 00:52:49,330 So entity damage just takes in a number, and subtracts that from health. 1049 00:52:49,330 --> 00:52:50,440 That's all it does. 1050 00:52:50,440 --> 00:52:51,250 Go invulnerable. 1051 00:52:51,250 --> 00:52:52,000 What does that do. 1052 00:52:52,000 --> 00:52:53,724 1053 00:52:53,724 --> 00:52:56,390 AUDIENCE: Means you've been taking damage for that many seconds? 1054 00:52:56,390 --> 00:52:57,306 COLTON OGDEN: It does. 1055 00:52:57,306 --> 00:52:59,890 It prevents you from taking damage for that many seconds. 1056 00:52:59,890 --> 00:53:04,990 All that really does is just set a flag, which I've alluded to quite a bit 1057 00:53:04,990 --> 00:53:09,610 already, an arbitrary flag that you can model via data or some other means. 1058 00:53:09,610 --> 00:53:11,770 Every entity has an invulnerable flag. 1059 00:53:11,770 --> 00:53:14,920 And if it's invulnerable, then the engine should look for that, 1060 00:53:14,920 --> 00:53:19,940 and change the rendering, and the mechanics of the entity accordingly. 1061 00:53:19,940 --> 00:53:22,990 And then lastly here, just simple if the player health is equal to 0, 1062 00:53:22,990 --> 00:53:27,040 which it might be after we take sufficient damage, change to Game Over. 1063 00:53:27,040 --> 00:53:28,210 That's all it does. 1064 00:53:28,210 --> 00:53:33,280 And then for every object, just as we do with every entity, update the object 1065 00:53:33,280 --> 00:53:37,450 and if the player collides with it, then trigger its On Collide function. 1066 00:53:37,450 --> 00:53:40,667 And this can be a function that you arbitrarily create, 1067 00:53:40,667 --> 00:53:42,250 depending on the needs of your object. 1068 00:53:42,250 --> 00:53:44,920 1069 00:53:44,920 --> 00:53:48,550 If you look up here, for example, every time we create a room, 1070 00:53:48,550 --> 00:53:51,400 we generate objects in the room. 1071 00:53:51,400 --> 00:53:55,570 We insert into objects a switch, which we saw before, in gameobjects.lua. 1072 00:53:55,570 --> 00:53:57,830 And takes an x and a y. 1073 00:53:57,830 --> 00:53:59,830 In this case, we just make sure that the x and y 1074 00:53:59,830 --> 00:54:01,950 is a random number between the top left of the map 1075 00:54:01,950 --> 00:54:06,610 and the bottom right of the map, within the padding that it has. 1076 00:54:06,610 --> 00:54:09,200 We get a reference to that object. 1077 00:54:09,200 --> 00:54:11,930 And then we define are On Collide function. 1078 00:54:11,930 --> 00:54:14,620 So what we do is we say if it's upressed, 1079 00:54:14,620 --> 00:54:19,030 so recall that we have a state in the game object definition. 1080 00:54:19,030 --> 00:54:21,810 If it's unpressed, change it to pressed. 1081 00:54:21,810 --> 00:54:23,410 It's all we really need to do. 1082 00:54:23,410 --> 00:54:26,410 And then notice here, for k, a doorway. 1083 00:54:26,410 --> 00:54:31,720 So for every doorway in doorways, self.doorways, set that doorway open 1084 00:54:31,720 --> 00:54:33,460 is true. 1085 00:54:33,460 --> 00:54:35,020 And then play a door sound. 1086 00:54:35,020 --> 00:54:38,260 So our On Collide function just interacts 1087 00:54:38,260 --> 00:54:41,080 with other things in the game world, and just very simple things 1088 00:54:41,080 --> 00:54:46,180 but has a pretty interesting sort of mechanic. 1089 00:54:46,180 --> 00:54:46,989 Like we have a-- 1090 00:54:46,989 --> 00:54:49,780 I took damage off the bat there, because my spawning isn't perfect. 1091 00:54:49,780 --> 00:54:55,250 But it changed from-- notice that it changed its state from unpressed 1092 00:54:55,250 --> 00:54:56,310 to pressed. 1093 00:54:56,310 --> 00:54:57,995 Because it went from the one sprite to-- 1094 00:54:57,995 --> 00:54:59,870 I'll go into another room so we can see that. 1095 00:54:59,870 --> 00:55:01,050 I'll take some damage on the way. 1096 00:55:01,050 --> 00:55:01,841 Go to another room. 1097 00:55:01,841 --> 00:55:03,180 Notice the sprite. 1098 00:55:03,180 --> 00:55:06,110 It sort of looks like it's unpressed, right? 1099 00:55:06,110 --> 00:55:08,520 Because the game object's default state is unpressed. 1100 00:55:08,520 --> 00:55:13,050 And then On Collide triggers when I go on top of it. 1101 00:55:13,050 --> 00:55:16,530 It changes state, which has an effect on what gets rendered. 1102 00:55:16,530 --> 00:55:18,960 And it's On Collide function is called, which 1103 00:55:18,960 --> 00:55:21,210 opened up every doorway in the room. 1104 00:55:21,210 --> 00:55:25,230 So simple like 15 lines of code. 1105 00:55:25,230 --> 00:55:29,160 But pretty compelling, interesting behavior for the sake of our dungeon. 1106 00:55:29,160 --> 00:55:31,310 Like, it adds a lot, as simple as that is. 1107 00:55:31,310 --> 00:55:33,060 Now we sort of feel like we're interacting 1108 00:55:33,060 --> 00:55:35,400 with our game world a little bit. 1109 00:55:35,400 --> 00:55:38,970 So that's how that works. 1110 00:55:38,970 --> 00:55:42,750 And then lastly, rendering on line 188. 1111 00:55:42,750 --> 00:55:45,660 Just go through all of our tiles, render all the tiles. 1112 00:55:45,660 --> 00:55:47,190 We've seen this before. 1113 00:55:47,190 --> 00:55:49,380 Render all the doorways, render all the objects, 1114 00:55:49,380 --> 00:55:52,270 render all the entities, if they're not dead. 1115 00:55:52,270 --> 00:55:52,770 Right? 1116 00:55:52,770 --> 00:55:55,980 If they're dead, then don't render them. 1117 00:55:55,980 --> 00:55:59,820 And then this bit here, we'll take a look at the end, which is stenciling. 1118 00:55:59,820 --> 00:56:03,794 So notice that when I walk through doors. 1119 00:56:03,794 --> 00:56:06,960 Well first of all, notice that I can't walk through doors if they're closed, 1120 00:56:06,960 --> 00:56:07,751 which is important. 1121 00:56:07,751 --> 00:56:13,380 So when you collide with your doorway objects, if doorway.Open is false, 1122 00:56:13,380 --> 00:56:16,080 it shouldn't trigger the room switch, right? 1123 00:56:16,080 --> 00:56:19,440 But if I open the doors they're now all set to recall. 1124 00:56:19,440 --> 00:56:21,120 Door.open is now equal to true. 1125 00:56:21,120 --> 00:56:25,200 So they've changed their renderings, and now they're rendering open doorways. 1126 00:56:25,200 --> 00:56:27,960 If I walk through it, notice that it looks as if the player walks 1127 00:56:27,960 --> 00:56:29,580 underneath the tiles. 1128 00:56:29,580 --> 00:56:33,480 But I'm drawing the tiles before the player. 1129 00:56:33,480 --> 00:56:38,430 And one approach that you might think to do 1130 00:56:38,430 --> 00:56:43,740 when sort of creating this believable appearance of walking 1131 00:56:43,740 --> 00:56:45,420 through a doorway, is say OK. 1132 00:56:45,420 --> 00:56:51,130 I'll just render the player after I render before I render the doorways. 1133 00:56:51,130 --> 00:56:51,630 Right? 1134 00:56:51,630 --> 00:56:53,670 So render all the doorways last. 1135 00:56:53,670 --> 00:57:00,270 But it doesn't quite work out, because the sprite actually starts right here. 1136 00:57:00,270 --> 00:57:02,880 So what does somebody think is going to happen if I were 1137 00:57:02,880 --> 00:57:07,340 to draw the doorway after the player? 1138 00:57:07,340 --> 00:57:11,020 AUDIENCE: Your default player disappears if you cross that line or [INAUDIBLE] 1139 00:57:11,020 --> 00:57:11,645 over that line. 1140 00:57:11,645 --> 00:57:12,561 COLTON OGDEN: Exactly. 1141 00:57:12,561 --> 00:57:15,840 The player would disappear as soon as he gets to this little bit of line right 1142 00:57:15,840 --> 00:57:17,298 here, which is not very convincing. 1143 00:57:17,298 --> 00:57:21,180 And actually I'll try right now to take away the stenciling, 1144 00:57:21,180 --> 00:57:23,110 so we can see what that looks like. 1145 00:57:23,110 --> 00:57:29,050 So if I just take away the stenciling here, and then I just render. 1146 00:57:29,050 --> 00:57:33,490 1147 00:57:33,490 --> 00:57:36,030 Can't type today. 1148 00:57:36,030 --> 00:57:37,890 So I'm going to go ahead. 1149 00:57:37,890 --> 00:57:38,500 Do that. 1150 00:57:38,500 --> 00:57:42,410 1151 00:57:42,410 --> 00:57:47,530 Well, first of all, the rendering order is such that now the doorways render 1152 00:57:47,530 --> 00:57:49,120 after before the player. 1153 00:57:49,120 --> 00:57:51,220 So he just walks right over them, right? 1154 00:57:51,220 --> 00:57:53,560 So I'm just walking, I was walking over the walls. 1155 00:57:53,560 --> 00:57:54,730 That's not compelling. 1156 00:57:54,730 --> 00:57:58,970 And if I were to do something as simple as change the rendering order. 1157 00:57:58,970 --> 00:58:00,990 So right now, the doorways render first. 1158 00:58:00,990 --> 00:58:03,490 I'll just render the doorways after the player. 1159 00:58:03,490 --> 00:58:09,137 So right here, I took that out, right? 1160 00:58:09,137 --> 00:58:10,510 No. 1161 00:58:10,510 --> 00:58:12,376 So right now, they render before the player. 1162 00:58:12,376 --> 00:58:14,000 I want to render them after the player. 1163 00:58:14,000 --> 00:58:18,100 And I'm going to just run it. 1164 00:58:18,100 --> 00:58:21,070 And then going to step on the switch. 1165 00:58:21,070 --> 00:58:22,960 And then, yep. 1166 00:58:22,960 --> 00:58:24,700 Notice we get some weird behavior, too. 1167 00:58:24,700 --> 00:58:27,400 1168 00:58:27,400 --> 00:58:32,170 Like sees his head is getting cut off? 1169 00:58:32,170 --> 00:58:36,790 And other entities as well, right? 1170 00:58:36,790 --> 00:58:39,550 In that case, I couldn't really tell. 1171 00:58:39,550 --> 00:58:41,830 But yeah. 1172 00:58:41,830 --> 00:58:43,330 Very weird rending behavior. 1173 00:58:43,330 --> 00:58:47,590 And what we do to fix that is we create what's called a stencil. 1174 00:58:47,590 --> 00:58:51,490 So basically I'll try and get a screenshot here I can show. 1175 00:58:51,490 --> 00:58:55,880 First let me fix the changes that I just made. 1176 00:58:55,880 --> 00:58:57,230 Right. 1177 00:58:57,230 --> 00:59:01,645 And then if I go back into the code here. 1178 00:59:01,645 --> 00:59:04,520 So a stencil is just-- and we'll see a slide on this in a little bit. 1179 00:59:04,520 --> 00:59:10,310 But a stencil is just basically any sort of arbitrary shape that want, 1180 00:59:10,310 --> 00:59:12,080 that you draw onto the screen. 1181 00:59:12,080 --> 00:59:17,690 It's invisible, but it determines whatever 1182 00:59:17,690 --> 00:59:20,330 gets drawn on top of that stencil, it determines whether or not 1183 00:59:20,330 --> 00:59:21,830 that thing gets rendered. 1184 00:59:21,830 --> 00:59:28,260 So I have a stencil going basically from here onwards to the next room. 1185 00:59:28,260 --> 00:59:30,344 So right about where the doorway hits the archway, 1186 00:59:30,344 --> 00:59:32,260 because that's where we want the player's head 1187 00:59:32,260 --> 00:59:33,410 to look like it disappears. 1188 00:59:33,410 --> 00:59:34,850 Stencil going here. 1189 00:59:34,850 --> 00:59:37,340 I have a stencil going right here. 1190 00:59:37,340 --> 00:59:38,370 And right here. 1191 00:59:38,370 --> 00:59:40,290 And on the right side as well. 1192 00:59:40,290 --> 00:59:42,230 And what that does is I've set the stencil 1193 00:59:42,230 --> 00:59:47,120 to say whatever passes through this stencil during the sort 1194 00:59:47,120 --> 00:59:50,480 of stencil testing period which is, well all we do is we just 1195 00:59:50,480 --> 00:59:52,130 draw the player during that time. 1196 00:59:52,130 --> 00:59:55,820 But basically if it's on the stencil, don't render it. 1197 00:59:55,820 --> 00:59:58,190 And so it what that has the effect of is we still 1198 00:59:58,190 --> 01:00:00,170 draw the doorways before the player. 1199 01:00:00,170 --> 01:00:03,210 So the player walks in and he's drawn above this part. 1200 01:00:03,210 --> 01:00:05,900 But as soon as he hits the stencil, he's not drawn. 1201 01:00:05,900 --> 01:00:07,970 It just-- all those, basically what it does 1202 01:00:07,970 --> 01:00:15,290 is it draws the character to the stencil, and not to the actual canvas. 1203 01:00:15,290 --> 01:00:19,700 And so we get if you want convincing layered, weird, visual effects 1204 01:00:19,700 --> 01:00:23,070 like that, stenciling is an approach. 1205 01:00:23,070 --> 01:00:23,570 OK. 1206 01:00:23,570 --> 01:00:24,830 And then that's all this. 1207 01:00:24,830 --> 01:00:28,040 So this stencil function, love.graphics.stencil, 1208 01:00:28,040 --> 01:00:29,450 takes in a function. 1209 01:00:29,450 --> 01:00:32,442 This is what's going to run during the actual stenciling process. 1210 01:00:32,442 --> 01:00:33,275 It's going to draw-- 1211 01:00:33,275 --> 01:00:34,550 I draw four rectangles. 1212 01:00:34,550 --> 01:00:39,061 All those rectangles are just those archways. 1213 01:00:39,061 --> 01:00:39,560 Right? 1214 01:00:39,560 --> 01:00:43,970 Perfectly layered over them such that it goes into the next room. 1215 01:00:43,970 --> 01:00:47,560 And then we do. 1216 01:00:47,560 --> 01:00:49,610 Notice that it says Replace, and then 1. 1217 01:00:49,610 --> 01:00:53,630 So we replace any pixel that gets drawn to that stencil 1218 01:00:53,630 --> 01:00:55,610 with the stencil value of 1. 1219 01:00:55,610 --> 01:01:00,931 And then we only draw things that are less than 1 during the stencil test. 1220 01:01:00,931 --> 01:01:03,680 Which means anything that didn't get ascribed to value of 1, which 1221 01:01:03,680 --> 01:01:05,900 means that if the player went over the stencil, 1222 01:01:05,900 --> 01:01:07,972 got a pixel value of 1, that's going to be false. 1223 01:01:07,972 --> 01:01:09,680 He's not going to be drawn to the screen. 1224 01:01:09,680 --> 01:01:10,648 Yes? 1225 01:01:10,648 --> 01:01:15,488 AUDIENCE: So you are stenciling, if you created a different shape, 1226 01:01:15,488 --> 01:01:20,417 you could use that, for say, like a light system, some areas are dark, 1227 01:01:20,417 --> 01:01:21,292 some areas are light? 1228 01:01:21,292 --> 01:01:26,392 COLTON OGDEN: Good question was if you have a stencil, because you 1229 01:01:26,392 --> 01:01:28,100 can do with an arbitrary shape, you could 1230 01:01:28,100 --> 01:01:32,240 create lighting systems where some areas are dark, and some areas are light. 1231 01:01:32,240 --> 01:01:34,600 I want to say possibly. 1232 01:01:34,600 --> 01:01:38,990 The thing is, I'm not 100% sure whether stenciling allows you to do, 1233 01:01:38,990 --> 01:01:44,940 whether love 2D stenciling allows you to do arbitrary numbers. 1234 01:01:44,940 --> 01:01:48,320 I basically am not sure if it's on or off, or a gradient. 1235 01:01:48,320 --> 01:01:51,110 Typically, if I were to do our lighting system like that, 1236 01:01:51,110 --> 01:01:54,560 I would probably draw a faux lighting system. 1237 01:01:54,560 --> 01:01:57,830 One, you can use a lighting kit, like box 1238 01:01:57,830 --> 01:02:01,310 2D lights, which does really compelling, cool lights for you. 1239 01:02:01,310 --> 01:02:05,150 Or sort of a cruder way to do it, but possibly realistic, 1240 01:02:05,150 --> 01:02:12,020 would be to draw a shape that fits whatever you want to be your darkness, 1241 01:02:12,020 --> 01:02:16,330 and then render it at an opacity that's less than 100%. 1242 01:02:16,330 --> 01:02:20,240 So you'd have a room, and let's say maybe to sides of it 1243 01:02:20,240 --> 01:02:21,950 are kind of shadowy. 1244 01:02:21,950 --> 01:02:24,320 You draw black rectangles there, right? 1245 01:02:24,320 --> 01:02:28,250 But instead of drawing those black rectangles at 255 alpha, 1246 01:02:28,250 --> 01:02:31,950 you draw them at 200 or 150, or something like that. 1247 01:02:31,950 --> 01:02:33,950 And so you can still see what's underneath them, 1248 01:02:33,950 --> 01:02:37,790 but it looks as if they are a shadow. 1249 01:02:37,790 --> 01:02:40,040 And you can use gradient effects to do the same thing. 1250 01:02:40,040 --> 01:02:44,240 If you want to have shadow that's darker going lighter, 1251 01:02:44,240 --> 01:02:47,494 I believe you can draw rectangles with a gradient effect in Love 2D. 1252 01:02:47,494 --> 01:02:49,160 I'd have to look into a little bit more. 1253 01:02:49,160 --> 01:02:51,080 But you would look to do something like that. 1254 01:02:51,080 --> 01:02:55,280 Draw a gradient of shadow via some rectangle, or some arbitrary shape, 1255 01:02:55,280 --> 01:02:56,930 to simulate lighting in that case. 1256 01:02:56,930 --> 01:02:59,110 And you could accomplish something similar to that. 1257 01:02:59,110 --> 01:03:02,359 And there are a lot of other crazy cool ways I've seeing lightning done in 2D. 1258 01:03:02,359 --> 01:03:05,759 But that's probably offhand the simplest way that I could think of doing it. 1259 01:03:05,759 --> 01:03:06,258 Cool. 1260 01:03:06,258 --> 01:03:09,440 1261 01:03:09,440 --> 01:03:12,440 So that's stenciling, and that's basically it 1262 01:03:12,440 --> 01:03:16,400 for the dungeon generation, which is arguably the most important part. 1263 01:03:16,400 --> 01:03:19,790 And also we looked earlier at the sort of transition mechanic. 1264 01:03:19,790 --> 01:03:23,154 And we'll look at the transition mechanic a little bit more 1265 01:03:23,154 --> 01:03:23,820 in a little bit. 1266 01:03:23,820 --> 01:03:27,260 But let's take a five minute for right now, and then come back to that 1267 01:03:27,260 --> 01:03:29,820 and see some more stuff. 1268 01:03:29,820 --> 01:03:30,320 All right. 1269 01:03:30,320 --> 01:03:32,717 Welcome back to Lecture 5, Legend of Zelda. 1270 01:03:32,717 --> 01:03:34,550 So before the break, we talked about a bunch 1271 01:03:34,550 --> 01:03:38,880 of different things, dungeon generation being foremost among them. 1272 01:03:38,880 --> 01:03:42,930 Now we'll actually start talking about things like hitboxes and hurtboxes, 1273 01:03:42,930 --> 01:03:44,420 as we can see here on the screen. 1274 01:03:44,420 --> 01:03:47,790 So a hitbox is a rectangle, basically. 1275 01:03:47,790 --> 01:03:50,540 And it's how we've implemented it in the distro. 1276 01:03:50,540 --> 01:03:52,820 But we can see here there's a few different sort 1277 01:03:52,820 --> 01:03:53,940 of rectangles overlapping. 1278 01:03:53,940 --> 01:03:55,650 We have the green rectangles here. 1279 01:03:55,650 --> 01:03:56,890 These are hurtboxes. 1280 01:03:56,890 --> 01:03:58,440 These are where you can get hurt. 1281 01:03:58,440 --> 01:03:59,640 And then this is a hitbox. 1282 01:03:59,640 --> 01:04:01,920 This is where you can hit something. 1283 01:04:01,920 --> 01:04:04,380 And so games, like especially with fighting games, 1284 01:04:04,380 --> 01:04:06,900 in a lot of games of fairly complex interactions, 1285 01:04:06,900 --> 01:04:10,020 and complex entities that have weapons or particles, 1286 01:04:10,020 --> 01:04:11,610 things like that all do damage. 1287 01:04:11,610 --> 01:04:15,180 You'll see a lot of complicated overlapping, 1288 01:04:15,180 --> 01:04:18,974 and arrangement of these rectangles that sort of bring about 1289 01:04:18,974 --> 01:04:21,390 how things interact with each other in terms of collision, 1290 01:04:21,390 --> 01:04:24,450 and doing damage, and affecting other entities. 1291 01:04:24,450 --> 01:04:29,220 In this case, he's doing an attack that goes from the left to the right. 1292 01:04:29,220 --> 01:04:30,390 It's a low attack. 1293 01:04:30,390 --> 01:04:33,104 Only his foot, essentially, a little bit inwards. 1294 01:04:33,104 --> 01:04:36,270 But essentially his foot does damage, whereas the rest of him is vulnerable. 1295 01:04:36,270 --> 01:04:39,520 If someone were to come up to him from up above and attack him, 1296 01:04:39,520 --> 01:04:41,440 it would do some damage. 1297 01:04:41,440 --> 01:04:45,600 And there's Minecraft, and it shows you how the same sort of principle 1298 01:04:45,600 --> 01:04:48,130 applies to 3D games as well. 1299 01:04:48,130 --> 01:04:53,070 In this case, what you see there are all hurtboxes. 1300 01:04:53,070 --> 01:04:54,750 Those are all aware things can get hurt. 1301 01:04:54,750 --> 01:04:57,301 Even though those are few of those things are items, 1302 01:04:57,301 --> 01:05:00,300 so that only really affects whether or not the player collides with them 1303 01:05:00,300 --> 01:05:01,860 and picks them up. 1304 01:05:01,860 --> 01:05:07,380 But that's basically the difference between hitboxes and hurtboxes. 1305 01:05:07,380 --> 01:05:10,410 The distro I think I accidentally called the file hurtbox. 1306 01:05:10,410 --> 01:05:13,380 So when I push it up, it's going to be renamed hitbox, 1307 01:05:13,380 --> 01:05:15,070 because that's what we use it for. 1308 01:05:15,070 --> 01:05:22,354 But what is offhand in this game, what do we need a hitbox for? 1309 01:05:22,354 --> 01:05:24,270 AUDIENCE: [INAUDIBLE] attacks from the swoord. 1310 01:05:24,270 --> 01:05:25,728 COLTON OGDEN: Attacks with a sword. 1311 01:05:25,728 --> 01:05:28,550 And the reason that we need a hitbox for that is why? 1312 01:05:28,550 --> 01:05:30,540 AUDIENCE: To [INAUDIBLE] the hit. 1313 01:05:30,540 --> 01:05:31,290 COLTON OGDEN: Yes. 1314 01:05:31,290 --> 01:05:35,476 And why can't we just use the player's position x-y width and height? 1315 01:05:35,476 --> 01:05:37,350 AUDIENCE: Because it has a direction as well. 1316 01:05:37,350 --> 01:05:40,225 COLTON OGDEN: Because it has a direction as well, and also it needs-- 1317 01:05:40,225 --> 01:05:41,610 that's essentially its hurtbox. 1318 01:05:41,610 --> 01:05:42,270 Right? 1319 01:05:42,270 --> 01:05:44,170 So those two reasons. 1320 01:05:44,170 --> 01:05:50,310 It has that direction that we need to sort of act as its reference point 1321 01:05:50,310 --> 01:05:54,030 for generating a hit box, to inflict damage on other entities. 1322 01:05:54,030 --> 01:05:56,280 And we need to use the player's main hitbox 1323 01:05:56,280 --> 01:05:58,800 and hurtbox that it already has to see if something 1324 01:05:58,800 --> 01:06:04,030 hit it, the player, maybe from another side, or something like that. 1325 01:06:04,030 --> 01:06:05,670 So let's go ahead and take a look here. 1326 01:06:05,670 --> 01:06:09,090 The main bit of code that deals with the hitbox, in this case, 1327 01:06:09,090 --> 01:06:11,100 is one going to be hurtbox. 1328 01:06:11,100 --> 01:06:11,940 Should be hitbox. 1329 01:06:11,940 --> 01:06:15,390 But we can see this is literally just a rectangle class. 1330 01:06:15,390 --> 01:06:16,790 xy, a width and a height. 1331 01:06:16,790 --> 01:06:20,490 self.x, self.y, self-taught, self.width, self.height equals all those things. 1332 01:06:20,490 --> 01:06:22,860 That's all you need for a hitbox. 1333 01:06:22,860 --> 01:06:26,370 Literally box, just all you need are those fields. 1334 01:06:26,370 --> 01:06:29,051 And then you can do simply collides. 1335 01:06:29,051 --> 01:06:30,050 Just like you do entity. 1336 01:06:30,050 --> 01:06:32,220 Entity collides hurtbox. 1337 01:06:32,220 --> 01:06:33,300 Yes, no, true or false. 1338 01:06:33,300 --> 01:06:38,220 Because recall, collides expects xy width or height. 1339 01:06:38,220 --> 01:06:41,610 And it's defined an entity.lua. 1340 01:06:41,610 --> 01:06:45,180 So if we go up to the player states. 1341 01:06:45,180 --> 01:06:48,240 So recall, last week we introduced the idea 1342 01:06:48,240 --> 01:06:51,240 of having the player maintain its own collection of states, 1343 01:06:51,240 --> 01:06:52,350 in a state machine. 1344 01:06:52,350 --> 01:06:55,740 As opposed to just the game world having a state machine that 1345 01:06:55,740 --> 01:06:57,960 influences whether we're at the Start screen, 1346 01:06:57,960 --> 01:07:03,750 the Play State screen, whatever we want to divide our game up into. 1347 01:07:03,750 --> 01:07:06,190 We have entities states as well. 1348 01:07:06,190 --> 01:07:09,660 Now one of those is the-- so we have the idle in the walk state. 1349 01:07:09,660 --> 01:07:14,467 Those are so very similar to last week's, where the idle state, they're 1350 01:07:14,467 --> 01:07:15,300 just standing still. 1351 01:07:15,300 --> 01:07:19,020 And the walking state they're moving and their animation changes accordingly. 1352 01:07:19,020 --> 01:07:23,520 The swing sword state is a new state, and what this does 1353 01:07:23,520 --> 01:07:26,190 is the player presses spacebar. 1354 01:07:26,190 --> 01:07:28,620 It triggers this swing sword state. 1355 01:07:28,620 --> 01:07:29,880 There's a new animation. 1356 01:07:29,880 --> 01:07:34,290 So we go into the swing sword animation, relative to which direction we're in. 1357 01:07:34,290 --> 01:07:40,680 And we get that direction and then we calculate the xy width and height 1358 01:07:40,680 --> 01:07:42,310 of whatever our hurtbox. 1359 01:07:42,310 --> 01:07:46,110 Should be hitbox, is going to be for the sword. 1360 01:07:46,110 --> 01:07:47,880 When the sword hits something. 1361 01:07:47,880 --> 01:07:51,990 So that hitbox, if it's facing the left, it's 1362 01:07:51,990 --> 01:07:54,540 going to be 8 pixels wide by 16 tall, which 1363 01:07:54,540 --> 01:07:57,090 is roughly the left side of the player. 1364 01:07:57,090 --> 01:08:00,870 And then we just calculate the x and y depending on which position we're in. 1365 01:08:00,870 --> 01:08:05,520 It should be roughly centered based on whatever direction the player is 1366 01:08:05,520 --> 01:08:06,940 looking at. 1367 01:08:06,940 --> 01:08:10,230 And so we then instantiate that hurtbox here. 1368 01:08:10,230 --> 01:08:13,590 We call it a self.swordhurtbox. 1369 01:08:13,590 --> 01:08:16,430 And then all we really need to do is what? 1370 01:08:16,430 --> 01:08:20,357 In our game loop to check to see if we've hit an entity? 1371 01:08:20,357 --> 01:08:26,430 1372 01:08:26,430 --> 01:08:32,340 We just need to loop over the entities in our room, the current room right? 1373 01:08:32,340 --> 01:08:32,970 Here. 1374 01:08:32,970 --> 01:08:37,319 So every entity in the dungeon's current room.entities. 1375 01:08:37,319 --> 01:08:40,859 If the entity collides with our sword hurtbox, sword hitbox, 1376 01:08:40,859 --> 01:08:45,420 then, we saw this method before, entity damage one. 1377 01:08:45,420 --> 01:08:47,247 And then hit enemy play. 1378 01:08:47,247 --> 01:08:48,330 That's as simple as it is. 1379 01:08:48,330 --> 01:08:54,540 And recall, in room.Lua, if an entity's health dropped below one, dropped to 0, 1380 01:08:54,540 --> 01:08:56,640 it would just trigger it to become dead. 1381 01:08:56,640 --> 01:08:57,689 Right? 1382 01:08:57,689 --> 01:09:00,430 And so that's all we need effectively. 1383 01:09:00,430 --> 01:09:02,910 And then we have some additional logic to make sure 1384 01:09:02,910 --> 01:09:04,890 that the animation only plays one time. 1385 01:09:04,890 --> 01:09:10,290 And then once it has played one time, change its state to idle. 1386 01:09:10,290 --> 01:09:13,500 And then we can press spacebar repeatedly within that same state, 1387 01:09:13,500 --> 01:09:15,300 just to keep swinging if we want to. 1388 01:09:15,300 --> 01:09:18,540 And it will just restart the animation, and restart 1389 01:09:18,540 --> 01:09:20,399 the hitbox being instantiated. 1390 01:09:20,399 --> 01:09:23,519 And so that's all we really need to do for that. 1391 01:09:23,519 --> 01:09:26,310 Now I have some lines of code here at the bottom of the sword swing 1392 01:09:26,310 --> 01:09:27,569 state.lua. 1393 01:09:27,569 --> 01:09:30,029 And player swords, swings swords state. 1394 01:09:30,029 --> 01:09:32,939 And what these do is sometimes it's useful 1395 01:09:32,939 --> 01:09:36,563 when you're programming to sort of see where your collision boxes are, right? 1396 01:09:36,563 --> 01:09:39,479 Because you don't necessarily know if everything's lined up perfectly. 1397 01:09:39,479 --> 01:09:41,937 When you're detecting collision between different entities, 1398 01:09:41,937 --> 01:09:44,939 you want to just check to see are the rectangles actually overlapping 1399 01:09:44,939 --> 01:09:46,229 when this triggers? 1400 01:09:46,229 --> 01:09:50,189 So all you need to do in order to visually see this at a glance, 1401 01:09:50,189 --> 01:09:54,690 and you may have seen this before, in other games or debug modes of games, 1402 01:09:54,690 --> 01:09:57,357 is just draw a line rectangles. 1403 01:09:57,357 --> 01:10:00,690 And then just give them the xy width and height that you want to look at, right? 1404 01:10:00,690 --> 01:10:04,710 So here, I'm going to go ahead and save this. 1405 01:10:04,710 --> 01:10:06,225 And then I'm going to run the-- 1406 01:10:06,225 --> 01:10:08,640 I've basically uncommented it. 1407 01:10:08,640 --> 01:10:10,800 Because by default, I don't want it showing. 1408 01:10:10,800 --> 01:10:13,440 They're pink rectangles, I don't want them displayed on screen, 1409 01:10:13,440 --> 01:10:14,880 unless I want to do debugging. 1410 01:10:14,880 --> 01:10:18,030 So I'm going to uncomment them down here. 1411 01:10:18,030 --> 01:10:20,460 Notice it sets the color to 255, 0 255. 1412 01:10:20,460 --> 01:10:22,170 That's magenta. 1413 01:10:22,170 --> 01:10:23,914 I'm going to run this. 1414 01:10:23,914 --> 01:10:25,225 [MUSIC PLAYING] 1415 01:10:25,225 --> 01:10:26,790 Turn that down a little bit. 1416 01:10:26,790 --> 01:10:28,980 Nothing looks particularly different. 1417 01:10:28,980 --> 01:10:34,170 But when I swing my sword, notice that there's a little rectangle. 1418 01:10:34,170 --> 01:10:37,170 And the rectangles aren't 100% perfect necessarily. 1419 01:10:37,170 --> 01:10:39,630 They give the player little bit of an advantage. 1420 01:10:39,630 --> 01:10:42,930 Like up above, like his hitbox is barely anything. 1421 01:10:42,930 --> 01:10:47,370 Up above, in the actual animation, but in the collision, 1422 01:10:47,370 --> 01:10:52,310 I give it quite a wide berth. 1423 01:10:52,310 --> 01:10:54,270 And so that's how you can, at a glance, sort of 1424 01:10:54,270 --> 01:10:57,400 see whether your things are interacting appropriately. 1425 01:10:57,400 --> 01:10:58,330 There's lines of code. 1426 01:10:58,330 --> 01:11:01,170 I did the same thing for the other states, the entity, walking, 1427 01:11:01,170 --> 01:11:02,100 and idle states. 1428 01:11:02,100 --> 01:11:05,222 If you want to sort of look at those, and see not only the player 1429 01:11:05,222 --> 01:11:08,430 swinging the sword, but also the other entities, and the collision boxes they 1430 01:11:08,430 --> 01:11:11,820 have, and just to check whether or not they're overlapping appropriately, 1431 01:11:11,820 --> 01:11:14,040 or to change them, or do whatever you want with them. 1432 01:11:14,040 --> 01:11:15,345 But that's a nice way to do-- 1433 01:11:15,345 --> 01:11:17,220 sometimes it's hard to debug collision if you 1434 01:11:17,220 --> 01:11:18,930 can't see exactly what's going on. 1435 01:11:18,930 --> 01:11:22,500 Because it's often just in terms of xy width and height, so on and so forth, 1436 01:11:22,500 --> 01:11:23,950 with offsets and such. 1437 01:11:23,950 --> 01:11:27,180 It can be kind of a pain and/or sort of difficult 1438 01:11:27,180 --> 01:11:28,680 to track down certain bugs that way. 1439 01:11:28,680 --> 01:11:31,229 So just draw to the screen. 1440 01:11:31,229 --> 01:11:34,020 You can apply that same logic to a lot of things in your game world 1441 01:11:34,020 --> 01:11:38,970 that may be hidden, but you want to see sort of visually just draw shapes 1442 01:11:38,970 --> 01:11:40,440 or draw different things for them. 1443 01:11:40,440 --> 01:11:42,310 So you can see what's going on. 1444 01:11:42,310 --> 01:11:47,160 So that's how the hitbox and hurtbox work for our player. 1445 01:11:47,160 --> 01:11:50,706 And you can easily just spawn more hitboxes for other entities 1446 01:11:50,706 --> 01:11:51,330 if you want to. 1447 01:11:51,330 --> 01:11:53,940 If you wanted to give them states, or maybe 1448 01:11:53,940 --> 01:11:57,750 you want to create projectiles that are offensive. 1449 01:11:57,750 --> 01:12:01,680 Maybe just create projectiles, and then shoot projectiles 1450 01:12:01,680 --> 01:12:06,360 in a specific direction, but assign a hitbox to that projectile, 1451 01:12:06,360 --> 01:12:07,660 if you want to. 1452 01:12:07,660 --> 01:12:10,200 Or just use the projectiles xy width and height, 1453 01:12:10,200 --> 01:12:12,270 and then you can calculate a collision that way. 1454 01:12:12,270 --> 01:12:14,550 Just treat it like a game object, or an entity. 1455 01:12:14,550 --> 01:12:15,780 It's up to you. 1456 01:12:15,780 --> 01:12:18,700 Or a separate class all together. 1457 01:12:18,700 --> 01:12:21,000 But that's hitboxes and hurtboxes in a nutshell. 1458 01:12:21,000 --> 01:12:23,400 Anybody have any questions as to how those sort of work? 1459 01:12:23,400 --> 01:12:25,950 1460 01:12:25,950 --> 01:12:27,490 OK, cool. 1461 01:12:27,490 --> 01:12:29,360 So let's go on to the next topic. 1462 01:12:29,360 --> 01:12:30,490 So events. 1463 01:12:30,490 --> 01:12:32,260 So I spoke of this earlier. 1464 01:12:32,260 --> 01:12:35,860 Events are just a nice way to sort of say when something 1465 01:12:35,860 --> 01:12:39,550 happens, do this block of code. 1466 01:12:39,550 --> 01:12:40,910 And you can do this anywhere. 1467 01:12:40,910 --> 01:12:44,290 And you can decouple it from like maybe two different objects 1468 01:12:44,290 --> 01:12:45,430 interact with each other. 1469 01:12:45,430 --> 01:12:48,130 But you don't want them to sort of pass references 1470 01:12:48,130 --> 01:12:51,130 back and forth between each other, and bloat your code. 1471 01:12:51,130 --> 01:12:55,660 Maybe you want the code for that check to happen not inside your main loop. 1472 01:12:55,660 --> 01:12:58,870 You want to sort of abstract it out to some sort of other function, 1473 01:12:58,870 --> 01:13:00,640 like instantiated events. 1474 01:13:00,640 --> 01:13:02,950 And then have your main rendering and update logic 1475 01:13:02,950 --> 01:13:06,077 be free of all this conditional stuff. 1476 01:13:06,077 --> 01:13:06,910 So you create event. 1477 01:13:06,910 --> 01:13:12,400 You say on some event, so maybe like on player walk, 1478 01:13:12,400 --> 01:13:14,592 and then you just update some, maybe a label 1479 01:13:14,592 --> 01:13:17,050 on the top right of the screen, that gives the player's xy. 1480 01:13:17,050 --> 01:13:20,286 And you just say that xy is equal to that player's xy. 1481 01:13:20,286 --> 01:13:22,660 I mean, aside from the fact that you could just literally 1482 01:13:22,660 --> 01:13:24,144 draw the player's xy. 1483 01:13:24,144 --> 01:13:25,310 But it's the same principle. 1484 01:13:25,310 --> 01:13:30,370 You can update some value somewhere separate from another entity. 1485 01:13:30,370 --> 01:13:34,750 And then just wait for an event, arbitrarily defined event, 1486 01:13:34,750 --> 01:13:37,100 that you then broadcast later. 1487 01:13:37,100 --> 01:13:39,460 So let's say I want a broadcast swing sword. 1488 01:13:39,460 --> 01:13:40,840 I have a swing sword event. 1489 01:13:40,840 --> 01:13:42,790 So whenever the player presses space, not only 1490 01:13:42,790 --> 01:13:46,120 do they do all the code that we saw before, but they swing sword. 1491 01:13:46,120 --> 01:13:50,035 And then we say when you swing sword, pass in the xy of wherever they swung 1492 01:13:50,035 --> 01:13:51,010 the sword. 1493 01:13:51,010 --> 01:13:55,300 And so then you can say OK, on swing sword, look at all the entities, 1494 01:13:55,300 --> 01:13:58,344 and see whether or not the hitbox at xy collides with them. 1495 01:13:58,344 --> 01:14:01,510 And you can sort of take out the logic from where you had it before, and put 1496 01:14:01,510 --> 01:14:03,370 it in some other centralized location. 1497 01:14:03,370 --> 01:14:04,690 If you want to. 1498 01:14:04,690 --> 01:14:09,760 More representative of this model is the idea of an achievement system, 1499 01:14:09,760 --> 01:14:11,920 where instead of every frame, and you can 1500 01:14:11,920 --> 01:14:14,600 have-- games have a ridiculous number of achievements. 1501 01:14:14,600 --> 01:14:16,510 Some games have like 1,000 achievements. 1502 01:14:16,510 --> 01:14:19,210 You don't want to put the test for every one of those 1,000 1503 01:14:19,210 --> 01:14:23,110 achievements necessarily inside of your update logic, right? 1504 01:14:23,110 --> 01:14:26,297 You can instead just broadcast an event for all 1505 01:14:26,297 --> 01:14:29,380 of the different things that influence whether those achievements are met. 1506 01:14:29,380 --> 01:14:34,210 So whether a player needs to get 100 kills in a game, or 100 coins. 1507 01:14:34,210 --> 01:14:36,460 Whether they need to jump off some ledge. 1508 01:14:36,460 --> 01:14:38,770 You just have events that model all these interactions. 1509 01:14:38,770 --> 01:14:41,350 Event on, pick-up coin, do this. 1510 01:14:41,350 --> 01:14:45,820 Increment some time, some counter that's stored somewhere else. 1511 01:14:45,820 --> 01:14:47,965 Event.on, kill creature. 1512 01:14:47,965 --> 01:14:51,250 Or kill creature triggers every time you, 1513 01:14:51,250 --> 01:14:56,170 literally a creature is sent from as false to dead as true. 1514 01:14:56,170 --> 01:14:58,690 1515 01:14:58,690 --> 01:15:03,550 Maybe whenever the player jumps, you do an on jump function. 1516 01:15:03,550 --> 01:15:06,040 And then you can test to see whether or not-- in that code, 1517 01:15:06,040 --> 01:15:08,350 you can test to see whether they jumped off that ledge. 1518 01:15:08,350 --> 01:15:11,149 And then if that happens, you have your achievement system, 1519 01:15:11,149 --> 01:15:12,940 but you don't have all these if statements, 1520 01:15:12,940 --> 01:15:18,040 and all these tests happening inside your sort of imperative game loop. 1521 01:15:18,040 --> 01:15:22,900 You can just pseudo asynchronously check for all of them, 1522 01:15:22,900 --> 01:15:26,590 given a sufficiently detailed event system in your game. 1523 01:15:26,590 --> 01:15:30,430 And so the library that we'll use just to show this a little bit 1524 01:15:30,430 --> 01:15:34,030 is in the knife library, that we saw before with timer. 1525 01:15:34,030 --> 01:15:36,760 Timer.on, timer.every, timer.tween. 1526 01:15:36,760 --> 01:15:38,800 In the knife library, there's a submodule 1527 01:15:38,800 --> 01:15:44,320 called Event, which allows you to call event.on. 1528 01:15:44,320 --> 01:15:45,580 Give it a name and a function. 1529 01:15:45,580 --> 01:15:49,420 So on player jump, off player jump. 1530 01:15:49,420 --> 01:15:50,130 You know? 1531 01:15:50,130 --> 01:15:50,890 Function. 1532 01:15:50,890 --> 01:15:56,830 If Player.Position is by some cliff, or some area that's relevant, 1533 01:15:56,830 --> 01:15:58,630 then call this block of code. 1534 01:15:58,630 --> 01:16:03,040 And increment, or set the achievement to true. 1535 01:16:03,040 --> 01:16:04,470 Event.dispatch. 1536 01:16:04,470 --> 01:16:06,380 Dispatch an event when something happens. 1537 01:16:06,380 --> 01:16:13,150 So if a player jumps, so when they press the spacebar, event.Dispatch jump. 1538 01:16:13,150 --> 01:16:17,027 And then just whatever values that your callback function needs. 1539 01:16:17,027 --> 01:16:19,360 Let's say you want to check to see what is on the cliff. 1540 01:16:19,360 --> 01:16:21,730 Well, if you want to check to see whether they jump off 1541 01:16:21,730 --> 01:16:25,540 that specific cliff, you need to check their xy position, presumably, 1542 01:16:25,540 --> 01:16:28,980 so you can just pass in optional parameters via event.dispatch. 1543 01:16:28,980 --> 01:16:32,380 You can say OK, dispatch the event that the player jumped, 1544 01:16:32,380 --> 01:16:34,810 and say that the player jumped at xy. 1545 01:16:34,810 --> 01:16:37,990 And so this function call back is going to have access to the xy. 1546 01:16:37,990 --> 01:16:41,230 It's going to say OK, on jump, I say I got, 1547 01:16:41,230 --> 01:16:45,730 I'm getting my callback called with player.x player.Y. And it happens to-- 1548 01:16:45,730 --> 01:16:46,990 oh, it's not at the cliff. 1549 01:16:46,990 --> 01:16:48,030 So nothing happens. 1550 01:16:48,030 --> 01:16:54,400 Or it is the cliff, so the achievement, jump off cliff, unlocked is true. 1551 01:16:54,400 --> 01:16:57,304 And test now is not happening every single frame, 1552 01:16:57,304 --> 01:16:58,720 which otherwise would potentially. 1553 01:16:58,720 --> 01:17:03,380 And it's not blocking up your update logic for your player jumping. 1554 01:17:03,380 --> 01:17:03,880 Right? 1555 01:17:03,880 --> 01:17:08,790 The player, the jumping logic inside player, the player jumps state, 1556 01:17:08,790 --> 01:17:10,420 doesn't need to know-- 1557 01:17:10,420 --> 01:17:13,420 doesn't need to ask whether or not we've jumped off a cliff. 1558 01:17:13,420 --> 01:17:17,400 That's something that we should just delegate to our achievement file, 1559 01:17:17,400 --> 01:17:18,410 or whatever you want. 1560 01:17:18,410 --> 01:17:21,070 And that's sort of the flexibility that events afford you. 1561 01:17:21,070 --> 01:17:22,570 So we use event. 1562 01:17:22,570 --> 01:17:24,640 I'll touch on this a little bit briefly here. 1563 01:17:24,640 --> 01:17:38,610 But basically, if we go to the player walk state on line 21.39, first of all 1564 01:17:38,610 --> 01:17:41,260 we're checking for input here. 1565 01:17:41,260 --> 01:17:41,760 Right? 1566 01:17:41,760 --> 01:17:44,790 We're just saying if we press the left, right, up, or down. 1567 01:17:44,790 --> 01:17:50,770 The direction is that walk left, walk right, so on and so forth. 1568 01:17:50,770 --> 01:17:56,530 And then what we do is we call entity walk state.update. 1569 01:17:56,530 --> 01:18:00,790 So this base walk state code that exists in entity, so that we can 1570 01:18:00,790 --> 01:18:04,107 let every single entity have this code. 1571 01:18:04,107 --> 01:18:05,940 All it does just check to see whether or not 1572 01:18:05,940 --> 01:18:09,010 the player or entity that it belongs to hit a wall. 1573 01:18:09,010 --> 01:18:12,460 And if it did, then set there bumped equals true. 1574 01:18:12,460 --> 01:18:17,160 And what it does is just a flag that says, OK, the player bumped a wall. 1575 01:18:17,160 --> 01:18:17,790 OK? 1576 01:18:17,790 --> 01:18:18,900 Why is that relevant? 1577 01:18:18,900 --> 01:18:23,280 Because then, after we call that, we can say, OK, if we bumped a wall, 1578 01:18:23,280 --> 01:18:26,340 and this only happens when the player walk state, 1579 01:18:26,340 --> 01:18:29,550 if we're looking to the left, temporarily adjust our position. 1580 01:18:29,550 --> 01:18:34,590 Because when it bumps you, it knocks you back out back into the world. 1581 01:18:34,590 --> 01:18:39,030 But we're going to re-bump our position into wherever we collided. 1582 01:18:39,030 --> 01:18:41,820 We're going to look at every doorway, and then 1583 01:18:41,820 --> 01:18:46,230 we're going to say if we collided with that doorway, and it's open, 1584 01:18:46,230 --> 01:18:48,845 then we're going to shift it to the center of the doorway 1585 01:18:48,845 --> 01:18:51,720 so that it doesn't look as if the player is walking through the wall. 1586 01:18:51,720 --> 01:18:54,320 We're going to set it to wherever the wall is, 1587 01:18:54,320 --> 01:18:57,510 or wherever the door is, the very center of the doorway. 1588 01:18:57,510 --> 01:19:00,525 And then we're going to call event.Dispatch shift, 1589 01:19:00,525 --> 01:19:02,010 and in that direction. 1590 01:19:02,010 --> 01:19:06,280 So shift left, shift right, shift up, and shift down. 1591 01:19:06,280 --> 01:19:10,710 And so all of these four different cases are going to say OK, 1592 01:19:10,710 --> 01:19:12,480 the player has hit a doorway. 1593 01:19:12,480 --> 01:19:15,510 I have a function somewhere. 1594 01:19:15,510 --> 01:19:18,920 Event.on, shift down, shift left, shift right, shift up. 1595 01:19:18,920 --> 01:19:20,312 That's going to trigger what? 1596 01:19:20,312 --> 01:19:27,070 1597 01:19:27,070 --> 01:19:27,990 The next room. 1598 01:19:27,990 --> 01:19:31,210 It's going to trigger us moving to the next room, and also the next room 1599 01:19:31,210 --> 01:19:34,120 spawning, and the camera sort of shifting position. 1600 01:19:34,120 --> 01:19:38,830 1601 01:19:38,830 --> 01:19:43,480 So the code for this is in dungeon. 1602 01:19:43,480 --> 01:19:45,982 So we're going to go ahead and look at dungeon. 1603 01:19:45,982 --> 01:19:50,620 So right here, on line 29 through 43, event.on, 1604 01:19:50,620 --> 01:19:54,185 shift left, shift right, shift up, shift down. 1605 01:19:54,185 --> 01:19:57,320 And what that does is we have another function called begin shifting, 1606 01:19:57,320 --> 01:19:58,930 which takes in an x and y. 1607 01:19:58,930 --> 01:20:01,786 Negative virtual width, virtual width, negative virtual height, 1608 01:20:01,786 --> 01:20:02,410 virtual height. 1609 01:20:02,410 --> 01:20:06,910 Does anybody recall why we need to pass those numbers in there? 1610 01:20:06,910 --> 01:20:11,560 If we're shifting left, and we're passing a negative virtual width, 1611 01:20:11,560 --> 01:20:16,000 what do you think that number is going to be? 1612 01:20:16,000 --> 01:20:19,350 So recall every room has an adjacent offset x and y 1613 01:20:19,350 --> 01:20:23,970 that renders that room with that offset basically added to it. 1614 01:20:23,970 --> 01:20:25,110 Its x and y. 1615 01:20:25,110 --> 01:20:28,170 So if we begin shifting to the left, negative virtual width 1616 01:20:28,170 --> 01:20:29,340 is going to be the x offset. 1617 01:20:29,340 --> 01:20:35,130 Because that room needs to be rendered a screen width to the left, right? 1618 01:20:35,130 --> 01:20:37,440 And so on for the right, virtual width. 1619 01:20:37,440 --> 01:20:39,180 It adds a virtual width to the x offset. 1620 01:20:39,180 --> 01:20:41,160 The adjacent x offset. 1621 01:20:41,160 --> 01:20:45,780 And then virtual height, negative and positive for shift up, and shift down. 1622 01:20:45,780 --> 01:20:53,910 So begin shifting, basically the gist of this is it's a tween operation. 1623 01:20:53,910 --> 01:21:00,540 So we start here, recall timer.tween, just takes a value and interpolates it. 1624 01:21:00,540 --> 01:21:04,190 So self, we have a camera and a camera y, right? 1625 01:21:04,190 --> 01:21:06,180 Going to equal shift x and shift y. 1626 01:21:06,180 --> 01:21:07,320 Eventually. 1627 01:21:07,320 --> 01:21:10,020 So shift x and shift y being the adjacent offset, that we're 1628 01:21:10,020 --> 01:21:12,420 going to need to shift the camera by. 1629 01:21:12,420 --> 01:21:17,130 So camera x and camera y, they both sort of zero, always. 1630 01:21:17,130 --> 01:21:20,400 When the room gets completely finalized. 1631 01:21:20,400 --> 01:21:23,870 So if the shift x is virtual width, negative virtual width, 1632 01:21:23,870 --> 01:21:25,620 cause we're shifting left, then it's going 1633 01:21:25,620 --> 01:21:30,750 to tween the camera going from right to left over the span of a second, right? 1634 01:21:30,750 --> 01:21:34,620 And then the player, the player x and player y, 1635 01:21:34,620 --> 01:21:39,000 those are basically set up here to the opposite end 1636 01:21:39,000 --> 01:21:41,110 of the room, the next room. 1637 01:21:41,110 --> 01:21:43,230 So if the player is going from the top of the room 1638 01:21:43,230 --> 01:21:47,820 to the bottom of the next room, it needs to get its x and y 1639 01:21:47,820 --> 01:21:51,360 put in that position, the bottom part of the next room. 1640 01:21:51,360 --> 01:21:57,977 Or the left part of the next room, if they're moving from the right, right? 1641 01:21:57,977 --> 01:22:00,060 Or the right part of they're moving from the left. 1642 01:22:00,060 --> 01:22:01,768 And the bottom part if they're moving up. 1643 01:22:01,768 --> 01:22:03,393 And the up part if they're moving down. 1644 01:22:03,393 --> 01:22:04,392 So that's all that does. 1645 01:22:04,392 --> 01:22:06,510 Puts them in the right position, on the next room. 1646 01:22:06,510 --> 01:22:08,940 Tweens both of them, the camera and the player, 1647 01:22:08,940 --> 01:22:11,370 because the player needs to keep moving to the next room. 1648 01:22:11,370 --> 01:22:15,390 And the camera needs to shift up. 1649 01:22:15,390 --> 01:22:17,529 When it's finished, we call finished shifting, 1650 01:22:17,529 --> 01:22:20,070 which is just a function that says basically everything to 0. 1651 01:22:20,070 --> 01:22:23,040 It sets the current room to the next room. 1652 01:22:23,040 --> 01:22:26,130 It sets the camera x and all that stuff all to 0, 1653 01:22:26,130 --> 01:22:28,950 and then all the entities and objects there, it all gets set to 0. 1654 01:22:28,950 --> 01:22:31,170 So they are offset to 0. 1655 01:22:31,170 --> 01:22:33,570 So that everything is basically right at 0.0 1656 01:22:33,570 --> 01:22:35,700 again, just like it was at the very beginning. 1657 01:22:35,700 --> 01:22:38,400 1658 01:22:38,400 --> 01:22:40,890 And then last but not least, when we get into the new room, 1659 01:22:40,890 --> 01:22:42,840 we start with the doors all open. 1660 01:22:42,840 --> 01:22:45,810 And then when we get into the room here, because this is all 1661 01:22:45,810 --> 01:22:48,330 done in the finished function, recall, this 1662 01:22:48,330 --> 01:22:52,080 will only happen after the tween is completed. 1663 01:22:52,080 --> 01:22:54,120 Every doorway is going to get set to false. 1664 01:22:54,120 --> 01:22:55,300 Open equals false. 1665 01:22:55,300 --> 01:22:58,220 So all the doors will close as soon as we get into the next room, 1666 01:22:58,220 --> 01:22:59,970 after we've performed the tween operation. 1667 01:22:59,970 --> 01:23:01,560 And then we'll play a door sound. 1668 01:23:01,560 --> 01:23:06,540 So that's the code involved in actually doing the shift operation. 1669 01:23:06,540 --> 01:23:08,610 So we were able to trigger it. 1670 01:23:08,610 --> 01:23:12,390 We don't have to necessarily do that code from the player walk state. 1671 01:23:12,390 --> 01:23:16,800 We just say if the players collide with the doorway, 1672 01:23:16,800 --> 01:23:20,730 then dispatch an event that is handled by dungeon. 1673 01:23:20,730 --> 01:23:25,890 Because dungeon has access to current room, next room, and all the stuff 1674 01:23:25,890 --> 01:23:28,110 that it needs to actually perform that transition. 1675 01:23:28,110 --> 01:23:31,200 So we have the two that are sort of decoupled but they work well 1676 01:23:31,200 --> 01:23:32,640 in tandem with one another. 1677 01:23:32,640 --> 01:23:35,578 So anybody have questions as to sort of how this works? 1678 01:23:35,578 --> 01:23:38,970 1679 01:23:38,970 --> 01:23:40,400 OK. 1680 01:23:40,400 --> 01:23:42,330 That's essentially the dungeon scrolling. 1681 01:23:42,330 --> 01:23:43,760 It's a tween operation. 1682 01:23:43,760 --> 01:23:46,290 It's a camera, a temporary room gets rendered. 1683 01:23:46,290 --> 01:23:49,130 We move to a temporary room, everything gets set back to 0. 1684 01:23:49,130 --> 01:23:54,080 And then it's just a wild loop of that sort of behavior, effectively. 1685 01:23:54,080 --> 01:23:58,190 And we use the event library to sort of clean up that whole aspect. 1686 01:23:58,190 --> 01:24:01,820 And sort of screen scrolling here, just another demonstration. 1687 01:24:01,820 --> 01:24:04,070 We went over it in detail, but this is a nice GIF 1688 01:24:04,070 --> 01:24:07,160 I found that sort of encapsulates what that means. 1689 01:24:07,160 --> 01:24:09,900 Stenciling is something that we saw earlier. 1690 01:24:09,900 --> 01:24:14,906 And if we look at this as a stencil, so we 1691 01:24:14,906 --> 01:24:17,030 can pretend that these are the circle of the heart, 1692 01:24:17,030 --> 01:24:20,600 and that rectangle are a stencil. 1693 01:24:20,600 --> 01:24:26,630 And then we want to draw this gray rectangle on top of those stencils. 1694 01:24:26,630 --> 01:24:30,330 We can use the stencil to mask out specific parts, which 1695 01:24:30,330 --> 01:24:33,650 would otherwise be pretty tough to do. 1696 01:24:33,650 --> 01:24:36,740 I mean, it's hard to necessarily, maybe individually 1697 01:24:36,740 --> 01:24:41,030 render pixels, or create a shape that sort of looks like this. 1698 01:24:41,030 --> 01:24:43,910 Much easier for a lot of very interesting visual effects 1699 01:24:43,910 --> 01:24:46,970 to use a stencil of arbitrary shape and size. 1700 01:24:46,970 --> 01:24:48,530 And you can use images, too. 1701 01:24:48,530 --> 01:24:51,717 You can use images of stencils, to create some pretty cool effects. 1702 01:24:51,717 --> 01:24:54,050 We went over it before, when I talked about the archway. 1703 01:24:54,050 --> 01:24:56,550 So I won't go over into much more detail. 1704 01:24:56,550 --> 01:25:00,260 But again, you can look at that in the, where was it exactly? 1705 01:25:00,260 --> 01:25:04,070 It was in the room function, room class, sorry. 1706 01:25:04,070 --> 01:25:05,410 Down here at the bottom. 1707 01:25:05,410 --> 01:25:11,870 So lines to 213 to 229 recall they're a stencil function. 1708 01:25:11,870 --> 01:25:14,600 The couple functions in particular that you need to use 1709 01:25:14,600 --> 01:25:18,650 are love.graphics.stencil which draws the stencils, and then 1710 01:25:18,650 --> 01:25:21,830 love.graphics.setstenciltest which compares 1711 01:25:21,830 --> 01:25:25,400 the stencil values to some value, and draws them 1712 01:25:25,400 --> 01:25:27,210 whether or not that condition is true. 1713 01:25:27,210 --> 01:25:31,730 So we have our function here, which draws four rectangles. 1714 01:25:31,730 --> 01:25:33,410 Those are all the archways. 1715 01:25:33,410 --> 01:25:37,220 It replaces any pixels that get drawn to those rectangles with the value 1. 1716 01:25:37,220 --> 01:25:39,620 The stencil value 1, so stencil value is just 1717 01:25:39,620 --> 01:25:44,870 like a hidden value that determines whether a image will get 1718 01:25:44,870 --> 01:25:47,210 drawn if it's being stenciled or not. 1719 01:25:47,210 --> 01:25:52,940 Set stencil test means that we're looking for anything less than 1. 1720 01:25:52,940 --> 01:25:54,222 And we'll draw that. 1721 01:25:54,222 --> 01:25:56,180 And because the player is going to be 1 if it's 1722 01:25:56,180 --> 01:26:00,530 on any of those stencil rectangles, it will not 1723 01:26:00,530 --> 01:26:03,270 draw the player if it overlaps with those stencil rectangles. 1724 01:26:03,270 --> 01:26:05,150 And so that's in general how it works. 1725 01:26:05,150 --> 01:26:07,316 And you can do, there's a lot different comparisons. 1726 01:26:07,316 --> 01:26:09,650 You can do greater than 1. 1727 01:26:09,650 --> 01:26:14,750 You can do iterative stenciling so that you can increment of value. 1728 01:26:14,750 --> 01:26:18,362 You can have simple values go between 0 and 255. 1729 01:26:18,362 --> 01:26:20,820 There's a lot of interesting effects you can get with that. 1730 01:26:20,820 --> 01:26:25,292 But the general use that we just saw is set the values to one, 1731 01:26:25,292 --> 01:26:28,250 and check to see whether they're less than 1, if you want to draw them. 1732 01:26:28,250 --> 01:26:29,795 If you want to not draw them. 1733 01:26:29,795 --> 01:26:32,000 Does anybody have questions how stenciling works, 1734 01:26:32,000 --> 01:26:35,480 and how these functions work? 1735 01:26:35,480 --> 01:26:36,412 Yeah? 1736 01:26:36,412 --> 01:26:40,195 AUDIENCE: So like having stat stencil cover up the door? 1737 01:26:40,195 --> 01:26:43,688 So when you draw the player, you won't actually 1738 01:26:43,688 --> 01:26:45,190 draw on the stencil, [INAUDIBLE]. 1739 01:26:45,190 --> 01:26:46,300 COLTON OGDEN: Yes. 1740 01:26:46,300 --> 01:26:52,240 So it's like having the stencil rectangles go over the doorway, 1741 01:26:52,240 --> 01:26:57,625 so that the player will not get drawn when it's underneath them. 1742 01:26:57,625 --> 01:27:01,290 If I go back to a slide that has it. 1743 01:27:01,290 --> 01:27:03,670 The stencils are here. 1744 01:27:03,670 --> 01:27:04,870 Right? 1745 01:27:04,870 --> 01:27:08,830 I had to go through and figure out the exact xy that I needed for them. 1746 01:27:08,830 --> 01:27:09,880 And there is a-- 1747 01:27:09,880 --> 01:27:12,400 what you can do is you can take that stencil function that 1748 01:27:12,400 --> 01:27:16,291 draws the rectangles, and you can just take it out of the stencil test, 1749 01:27:16,291 --> 01:27:16,790 and see. 1750 01:27:16,790 --> 01:27:19,456 You will actually be able to see where the exact rectangles are. 1751 01:27:19,456 --> 01:27:22,390 Because then it will just literally draw the rectangles. 1752 01:27:22,390 --> 01:27:26,714 But here, basically right between here and where it would be on the next room. 1753 01:27:26,714 --> 01:27:29,380 So that when we go from here over into the next room, it's still 1754 01:27:29,380 --> 01:27:31,240 stencils them. 1755 01:27:31,240 --> 01:27:33,670 Right here, the player is going to go over them. 1756 01:27:33,670 --> 01:27:35,740 It's going to set its stencil value to 1. 1757 01:27:35,740 --> 01:27:40,004 It's checking for anything less than 1 to render. 1758 01:27:40,004 --> 01:27:41,920 So it's going to fail the test, and it's going 1759 01:27:41,920 --> 01:27:46,370 to not draw that player at that point. 1760 01:27:46,370 --> 01:27:48,490 So it's effectively just masking out the player, 1761 01:27:48,490 --> 01:27:50,740 because we're assigning it to the right stencil value, 1762 01:27:50,740 --> 01:27:52,617 and we're doing the right comparison for it. 1763 01:27:52,617 --> 01:27:53,950 But yeah, that's effectively it. 1764 01:27:53,950 --> 01:27:57,700 Just using it to, because we were in a situation 1765 01:27:57,700 --> 01:28:01,690 where our tiles didn't cleanly lend themselves to drawing over 1766 01:28:01,690 --> 01:28:03,430 the player, which you could do. 1767 01:28:03,430 --> 01:28:06,670 You could draw the shadow part underneath the archway part, 1768 01:28:06,670 --> 01:28:08,380 and then just change the rendering order. 1769 01:28:08,380 --> 01:28:11,560 But the spreadsheet that we had didn't afford us that flexibility. 1770 01:28:11,560 --> 01:28:17,140 So we went with a little more interesting stenciling approach 1771 01:28:17,140 --> 01:28:20,120 to getting it done. 1772 01:28:20,120 --> 01:28:21,440 We looked at this earlier. 1773 01:28:21,440 --> 01:28:26,870 So game design via data, rather than a bunch of logic. 1774 01:28:26,870 --> 01:28:32,140 So the more you can sort of get towards modeling your anything in your game 1775 01:28:32,140 --> 01:28:35,005 like data, like this, the more flexible your engine is, 1776 01:28:35,005 --> 01:28:36,880 the easier it is for people to mod your game. 1777 01:28:36,880 --> 01:28:38,290 Which is hugely important. 1778 01:28:38,290 --> 01:28:40,270 And the easier it is for you to let designers 1779 01:28:40,270 --> 01:28:43,160 take charge of actually creating assets for your game. 1780 01:28:43,160 --> 01:28:45,880 So here we've created an arbitrary collection of data, 1781 01:28:45,880 --> 01:28:48,640 and you can get as complex with this as you want to. 1782 01:28:48,640 --> 01:28:51,400 The only thing that really matters is whether your game engine 1783 01:28:51,400 --> 01:28:54,800 supports those fields, and acts on those fields accordingly. 1784 01:28:54,800 --> 01:28:56,590 But once it does, I mean, the more things 1785 01:28:56,590 --> 01:29:00,070 you add, the more possibilities you have for adding new things. 1786 01:29:00,070 --> 01:29:02,470 So goblin, we have health, strength. 1787 01:29:02,470 --> 01:29:05,330 So strength should be accounted for in our game engine. 1788 01:29:05,330 --> 01:29:08,080 And this is, we're talking in just the general abstract sense now. 1789 01:29:08,080 --> 01:29:10,180 Let's say we're like making an RPG or something. 1790 01:29:10,180 --> 01:29:12,325 Or maybe this is part of our Zelda game. 1791 01:29:12,325 --> 01:29:14,200 If we got a little bit more detailed with it. 1792 01:29:14,200 --> 01:29:18,379 But goblin is going to be a creature that has 10 health. 1793 01:29:18,379 --> 01:29:20,170 It's got two strength, so these values will 1794 01:29:20,170 --> 01:29:21,970 get loaded when it's created as an entity, 1795 01:29:21,970 --> 01:29:24,010 and strength is some value that our engine 1796 01:29:24,010 --> 01:29:27,130 needs to apply to anything that it decides to attack. 1797 01:29:27,130 --> 01:29:27,630 Right? 1798 01:29:27,630 --> 01:29:29,338 You could do the same thing with defense. 1799 01:29:29,338 --> 01:29:30,880 You could create arbitrary things. 1800 01:29:30,880 --> 01:29:32,270 It's got a goblin texture. 1801 01:29:32,270 --> 01:29:33,820 So that's the sprite. 1802 01:29:33,820 --> 01:29:36,250 We've defined some animations here, which 1803 01:29:36,250 --> 01:29:39,550 you've already seen how to instantiate those in our game engine. 1804 01:29:39,550 --> 01:29:43,760 Maybe it starts off with a club weapon. 1805 01:29:43,760 --> 01:29:49,300 And you can also reference other sort of Lua files 1806 01:29:49,300 --> 01:29:54,010 that have these definitions, if you have maybe a weapons defs file. 1807 01:29:54,010 --> 01:29:58,030 You could index into weapons defs club, and then that club item 1808 01:29:58,030 --> 01:30:00,340 will maybe have a bunch of its own characteristics 1809 01:30:00,340 --> 01:30:04,770 that when your game engine is loading this goblin def, 1810 01:30:04,770 --> 01:30:09,580 it loads in the club def as well, and instantiates a bunch of qualities 1811 01:30:09,580 --> 01:30:13,510 onto that entity, or that item, that then have 1812 01:30:13,510 --> 01:30:16,600 behavior relevant to your game engine. 1813 01:30:16,600 --> 01:30:17,570 Aggressive is true. 1814 01:30:17,570 --> 01:30:21,730 So if something is entity.Aggressive, then maybe it's AI 1815 01:30:21,730 --> 01:30:23,180 will seek out the player. 1816 01:30:23,180 --> 01:30:23,680 Right? 1817 01:30:23,680 --> 01:30:24,846 And you can set it to false. 1818 01:30:24,846 --> 01:30:27,730 So now you can differentiate between entities that chase the player, 1819 01:30:27,730 --> 01:30:31,420 and entities that are sort of docile, and just do their own random thing. 1820 01:30:31,420 --> 01:30:32,127 Sleeps at night. 1821 01:30:32,127 --> 01:30:33,710 Maybe your game has a day/night cycle. 1822 01:30:33,710 --> 01:30:38,080 Maybe some entities stay awake, and some go into a sleep state, right? 1823 01:30:38,080 --> 01:30:40,630 So it will look and say OK, it's nighttime, 1824 01:30:40,630 --> 01:30:42,520 does the entity sleep at night? 1825 01:30:42,520 --> 01:30:43,890 If it does, OK. 1826 01:30:43,890 --> 01:30:47,500 Then entity change state, sleep, right? 1827 01:30:47,500 --> 01:30:51,131 And then during the day, when the day happens, 1828 01:30:51,131 --> 01:30:52,630 you'll do the same thing in reverse. 1829 01:30:52,630 --> 01:30:55,560 You'll say if the entity sleeps at night, 1830 01:30:55,560 --> 01:30:57,670 then you say entity.awake is true. 1831 01:30:57,670 --> 01:30:59,650 Or whatever it is. 1832 01:30:59,650 --> 01:31:02,549 Change state awake, or idle, or walking. 1833 01:31:02,549 --> 01:31:03,340 And then flammable. 1834 01:31:03,340 --> 01:31:06,880 Maybe you have weapons that shoot damage, or shoot fire. 1835 01:31:06,880 --> 01:31:10,000 Or maybe you have torches that shoot fire, or some-- 1836 01:31:10,000 --> 01:31:12,220 maybe you're in a level that's like lava. 1837 01:31:12,220 --> 01:31:16,900 And you know, if you touch one of the tiles, it has a flammable effect. 1838 01:31:16,900 --> 01:31:19,870 And if it's flammable, may be your status equals flammable. 1839 01:31:19,870 --> 01:31:21,320 You take damage over time. 1840 01:31:21,320 --> 01:31:22,570 And you change your animation. 1841 01:31:22,570 --> 01:31:25,090 Maybe you'd get tinted red, or something like that. 1842 01:31:25,090 --> 01:31:27,530 But thinking about all these different possibilities, 1843 01:31:27,530 --> 01:31:31,030 like what your engine is capable of, you can create pretty much arbitrarily 1844 01:31:31,030 --> 01:31:34,390 complex data structures and entities, and items, 1845 01:31:34,390 --> 01:31:36,790 and whatever you want in your game, without having 1846 01:31:36,790 --> 01:31:38,290 to create a goblin class. 1847 01:31:38,290 --> 01:31:39,850 Or a skeleton class. 1848 01:31:39,850 --> 01:31:43,180 Or a arbitrarily complex creature class. 1849 01:31:43,180 --> 01:31:48,310 You just compose your creature with attributes and model 1850 01:31:48,310 --> 01:31:49,227 its behavior that way. 1851 01:31:49,227 --> 01:31:51,810 Composition over inheritance, which we talked about last week, 1852 01:31:51,810 --> 01:31:53,180 is very valuable in game design. 1853 01:31:53,180 --> 01:31:56,020 And that's what Unity's game engine sort of approaches. 1854 01:31:56,020 --> 01:31:58,840 Because entity is a purely entity component system, 1855 01:31:58,840 --> 01:32:03,940 whereby entities are modeled as collections of components 1856 01:32:03,940 --> 01:32:05,290 that each do something. 1857 01:32:05,290 --> 01:32:08,380 And we can sort of almost think of these as components, too. 1858 01:32:08,380 --> 01:32:11,500 Albeit in a much simpler sort of representation. 1859 01:32:11,500 --> 01:32:14,740 Does anybody have questions of this, or like why it's useful, 1860 01:32:14,740 --> 01:32:18,670 or anything like that? 1861 01:32:18,670 --> 01:32:20,330 OK. 1862 01:32:20,330 --> 01:32:24,560 So the last thing I wanted to talk about today, and I saw one or two students 1863 01:32:24,560 --> 01:32:27,440 were mentioning how they wished they knew, or wish we 1864 01:32:27,440 --> 01:32:31,670 talked about a little bit more how programming was done back in the day. 1865 01:32:31,670 --> 01:32:38,220 So I'm not an expert, necessarily, in programming 6502 assembly, 1866 01:32:38,220 --> 01:32:39,786 which is what the NES is written in. 1867 01:32:39,786 --> 01:32:41,910 There are a lot of people that are very good at it. 1868 01:32:41,910 --> 01:32:43,118 But there's a few links here. 1869 01:32:43,118 --> 01:32:47,510 So in the slides, if you wanted to look at the slides on the website, 1870 01:32:47,510 --> 01:32:52,160 Homebrew is actually quite a popular thing amongst certain communities 1871 01:32:52,160 --> 01:32:52,970 online. 1872 01:32:52,970 --> 01:32:56,180 And what it is essentially getting compilers 1873 01:32:56,180 --> 01:33:00,770 that will compile source code for some arbitrary processor, or development 1874 01:33:00,770 --> 01:33:04,040 environment from some arbitrary computer system. 1875 01:33:04,040 --> 01:33:08,360 Like the NES, which was a 8-bit microprocessor based machine 1876 01:33:08,360 --> 01:33:11,412 with its own set of interesting hardware. 1877 01:33:11,412 --> 01:33:13,370 It allowed you to compile the assembly for that 1878 01:33:13,370 --> 01:33:16,060 and actually run it via a program called an emulator. 1879 01:33:16,060 --> 01:33:21,020 And an emulator just allows you to run ROM images, or just arbitrary data 1880 01:33:21,020 --> 01:33:26,930 that maps to the machine instructions of some system 1881 01:33:26,930 --> 01:33:30,980 that the emulator has emulated via virtual machine. 1882 01:33:30,980 --> 01:33:35,539 And so if you wanted to look into it a little bit more in detail, 1883 01:33:35,539 --> 01:33:36,830 there's a couple of links here. 1884 01:33:36,830 --> 01:33:39,696 So NES.wiki has got a bunch of great links. 1885 01:33:39,696 --> 01:33:41,570 There's a Programming Guide that kind of goes 1886 01:33:41,570 --> 01:33:45,980 over the basics of how to do some 6502 assembly as well as with the NES, 1887 01:33:45,980 --> 01:33:47,810 and its particular hardware. 1888 01:33:47,810 --> 01:33:54,140 And then the compiler that most people use for this is called CC 65, 1889 01:33:54,140 --> 01:33:58,160 which is a 65 02 assembly compiler. 1890 01:33:58,160 --> 01:34:02,460 And so this is an example of some source code. 1891 01:34:02,460 --> 01:34:04,130 It's a little bit tough to read. 1892 01:34:04,130 --> 01:34:07,760 But I can't zoom in, I don't think. 1893 01:34:07,760 --> 01:34:11,180 But the gist of it is you have a lot of-- 1894 01:34:11,180 --> 01:34:13,305 and here, actually I could pull it up online. 1895 01:34:13,305 --> 01:34:14,110 Le me try. 1896 01:34:14,110 --> 01:34:17,270 1897 01:34:17,270 --> 01:34:20,280 Super Mario disassembly. 1898 01:34:20,280 --> 01:34:23,630 So go here. 1899 01:34:23,630 --> 01:34:24,380 This is on Github. 1900 01:34:24,380 --> 01:34:29,930 So somebody decompiled, basically, or disassembled rather, 1901 01:34:29,930 --> 01:34:34,400 took the bytes that represent all the machine code and the ROM image of Super 1902 01:34:34,400 --> 01:34:38,300 Mario Bros and then just converted it back to assembly language, 1903 01:34:38,300 --> 01:34:40,220 and then added comments to it. 1904 01:34:40,220 --> 01:34:43,910 Because I won't go into too much detail about what assembly is, 1905 01:34:43,910 --> 01:34:46,190 and how it works, but essentially it's just 1906 01:34:46,190 --> 01:34:50,750 a layer directly above machine code where the keywords 1907 01:34:50,750 --> 01:34:54,170 map to essentially what are bytes in memory 1908 01:34:54,170 --> 01:34:55,850 that are actually program instructions. 1909 01:34:55,850 --> 01:34:59,810 And that influence the behavior of your CPU such that you get programs. 1910 01:34:59,810 --> 01:35:05,000 And that's what c is layered on top of, an in every language thereof, 1911 01:35:05,000 --> 01:35:06,390 thereafter. 1912 01:35:06,390 --> 01:35:10,709 So if I zoom in here, see if I can. 1913 01:35:10,709 --> 01:35:11,750 It's being a little slow. 1914 01:35:11,750 --> 01:35:15,740 But it's letting me-- 1915 01:35:15,740 --> 01:35:18,020 so here we can see. 1916 01:35:18,020 --> 01:35:20,840 1917 01:35:20,840 --> 01:35:23,240 I think it's lagging because the file is just so large. 1918 01:35:23,240 --> 01:35:25,960 It's like 14,000 lines of code. 1919 01:35:25,960 --> 01:35:30,050 Because the thing about assembly is assembly is a very, very long. 1920 01:35:30,050 --> 01:35:31,730 Because there are so many-- 1921 01:35:31,730 --> 01:35:33,980 you need to have, just like really slowly. 1922 01:35:33,980 --> 01:35:36,380 Zooming in infinitely. 1923 01:35:36,380 --> 01:35:39,950 There are just so many steps you need to do in order 1924 01:35:39,950 --> 01:35:43,730 to achieve the same thing that you get in a high level language like C, 1925 01:35:43,730 --> 01:35:47,270 or even languages higher than that. 1926 01:35:47,270 --> 01:35:50,810 Taking a lot of things for granted, especially things like loading 1927 01:35:50,810 --> 01:35:51,320 registers. 1928 01:35:51,320 --> 01:35:54,620 So every CPU has got a series of registers that can store values, 1929 01:35:54,620 --> 01:35:58,190 and then the CPU has logic that you can basically 1930 01:35:58,190 --> 01:36:02,520 say OK, if the value in register a is greater than or equal to some value, 1931 01:36:02,520 --> 01:36:06,770 then branch to this sequence of the assembly code. 1932 01:36:06,770 --> 01:36:12,547 And often you'll have to do things like and/or operations on byte level, 1933 01:36:12,547 --> 01:36:13,130 just on bytes. 1934 01:36:13,130 --> 01:36:18,130 Like right here, we can see we're ending the value 3 on whatever 1935 01:36:18,130 --> 01:36:20,300 is in register a. 1936 01:36:20,300 --> 01:36:23,930 Like I said, don't intend to get too much into what assembly is. 1937 01:36:23,930 --> 01:36:28,760 But for those curious as to how games were implemented in the '80s, and even 1938 01:36:28,760 --> 01:36:31,400 the early '90s, it was all in assembly language. 1939 01:36:31,400 --> 01:36:33,920 Because assembly language is you're literally 1940 01:36:33,920 --> 01:36:37,880 programming the CPU of whatever machine you're trying to program. 1941 01:36:37,880 --> 01:36:41,660 And that's how you get as much efficiency as possible. 1942 01:36:41,660 --> 01:36:46,040 If you know your computing, environment you know what your CPU is capable of. 1943 01:36:46,040 --> 01:36:51,110 The thing about compiling a language like C, or C++, or Java, 1944 01:36:51,110 --> 01:36:53,480 which is even higher of an abstraction than those, 1945 01:36:53,480 --> 01:36:57,160 is you're allowing sort of algorithms to do the work for you. 1946 01:36:57,160 --> 01:37:01,310 You're allowing algorithms to take your source code 1947 01:37:01,310 --> 01:37:03,800 and turn it into this, basically. 1948 01:37:03,800 --> 01:37:05,810 A layer lower than this, effectively. 1949 01:37:05,810 --> 01:37:08,210 This is an intermediary level that it does generate. 1950 01:37:08,210 --> 01:37:12,320 But suffice to say, in the '80s and '90s, 1951 01:37:12,320 --> 01:37:17,059 C compilers were not as good as humans were in creating games, 1952 01:37:17,059 --> 01:37:19,850 especially to do a lot of the tricky things that they needed to do, 1953 01:37:19,850 --> 01:37:24,980 in order to get them working efficiently on processors that were, at the time, 1954 01:37:24,980 --> 01:37:26,750 one to three megahertz in speed. 1955 01:37:26,750 --> 01:37:31,070 Which now we have like three gigahertz processors, and it's no big deal. 1956 01:37:31,070 --> 01:37:35,990 But that is effectively, that's sort of a window 1957 01:37:35,990 --> 01:37:40,160 into what it was like developing games in the '80s and '90s. 1958 01:37:40,160 --> 01:37:43,130 And then in the '90s, with like things like N64 Playstation 1, 1959 01:37:43,130 --> 01:37:49,190 going onto Playstation 2, and so forth, it was typically done in a language 1960 01:37:49,190 --> 01:37:50,960 like C or C++. 1961 01:37:50,960 --> 01:37:53,120 Sometimes with some variants. 1962 01:37:53,120 --> 01:37:55,970 Certain consoles, like the PS3 has a notoriously difficult graphics 1963 01:37:55,970 --> 01:37:57,390 processor to program. 1964 01:37:57,390 --> 01:38:01,070 So a lot of PS3 three teams needed to program in assembly, 1965 01:38:01,070 --> 01:38:05,600 even at the time, which was 2007, 2009. 1966 01:38:05,600 --> 01:38:11,240 But that's, in a nutshell, what it's like programming the 65 02. 1967 01:38:11,240 --> 01:38:14,270 So if you want, those links up above, it's 1968 01:38:14,270 --> 01:38:16,550 a pretty enlightening experience actually digging 1969 01:38:16,550 --> 01:38:19,820 into that sort of thing, and trying to make sense of what the assembly does. 1970 01:38:19,820 --> 01:38:25,310 It's quite difficult, and quite burdensome because of how long 1971 01:38:25,310 --> 01:38:28,820 these programs are, and just how minute each individual instruction is. 1972 01:38:28,820 --> 01:38:32,300 Like just checking, just loading a value into a register, 1973 01:38:32,300 --> 01:38:36,320 just to do a loop often will just be iteratively loading a value 1974 01:38:36,320 --> 01:38:37,220 into a register. 1975 01:38:37,220 --> 01:38:41,030 And then like performing some operation, or calculation, off of that. 1976 01:38:41,030 --> 01:38:43,100 And then branching to some other loop of code. 1977 01:38:43,100 --> 01:38:46,230 A lot of that can be condensed into like just a couple of lines of C, 1978 01:38:46,230 --> 01:38:48,710 or even fewer lines of Lua. 1979 01:38:48,710 --> 01:38:52,520 So a lot more of a burden but there is insight. 1980 01:38:52,520 --> 01:38:54,770 Definitely some insight into digging a little deeper 1981 01:38:54,770 --> 01:38:56,250 and sort of looking there. 1982 01:38:56,250 --> 01:38:59,300 So once again, those are the links on the NES dev wiki. 1983 01:38:59,300 --> 01:39:02,330 Wiki.NESdev.com if you're interested in looking at that. 1984 01:39:02,330 --> 01:39:06,500 In Assignment 5, like you did in Assignment 4, 1985 01:39:06,500 --> 01:39:09,020 you can create a game object that's consumable. 1986 01:39:09,020 --> 01:39:13,060 And feel free to use code from Assignment 4 to do this. 1987 01:39:13,060 --> 01:39:16,890 When like you define your on consume function, 1988 01:39:16,890 --> 01:39:21,550 if you're going to adopt the same model as the last assignment, then any ideas 1989 01:39:21,550 --> 01:39:23,514 as to what we need to do? 1990 01:39:23,514 --> 01:39:26,460 1991 01:39:26,460 --> 01:39:31,030 Probably just add the opposite of damage the entity, right? 1992 01:39:31,030 --> 01:39:32,910 We want to add hearts. 1993 01:39:32,910 --> 01:39:35,760 We want to add HP to it. 1994 01:39:35,760 --> 01:39:41,100 And you'll see in the distro that health is modeled as an even number, 1995 01:39:41,100 --> 01:39:43,970 because every one digit is half a heart. 1996 01:39:43,970 --> 01:39:44,526 Yes. 1997 01:39:44,526 --> 01:39:46,900 AUDIENCE: Can you give a negative number to [INAUDIBLE]?? 1998 01:39:46,900 --> 01:39:48,690 COLTON OGDEN: You can. 1999 01:39:48,690 --> 01:39:51,300 And that will effectively be the same thing, too. 2000 01:39:51,300 --> 01:39:53,460 So. 2001 01:39:53,460 --> 01:39:55,930 The second part is including pots. 2002 01:39:55,930 --> 01:39:57,570 So there are pots in the sprite sheet. 2003 01:39:57,570 --> 01:39:58,791 So these should be solid. 2004 01:39:58,791 --> 01:40:00,540 So when the player interacts with them, he 2005 01:40:00,540 --> 01:40:04,870 should be bumped out of where he was. 2006 01:40:04,870 --> 01:40:06,120 Allow the player to lift them. 2007 01:40:06,120 --> 01:40:09,036 So there's an animation in the sprite sheet that will actually allow-- 2008 01:40:09,036 --> 01:40:11,730 that shows the player lifting up the pot. 2009 01:40:11,730 --> 01:40:15,630 So you probably need a new state, player lift pot state. 2010 01:40:15,630 --> 01:40:16,710 Walk with pot state. 2011 01:40:16,710 --> 01:40:18,330 Whatever you want to define it as. 2012 01:40:18,330 --> 01:40:22,920 But you'll need basically to have those two in order to get this to work. 2013 01:40:22,920 --> 01:40:25,770 What's one thing that we'll need to do in order for the player 2014 01:40:25,770 --> 01:40:26,580 to lift the pot. 2015 01:40:26,580 --> 01:40:29,340 Any ideas? 2016 01:40:29,340 --> 01:40:34,320 Besides the rendering aspect of it, when the player walks around, for example, 2017 01:40:34,320 --> 01:40:36,540 what needs to happen? 2018 01:40:36,540 --> 01:40:38,889 If he's holding the pot. 2019 01:40:38,889 --> 01:40:40,577 AUDIENCE: He's slower. 2020 01:40:40,577 --> 01:40:42,160 COLTON OGDEN: You can make him slower. 2021 01:40:42,160 --> 01:40:43,170 Yeah, that's possible. 2022 01:40:43,170 --> 01:40:45,240 That's not required for the assignment. 2023 01:40:45,240 --> 01:40:46,890 More fundamental than that. 2024 01:40:46,890 --> 01:40:49,674 2025 01:40:49,674 --> 01:40:51,840 The pot needs to track the player's location, right? 2026 01:40:51,840 --> 01:40:53,881 It needs to be relative to the player's location. 2027 01:40:53,881 --> 01:40:59,337 So keep the pot probably above the player by some amount. 2028 01:40:59,337 --> 01:41:01,420 I won't be too picky as to how you implement that. 2029 01:41:01,420 --> 01:41:04,680 But the pot needs to track the player. 2030 01:41:04,680 --> 01:41:06,240 Which is this next point, actually. 2031 01:41:06,240 --> 01:41:07,770 And the walking animations, like I said, should 2032 01:41:07,770 --> 01:41:09,420 change while they're carrying it. 2033 01:41:09,420 --> 01:41:11,430 Allow the player, lastly, to throw the pot. 2034 01:41:11,430 --> 01:41:15,150 So when you throw the pot, basically turn the pot into a projectile. 2035 01:41:15,150 --> 01:41:18,442 If it hits one of the walls, break it. 2036 01:41:18,442 --> 01:41:21,150 You can either just despawn it instantly, or have some animation. 2037 01:41:21,150 --> 01:41:21,960 It's up to you. 2038 01:41:21,960 --> 01:41:25,200 But just, if it hits a wall, despawn it. 2039 01:41:25,200 --> 01:41:28,140 Trigger it to-- maybe just trigger it to some values, false. 2040 01:41:28,140 --> 01:41:31,140 Render is false, whatever you want to do. 2041 01:41:31,140 --> 01:41:35,640 If it hits an enemy, it should damage the enemy by one, 2042 01:41:35,640 --> 01:41:37,140 just like we've seen already. 2043 01:41:37,140 --> 01:41:39,420 And if it travels farther than four tiles, 2044 01:41:39,420 --> 01:41:43,390 in addition to also hitting one of the walls, then destroy it too. 2045 01:41:43,390 --> 01:41:47,430 So those are the main components for Assignment 5. 2046 01:41:47,430 --> 01:41:51,750 And the ways that which you achieve most of it's fairly flexible. 2047 01:41:51,750 --> 01:41:55,170 But yeah, that's Lecture 5, Legend of Zelda. 2048 01:41:55,170 --> 01:41:56,070 So thanks for coming. 2049 01:41:56,070 --> 01:41:58,235 I'll see you next time. 2050 01:41:58,235 --> 01:41:58,735