1 00:00:00,000 --> 00:00:00,110 2 00:00:00,110 --> 00:00:01,902 COLTON OGDEN: So in Mario 2, we took a look 3 00:00:01,902 --> 00:00:06,030 at allowing us to control Mario, well, control the screen, rather, ourselves-- 4 00:00:06,030 --> 00:00:09,300 the camera, so to speak-- using love.graphics.translate as opposed 5 00:00:09,300 --> 00:00:10,890 to making it an autoscroller. 6 00:00:10,890 --> 00:00:13,618 In this update we're going to explore a little bit of what's 7 00:00:13,618 --> 00:00:15,660 called procedural generation, or you might see it 8 00:00:15,660 --> 00:00:18,750 as ProcGen, which is why this is the ProcGen update. 9 00:00:18,750 --> 00:00:20,850 But essentially, it allows us to generate 10 00:00:20,850 --> 00:00:24,300 levels that look a little something like this randomly. 11 00:00:24,300 --> 00:00:27,180 Using an algorithm, we can iterate sort of column 12 00:00:27,180 --> 00:00:30,150 by column throughout our game map. 13 00:00:30,150 --> 00:00:33,300 Instead of just setting the first half to the sky and the second half 14 00:00:33,300 --> 00:00:37,560 to bricks, we can essentially, column by column, say, OK, in this column, 15 00:00:37,560 --> 00:00:38,860 I want it just to be normal. 16 00:00:38,860 --> 00:00:41,520 I want to generate just sky and then bricks [INAUDIBLE] 17 00:00:41,520 --> 00:00:43,672 map divided map height divided by 2. 18 00:00:43,672 --> 00:00:46,380 Maybe in this column I want there to be a cloud that begins here. 19 00:00:46,380 --> 00:00:51,090 And so I want to set this tile and the tile to the right of it to cloud tiles. 20 00:00:51,090 --> 00:00:53,520 And then maybe on this one I want a column, 21 00:00:53,520 --> 00:00:55,770 or maybe both a cloud and a column. 22 00:00:55,770 --> 00:00:59,700 So when we get to the ground level, create the column tiles, 23 00:00:59,700 --> 00:01:03,630 the bottom one, and then the top one two tiles above where the ground begins. 24 00:01:03,630 --> 00:01:07,710 And this sort of way lends itself very well to side scrolling platformers. 25 00:01:07,710 --> 00:01:10,170 Because we can generate the world as it goes left to right. 26 00:01:10,170 --> 00:01:13,890 Just because the world does function in a sort of left to right way, 27 00:01:13,890 --> 00:01:18,450 the flow of how obstacles generate just sort of works well in this model, 28 00:01:18,450 --> 00:01:21,510 as opposed to generating everything sort of scan line by scan line. 29 00:01:21,510 --> 00:01:26,940 Because in that sense, you would have to generate the entire terrain one 30 00:01:26,940 --> 00:01:29,400 sort of x one row iteration. 31 00:01:29,400 --> 00:01:30,912 And it's not impossible to do it. 32 00:01:30,912 --> 00:01:32,370 Certainly you could do it this way. 33 00:01:32,370 --> 00:01:35,050 But at least in my mind, this way makes a little bit more sense. 34 00:01:35,050 --> 00:01:36,933 So we'll take a look at doing it that way. 35 00:01:36,933 --> 00:01:38,850 Now, instead of coding this one from scratch-- 36 00:01:38,850 --> 00:01:40,433 because it's a little bit of leg work. 37 00:01:40,433 --> 00:01:44,460 And it's not necessarily germane, I think, to a lot of conceptual learning. 38 00:01:44,460 --> 00:01:49,380 It's really iterating upon what we've already done with the first Mario 0. 39 00:01:49,380 --> 00:01:53,060 We'll explore the code as it's prewritten in the Mario 3 distro. 40 00:01:53,060 --> 00:01:56,460 Now, up here at the very top, you'll see sort of at the header 41 00:01:56,460 --> 00:01:58,620 where we have all of the tile declarations. 42 00:01:58,620 --> 00:02:01,260 We have cloud left and cloud right in addition 43 00:02:01,260 --> 00:02:05,430 to bush left, bush right, mushroom top, mushroom bottom, and then jump block. 44 00:02:05,430 --> 00:02:08,400 And these are just numbers that map exactly to that sprite sheet 45 00:02:08,400 --> 00:02:11,330 that I showed you earlier in the slides and here in the project. 46 00:02:11,330 --> 00:02:13,497 If I come down to where we actually begin-- and this 47 00:02:13,497 --> 00:02:15,360 is, again, in map.lua specifically. 48 00:02:15,360 --> 00:02:18,390 If we go down to where we normally have the map generating 49 00:02:18,390 --> 00:02:21,000 the empty tiles throughout the whole thing, 50 00:02:21,000 --> 00:02:24,120 we see that right after that, we begin at x1. 51 00:02:24,120 --> 00:02:27,720 And we start saying, well, x is less than self.mapWidth do. 52 00:02:27,720 --> 00:02:30,720 And then we're iterating throughout the entire map width in this case. 53 00:02:30,720 --> 00:02:32,970 And this is a little bit different than how we usually 54 00:02:32,970 --> 00:02:36,900 iterate through nested for loops, where we go y by y, 55 00:02:36,900 --> 00:02:38,965 and then we're exploring each. 56 00:02:38,965 --> 00:02:41,340 Basically, we're going an entire row at a time as opposed 57 00:02:41,340 --> 00:02:42,540 to a column at a time. 58 00:02:42,540 --> 00:02:44,640 In this case, we're going one column at a time. 59 00:02:44,640 --> 00:02:47,610 Now, what we're doing is we're leveraging math.random, 60 00:02:47,610 --> 00:02:49,560 which we actually explored in the Pong distro 61 00:02:49,560 --> 00:02:52,980 when we implemented the ball moving in random directions. 62 00:02:52,980 --> 00:02:57,660 Here we're essentially saying, if it's the case that x is less than 63 00:02:57,660 --> 00:03:00,930 self.mapWidth minus 2-- which just means make sure that we're away from 64 00:03:00,930 --> 00:03:03,420 the right side of the screen all the way at the very edge-- 65 00:03:03,420 --> 00:03:07,750 we have a 1 in 20 chance, which is why this math.random 20 is equal to 1, 66 00:03:07,750 --> 00:03:09,730 of creating a cloud. 67 00:03:09,730 --> 00:03:11,970 And so what we do is we say the cloud start is 68 00:03:11,970 --> 00:03:16,500 going to be some random value on the y-axis before six 69 00:03:16,500 --> 00:03:19,860 tiles from the bottom, just so that it's not right at the bottom of the screen 70 00:03:19,860 --> 00:03:22,230 or right where the tiles begin. 71 00:03:22,230 --> 00:03:27,300 And then we just set the tile of cloudStart at x in cloudStart 72 00:03:27,300 --> 00:03:31,440 and x plus 1 in cloudStart to CLOUD_LEFT and CLOUD_RIGHT. 73 00:03:31,440 --> 00:03:36,090 And what that has the effect of doing is, per the example here, 74 00:03:36,090 --> 00:03:38,640 it will have a chance to generate this cloud right here. 75 00:03:38,640 --> 00:03:39,807 This is the left tile. 76 00:03:39,807 --> 00:03:41,140 And then this is the right tile. 77 00:03:41,140 --> 00:03:43,060 So it goes down from the top. 78 00:03:43,060 --> 00:03:48,430 It picks a random y height if 1 in 20 is equal to 1. 79 00:03:48,430 --> 00:03:51,030 And then it just sets both tiles at once. 80 00:03:51,030 --> 00:03:52,710 OK, so we'll go over here. 81 00:03:52,710 --> 00:03:56,700 And then here we see we have a 5% chance to generate a mushroom. 82 00:03:56,700 --> 00:03:58,380 So I have it written as pipe here. 83 00:03:58,380 --> 00:03:59,588 But it's actually a mushroom. 84 00:03:59,588 --> 00:04:01,850 So it's literally the same thing as the last one. 85 00:04:01,850 --> 00:04:02,940 Well, not literally the same thing. 86 00:04:02,940 --> 00:04:04,500 But it's conceptually the same thing. 87 00:04:04,500 --> 00:04:05,910 We're setting two tiles. 88 00:04:05,910 --> 00:04:09,470 Only this time, we're actually setting two tiles vertically, the mushroom top 89 00:04:09,470 --> 00:04:10,470 and the mushroom bottom. 90 00:04:10,470 --> 00:04:13,650 If I rerun this, you'll see that we do have the mushroom top right here 91 00:04:13,650 --> 00:04:15,840 and the mushroom bottom when put together. 92 00:04:15,840 --> 00:04:17,360 It looked a little bit weird in the sprite sheet. 93 00:04:17,360 --> 00:04:19,290 But here we can see that, visually, they look 94 00:04:19,290 --> 00:04:21,690 very nice when they are drawn together. 95 00:04:21,690 --> 00:04:24,240 96 00:04:24,240 --> 00:04:26,370 And then also, an important thing to do, we 97 00:04:26,370 --> 00:04:29,640 draw a column of tiles going from the bottom 98 00:04:29,640 --> 00:04:34,638 all the way down to the screen when we get to y divided by 2, essentially. 99 00:04:34,638 --> 00:04:35,430 Which is important. 100 00:04:35,430 --> 00:04:39,390 Because if we have a column of mushrooms, 101 00:04:39,390 --> 00:04:43,920 it's requisite that we should also have tiles to build that mushroom on top of. 102 00:04:43,920 --> 00:04:45,030 So it's an important step. 103 00:04:45,030 --> 00:04:47,363 And you also have to, of course, make sure you increment 104 00:04:47,363 --> 00:04:51,120 x so we do eventually reach x being equal to mapWidth. 105 00:04:51,120 --> 00:04:53,940 There's also a 10% chance to generate a bush, same thing. 106 00:04:53,940 --> 00:04:57,330 A 10% chance to not generate anything at all, which means we 107 00:04:57,330 --> 00:05:00,290 actually create a gap in the tiles. 108 00:05:00,290 --> 00:05:04,220 So we're not creating a column of tiles. 109 00:05:04,220 --> 00:05:06,410 And then we also have a chance to generate a block. 110 00:05:06,410 --> 00:05:10,163 So 1 in 15 chance, in this case, to generate a yellow tile block. 111 00:05:10,163 --> 00:05:12,080 Now, if we run this over and over again, we'll 112 00:05:12,080 --> 00:05:15,020 see that it actually is the same exact output each time. 113 00:05:15,020 --> 00:05:18,950 And to influence this, what we can do in main.lua-- 114 00:05:18,950 --> 00:05:20,510 at the very top, roughly-- 115 00:05:20,510 --> 00:05:26,510 we can say math.randomseed os.time, which we aren't already doing. 116 00:05:26,510 --> 00:05:29,240 Well, the map is actually being generated 117 00:05:29,240 --> 00:05:31,430 before love.load in this case. 118 00:05:31,430 --> 00:05:34,160 So what I'm actually going to do is I'm going to copy this. 119 00:05:34,160 --> 00:05:37,640 And I'm going to put this underneath math.randomseed. 120 00:05:37,640 --> 00:05:41,780 Since the map was generating before math.randomseed was even called, 121 00:05:41,780 --> 00:05:44,105 it was always still getting the same random generation. 122 00:05:44,105 --> 00:05:46,490 I'm going to go ahead now and rerun it. 123 00:05:46,490 --> 00:05:48,710 And we do indeed see a brand new map in this case. 124 00:05:48,710 --> 00:05:51,740 And as I was hoping, we can see the yellow block here, 125 00:05:51,740 --> 00:05:53,690 which illustrates the logic there. 126 00:05:53,690 --> 00:05:56,300 So perfect, everything works just according to plan. 127 00:05:56,300 --> 00:05:58,700 And that's an overview roughly of procedural generation, 128 00:05:58,700 --> 00:06:01,232 at least as it applies to a platforming game. 129 00:06:01,232 --> 00:06:03,440 You can obviously take this as far as you want to go. 130 00:06:03,440 --> 00:06:05,045 You can implement all kinds of things. 131 00:06:05,045 --> 00:06:06,920 And actually, part of the assignment is going 132 00:06:06,920 --> 00:06:09,860 to be to generate the Mario pyramid. 133 00:06:09,860 --> 00:06:12,410 Using this exact sort of setup here, you can just 134 00:06:12,410 --> 00:06:15,110 sort of plug in that functionality and get it working. 135 00:06:15,110 --> 00:06:19,400 But that will be part of the assignment for the Mario end of the track. 136 00:06:19,400 --> 00:06:20,600 So join me in Mario 4. 137 00:06:20,600 --> 00:06:22,870 We're going to step away from procedural generation, 138 00:06:22,870 --> 00:06:26,660 and actually add our sort of Mario avatar and alien to the scene, 139 00:06:26,660 --> 00:06:28,940 and work towards having a character we can control. 140 00:06:28,940 --> 00:06:31,540 So see you soon in Mario 4. 141 00:06:31,540 --> 00:06:32,369