1 00:00:00,000 --> 00:00:01,984 [MUSIC PLAYING] 2 00:00:01,984 --> 00:00:16,390 3 00:00:16,390 --> 00:00:17,170 SPEAKER 1: Hello. 4 00:00:17,170 --> 00:00:19,810 Welcome to lecture three of GD50. 5 00:00:19,810 --> 00:00:24,940 Today, we're going be talking about Match 3, as shown by the little cubes 6 00:00:24,940 --> 00:00:27,190 here on the slide. 7 00:00:27,190 --> 00:00:29,950 Match 3 originated a little earlier than 2001, 8 00:00:29,950 --> 00:00:32,860 but the first big game that came out that was 9 00:00:32,860 --> 00:00:39,092 a sort of genre staple of Match 3 was Bejeweled, shown here on the screen. 10 00:00:39,092 --> 00:00:41,050 This is a more modern incarnation of Bejeweled, 11 00:00:41,050 --> 00:00:43,090 but it came out originally in 2001. 12 00:00:43,090 --> 00:00:46,130 It was actually a web browser game, and the formula is very simple. 13 00:00:46,130 --> 00:00:52,630 The premise is you have a grid of different colored or shaped items, 14 00:00:52,630 --> 00:00:54,820 usually pretty small, like eight by eight, or so. 15 00:00:54,820 --> 00:00:57,850 And your goal is just to simply, like the name says, match three or more 16 00:00:57,850 --> 00:00:59,470 of them in a row. 17 00:00:59,470 --> 00:01:02,140 If you do, you get a certain number of points. 18 00:01:02,140 --> 00:01:05,080 Matching usually more than three gives you more points, or a bonus. 19 00:01:05,080 --> 00:01:10,150 And whenever you match three, the blocks will disappear from the grid, 20 00:01:10,150 --> 00:01:12,280 and they'll be replaced by more blocks. 21 00:01:12,280 --> 00:01:15,490 And the ones that you made holes for, the blocks above them 22 00:01:15,490 --> 00:01:17,269 will come down via gravity. 23 00:01:17,269 --> 00:01:19,310 This is a more modern incarnation of the formula. 24 00:01:19,310 --> 00:01:22,260 This is Candy Crush, which I think most people know. 25 00:01:22,260 --> 00:01:28,690 It was a very big hit on mobile devices, and otherwise around 2013, 2012, 26 00:01:28,690 --> 00:01:32,380 and that's probably the most recent big Match 3 style game that's come out, 27 00:01:32,380 --> 00:01:34,360 but there are a lot of other takes on it-- 28 00:01:34,360 --> 00:01:36,910 different versions that try to add new features, and stuff. 29 00:01:36,910 --> 00:01:40,449 This is the game that we'll be putting together today, and I'll show you how, 30 00:01:40,449 --> 00:01:42,490 and we'll be covering a few other things as well. 31 00:01:42,490 --> 00:01:45,070 So the topics today, we'll be covering, first 32 00:01:45,070 --> 00:01:49,450 of all, a fundamental concept in dynamic languages, a lot of dynamic languages, 33 00:01:49,450 --> 00:01:50,584 and also Lua. 34 00:01:50,584 --> 00:01:52,750 It's called anonymous functions, which are functions 35 00:01:52,750 --> 00:01:56,540 that are first class, meaning that they operate as data types, 36 00:01:56,540 --> 00:01:58,700 and so we can do some fancy stuff with those. 37 00:01:58,700 --> 00:02:00,640 Tweening, which means just taking one thing, 38 00:02:00,640 --> 00:02:04,870 and interpolating its value between two values from 1, 39 00:02:04,870 --> 00:02:08,120 to a destination value over time, which is a very important thing in games. 40 00:02:08,120 --> 00:02:09,740 You can do things like move objects. 41 00:02:09,740 --> 00:02:11,740 We can also tween their opacity. 42 00:02:11,740 --> 00:02:16,340 Just sort of asynchronous behavior, and asynchronous variable manipulation. 43 00:02:16,340 --> 00:02:17,710 Timers, very important. 44 00:02:17,710 --> 00:02:20,500 We can time something to happen at certain intervals, 45 00:02:20,500 --> 00:02:22,720 or after a certain length of time has passed 46 00:02:22,720 --> 00:02:27,280 to get us past the idea of storing different timed variables, 47 00:02:27,280 --> 00:02:30,840 or different counters, and break away, and keep timer objects that 48 00:02:30,840 --> 00:02:32,090 will take care of this for us. 49 00:02:32,090 --> 00:02:34,630 We'll see how we do that with a specific library. 50 00:02:34,630 --> 00:02:39,780 And then we'll get to the actual details of Match 3, and how to solve matches, 51 00:02:39,780 --> 00:02:41,200 and how to account for that. 52 00:02:41,200 --> 00:02:45,010 Fill in the grid, account for when we actually solve a match, 53 00:02:45,010 --> 00:02:46,960 and repopulate it once we've done so. 54 00:02:46,960 --> 00:02:49,240 We'll talk about how to do this procedurally. 55 00:02:49,240 --> 00:02:53,080 It's very simple compared to, I think, Breakout's more procedural layout 56 00:02:53,080 --> 00:02:58,040 system, but it's still randomisation, and we'll talk about that. 57 00:02:58,040 --> 00:03:00,820 And then last, if we have time, we'll talk about sprite art, 58 00:03:00,820 --> 00:03:04,210 and palettes, which is a big fundamental thing when you're doing 2D game 59 00:03:04,210 --> 00:03:09,220 development, and something that this, and Breakout's sprite sheet 60 00:03:09,220 --> 00:03:14,170 took advantage of was the idea of using, on purpose, a restricted set of colors, 61 00:03:14,170 --> 00:03:16,790 a palette for creating your 2D art, and there 62 00:03:16,790 --> 00:03:20,650 are a lot of really cool, and impressive things we can do with that. 63 00:03:20,650 --> 00:03:25,550 But first, I'd like to actually show what we'll be running today in class. 64 00:03:25,550 --> 00:03:28,300 So I'm going to come here into my directory. 65 00:03:28,300 --> 00:03:30,370 Make sure I'm in the right place, which I am. 66 00:03:30,370 --> 00:03:33,310 So this is part of the distribution code, which is online. 67 00:03:33,310 --> 00:03:36,370 So there's a Match 3 directory. 68 00:03:36,370 --> 00:03:39,250 And would anybody like to come demo it in class? 69 00:03:39,250 --> 00:03:42,701 70 00:03:42,701 --> 00:03:45,691 All right, [? Tony. ?] Come on up. 71 00:03:45,691 --> 00:03:48,690 All right, so whenever you're ready, go ahead, and just hit Return here. 72 00:03:48,690 --> 00:03:51,510 73 00:03:51,510 --> 00:03:52,920 [GAME MUSIC PLAYING] 74 00:03:52,920 --> 00:03:55,640 All right, and so this is my implementation of Match 3. 75 00:03:55,640 --> 00:03:58,620 It uses a different set of tiles. 76 00:03:58,620 --> 00:04:02,220 We have things that are moving over time. 77 00:04:02,220 --> 00:04:03,650 It's arrow key based. 78 00:04:03,650 --> 00:04:07,280 79 00:04:07,280 --> 00:04:10,490 So if you press Enter on any tile, you can flip it with another tile. 80 00:04:10,490 --> 00:04:12,660 It doesn't have to be a match, in this case. 81 00:04:12,660 --> 00:04:16,065 So you can-- yeah. 82 00:04:16,065 --> 00:04:17,690 Yeah, you kind of got an unlucky board. 83 00:04:17,690 --> 00:04:19,898 There, at the very bottom, I see there's a few that-- 84 00:04:19,898 --> 00:04:22,610 some brown ones you can match together. 85 00:04:22,610 --> 00:04:26,579 So once you match them together, the tiles come down to repopulate. 86 00:04:26,579 --> 00:04:27,620 You get new tiles up top. 87 00:04:27,620 --> 00:04:30,605 88 00:04:30,605 --> 00:04:32,730 And so notice, we have a timer on the left as well. 89 00:04:32,730 --> 00:04:33,810 It's something that's counting down. 90 00:04:33,810 --> 00:04:37,470 We'll see how this is actually done with the library we'll be using, as opposed 91 00:04:37,470 --> 00:04:41,850 to managing a counter variable keeping track of it over time. 92 00:04:41,850 --> 00:04:47,540 93 00:04:47,540 --> 00:04:50,540 A lot of games will actually implement it so you have to-- you can only, 94 00:04:50,540 --> 00:04:52,623 and this will be part of the assignment, actually, 95 00:04:52,623 --> 00:04:56,160 where you can only move a tile if it creates a match. 96 00:04:56,160 --> 00:04:57,730 In this case, there's a-- 97 00:04:57,730 --> 00:05:00,980 and we can see the timer counting down, and then once you-- yeah, 98 00:05:00,980 --> 00:05:03,270 if you don't get past the goal, there's a game over. 99 00:05:03,270 --> 00:05:04,936 But thanks, [? Tony. ?] I appreciate it. 100 00:05:04,936 --> 00:05:05,940 AUDIENCE: No problem. 101 00:05:05,940 --> 00:05:07,773 SPEAKER 1: So that's the game in a nutshell. 102 00:05:07,773 --> 00:05:09,720 And another thing I want to point out to is 103 00:05:09,720 --> 00:05:13,200 the transition, the white transitions, and then the level text. 104 00:05:13,200 --> 00:05:16,020 Those are all done with timers that we'll be using, 105 00:05:16,020 --> 00:05:18,540 and tweens, which we'll be covering in class here 106 00:05:18,540 --> 00:05:20,505 as some of our early examples. 107 00:05:20,505 --> 00:05:23,130 But there's a lot of stuff that we haven't touched on, but also 108 00:05:23,130 --> 00:05:24,060 a lot that we have. 109 00:05:24,060 --> 00:05:29,140 It uses sprites, and a sprite sheet, and we've done that thing before. 110 00:05:29,140 --> 00:05:32,430 We chop up a sprite sheet, and then take out the whatever individual quads 111 00:05:32,430 --> 00:05:34,370 you need, and draw them to the screen. 112 00:05:34,370 --> 00:05:38,640 Here's what our goal is, which is we have a title screen with Match 3, 113 00:05:38,640 --> 00:05:40,080 start, and quit game in this case. 114 00:05:40,080 --> 00:05:40,954 A little bit simpler. 115 00:05:40,954 --> 00:05:43,780 No high scores this time just because we've already covered that, 116 00:05:43,780 --> 00:05:45,490 but we also have a level screen. 117 00:05:45,490 --> 00:05:48,150 It tells us what level we're on before we can actually play, 118 00:05:48,150 --> 00:05:51,030 and there will be a transition box with text in it. 119 00:05:51,030 --> 00:05:54,270 It'll come down, stop, and then come down again. 120 00:05:54,270 --> 00:05:59,280 So almost like chain behavior, which we'll see how we implement that too. 121 00:05:59,280 --> 00:06:03,510 And then lastly, on the bottom there is our main game screen, 122 00:06:03,510 --> 00:06:05,700 where we have a level, a score, and then a goal. 123 00:06:05,700 --> 00:06:10,090 If you get the goal amount of points before the timer runs out, 124 00:06:10,090 --> 00:06:12,180 then you go to level 2, and level 3, and level 4, 125 00:06:12,180 --> 00:06:16,477 and the score increases by a multiplied factor each time. 126 00:06:16,477 --> 00:06:18,810 So the first thing I'd like to start talking about today 127 00:06:18,810 --> 00:06:22,590 is how we actually get timer behavior using something a little bit more 128 00:06:22,590 --> 00:06:25,260 than just keeping track of some variable that we set to 0, 129 00:06:25,260 --> 00:06:28,210 and then adding dt to it every update. 130 00:06:28,210 --> 00:06:31,230 There's a better way to do that, but first, why don't we 131 00:06:31,230 --> 00:06:33,510 go ahead, and look at timer0. 132 00:06:33,510 --> 00:06:37,330 And so what I'm going to do is go into the timer0 directory. 133 00:06:37,330 --> 00:06:40,380 I'm going run it, and we can see here, in the middle of the screen, 134 00:06:40,380 --> 00:06:41,550 just a very simple-- 135 00:06:41,550 --> 00:06:44,460 just a label that just says timer, and then x seconds, 136 00:06:44,460 --> 00:06:49,290 where obviously the x is incrementing over time every second. 137 00:06:49,290 --> 00:06:53,250 So a crude way, what would be an easy way to implement this? 138 00:06:53,250 --> 00:06:56,208 139 00:06:56,208 --> 00:07:00,152 AUDIENCE: Do you like [INAUDIBLE] random in Flappy Bird [INAUDIBLE] randomizer 140 00:07:00,152 --> 00:07:04,096 [INAUDIBLE] if you just keep track of your delta prime 141 00:07:04,096 --> 00:07:11,491 and add it to some variable outside [INAUDIBLE] you do something else? 142 00:07:11,491 --> 00:07:16,025 You could even just display the variable [INAUDIBLE].. 143 00:07:16,025 --> 00:07:16,650 SPEAKER 1: Yes. 144 00:07:16,650 --> 00:07:23,700 So the response was keep some variable that you modify with dt in update, 145 00:07:23,700 --> 00:07:25,110 or display the variable. 146 00:07:25,110 --> 00:07:26,370 Yeah, that's definitely a way. 147 00:07:26,370 --> 00:07:26,820 Did you have-- 148 00:07:26,820 --> 00:07:29,444 AUDIENCE: Yeah, I was just going to say, keep a float variable, 149 00:07:29,444 --> 00:07:32,146 and constantly add a dt to it, and display it, 150 00:07:32,146 --> 00:07:33,880 but display the truncated version. 151 00:07:33,880 --> 00:07:34,740 SPEAKER 1: Yeah. 152 00:07:34,740 --> 00:07:39,730 So keep a float variable, but just truncate the delta time off of it. 153 00:07:39,730 --> 00:07:41,260 You could do that, definitely. 154 00:07:41,260 --> 00:07:44,240 We'll take a look here as to actually how I did do it. 155 00:07:44,240 --> 00:07:45,720 It's very similar to that. 156 00:07:45,720 --> 00:07:47,220 This is the wrong directory, though. 157 00:07:47,220 --> 00:07:50,679 So it's in timer0 in main. 158 00:07:50,679 --> 00:07:51,720 So we do have a variable. 159 00:07:51,720 --> 00:07:57,360 So the current second here, which we are going to keep track of 0, 1, 2. 160 00:07:57,360 --> 00:08:02,112 Lua doesn't really have the notion of truncate a float 161 00:08:02,112 --> 00:08:04,320 because when you take a number that's floating point, 162 00:08:04,320 --> 00:08:06,411 and you make it into a string, you actually 163 00:08:06,411 --> 00:08:08,160 have to do string substitution on it where 164 00:08:08,160 --> 00:08:14,104 you use a function called g sub to take off the last part manually 165 00:08:14,104 --> 00:08:16,770 because it doesn't really differentiate between ints and floats. 166 00:08:16,770 --> 00:08:19,790 It just has a number data type. 167 00:08:19,790 --> 00:08:22,080 But we can do this by just keeping track of 168 00:08:22,080 --> 00:08:24,690 whether or not we've passed a certain length of time 169 00:08:24,690 --> 00:08:27,840 because we know dt is given to us in seconds. 170 00:08:27,840 --> 00:08:32,010 We can just add to our variable, and then every time we've 171 00:08:32,010 --> 00:08:34,470 gone over 1, because it gives us-- 172 00:08:34,470 --> 00:08:39,330 it gives you usually like .013, whatever 1/60 or approximately 1/60 of a second 173 00:08:39,330 --> 00:08:40,169 is. 174 00:08:40,169 --> 00:08:44,560 Once our timer-- we're going to keep a timer variable-- equals 1, 175 00:08:44,560 --> 00:08:47,400 we'll just increment current second by 1, 176 00:08:47,400 --> 00:08:49,586 and then we'll set that timer back to 0, and then 177 00:08:49,586 --> 00:08:51,210 we'll just repeat over, and over again. 178 00:08:51,210 --> 00:08:54,960 We'll actually use modulus so in case we go slightly over 1 second, 179 00:08:54,960 --> 00:08:56,400 we can account for that. 180 00:08:56,400 --> 00:08:57,090 We do that here. 181 00:08:57,090 --> 00:08:59,630 So second timer gets second timer plus delta time, 182 00:08:59,630 --> 00:09:01,000 and then if it's greater than 1. 183 00:09:01,000 --> 00:09:04,920 So if a full second has elapsed, just increment current second, 184 00:09:04,920 --> 00:09:07,480 and then modulo a second timer by 1. 185 00:09:07,480 --> 00:09:10,240 And Lua is a little different in that most languages only let 186 00:09:10,240 --> 00:09:13,771 you modulo something if it's an integer, but since there is no differentiation, 187 00:09:13,771 --> 00:09:15,520 you can actually modulo floats, and you'll 188 00:09:15,520 --> 00:09:17,350 get the floating point value leftover. 189 00:09:17,350 --> 00:09:21,035 And so that's the basic way of actually doing that, 190 00:09:21,035 --> 00:09:22,910 but there's a couple of things wrong with it. 191 00:09:22,910 --> 00:09:26,714 So does anybody want to suggest what is potentially bad or unscalable 192 00:09:26,714 --> 00:09:27,880 about this kind of approach? 193 00:09:27,880 --> 00:09:32,921 194 00:09:32,921 --> 00:09:34,670 Well, I'll show you timer1 so we can maybe 195 00:09:34,670 --> 00:09:40,080 get a sense of how this could kind of get out of hand pretty quickly. 196 00:09:40,080 --> 00:09:42,890 So let's say-- first, I'll run timer1. 197 00:09:42,890 --> 00:09:49,820 So let's go into timer1 here, and notice now we have five labels. 198 00:09:49,820 --> 00:09:51,800 They're running at different intervals. 199 00:09:51,800 --> 00:09:55,130 The first timer, it's incrementing every 1 second, 200 00:09:55,130 --> 00:09:58,010 the second timer is incrementing every 4 seconds, 201 00:09:58,010 --> 00:10:03,800 the third one is incrementing every 4 seconds, and then so on, 3, and then 2. 202 00:10:03,800 --> 00:10:08,009 So if we wanted to do the same approach that we just did, 203 00:10:08,009 --> 00:10:09,050 this is what we would do. 204 00:10:09,050 --> 00:10:12,802 We have five variables, five timers. 205 00:10:12,802 --> 00:10:14,760 Because we want to keep track of whether or not 206 00:10:14,760 --> 00:10:17,504 something's gone over more than just one second, 207 00:10:17,504 --> 00:10:19,670 it's not super easy to just put this all in a table, 208 00:10:19,670 --> 00:10:22,790 and iterate over it, and use your iteration logic to do that. 209 00:10:22,790 --> 00:10:27,470 We actually, because they're in some sort of random, who knows what order, 210 00:10:27,470 --> 00:10:33,830 timer2 takes 2 seconds, OK, timer3 takes 4 seconds, timer4 takes 3, and then 2, 211 00:10:33,830 --> 00:10:37,209 you have to unmanageably keep all of this in separate variables. 212 00:10:37,209 --> 00:10:37,834 [? Yes, Tony ?] 213 00:10:37,834 --> 00:10:41,706 AUDIENCE: Couldn't you just use one second timer, or even one variable, 214 00:10:41,706 --> 00:10:46,605 and then just in the display [INAUDIBLE] 215 00:10:46,605 --> 00:10:47,480 SPEAKER 1: You could. 216 00:10:47,480 --> 00:10:49,010 Yeah, in this case, you could. 217 00:10:49,010 --> 00:10:54,170 Again, Lua's display, it's a little bit funky when you-- 218 00:10:54,170 --> 00:10:56,645 you have to do g sub, and some weird string stuff, 219 00:10:56,645 --> 00:10:57,770 but yes, you could do that. 220 00:10:57,770 --> 00:11:01,682 AUDIENCE: Couldn't you just do modulo 1, and then take that value as a string? 221 00:11:01,682 --> 00:11:04,130 Is that the equivalent of truncating? 222 00:11:04,130 --> 00:11:07,970 SPEAKER 1: Modulo 1 would still give you the floating point value 223 00:11:07,970 --> 00:11:09,750 because there's only one number type. 224 00:11:09,750 --> 00:11:14,950 So if we modulo 1.00157 by 1, we'd get 0.00157. 225 00:11:14,950 --> 00:11:16,450 AUDIENCE: Oh. 226 00:11:16,450 --> 00:11:17,450 OK. 227 00:11:17,450 --> 00:11:21,080 If you subtracted from that value, from I don't know. 228 00:11:21,080 --> 00:11:24,860 So it's a value minus the value of modulo 1, I guess. 229 00:11:24,860 --> 00:11:25,910 SPEAKER 1: So yeah. 230 00:11:25,910 --> 00:11:29,030 It was proposed that we've used modulo, and we could. 231 00:11:29,030 --> 00:11:33,589 In short, we could, but what if we're not just 232 00:11:33,589 --> 00:11:34,880 printing a value to the screen. 233 00:11:34,880 --> 00:11:38,840 What if we have 10 different things, like 10 different creatures that 234 00:11:38,840 --> 00:11:40,926 are all doing different things over time, 235 00:11:40,926 --> 00:11:43,550 and we don't necessarily want to have to keep a timer for each, 236 00:11:43,550 --> 00:11:44,799 and every one of those things. 237 00:11:44,799 --> 00:11:47,510 In a simple example like this, yeah, there's probably a-- 238 00:11:47,510 --> 00:11:49,820 on purpose, it's also a little bit convoluted just 239 00:11:49,820 --> 00:11:50,960 to illustrate the problem. 240 00:11:50,960 --> 00:11:54,770 But yes, there are shortcuts for this, but the fundamental problem 241 00:11:54,770 --> 00:12:00,840 is how can we get rid of having five different timers for something? 242 00:12:00,840 --> 00:12:02,590 And by the way, I'll go to the next slide. 243 00:12:02,590 --> 00:12:03,548 Timer0, the simple way. 244 00:12:03,548 --> 00:12:05,080 Timer1, the ugly way. 245 00:12:05,080 --> 00:12:10,860 Timer2 is the clean way that I found using this ecosystem. 246 00:12:10,860 --> 00:12:14,090 There's a wonderful library, and you could implement this yourself. 247 00:12:14,090 --> 00:12:17,180 The fundamental idea is have a global timer 248 00:12:17,180 --> 00:12:20,570 object that then manages all of these different things going 249 00:12:20,570 --> 00:12:25,625 on using the power of what I alluded to earlier, anonymous functions, 250 00:12:25,625 --> 00:12:27,000 and I'll show you how that works. 251 00:12:27,000 --> 00:12:32,627 So in main.lua of timer2, we have a set of intervals. 252 00:12:32,627 --> 00:12:33,710 We have a set of counters. 253 00:12:33,710 --> 00:12:36,530 254 00:12:36,530 --> 00:12:42,620 And then what we're doing here is we're just saying for i gets 1 to 5, 255 00:12:42,620 --> 00:12:45,427 we're calling a function call timer.every. 256 00:12:45,427 --> 00:12:47,510 So if you're familiar with JavaScript programming, 257 00:12:47,510 --> 00:12:49,310 there's a set interval function which lets 258 00:12:49,310 --> 00:12:52,582 you do something every length of time. 259 00:12:52,582 --> 00:12:54,290 So first of all, timer is just a library. 260 00:12:54,290 --> 00:12:55,456 We've just required it here. 261 00:12:55,456 --> 00:13:01,040 It's part of the knife ecosystem, and then 262 00:13:01,040 --> 00:13:04,940 here, we have a couple of functions, timer.every, and timer.after 263 00:13:04,940 --> 00:13:06,530 that we'll use. 264 00:13:06,530 --> 00:13:09,440 Well, basically, what it does is you give it 265 00:13:09,440 --> 00:13:12,190 a length of time-- timer.every seconds. 266 00:13:12,190 --> 00:13:14,809 It's in seconds, and you can give it fractional seconds. 267 00:13:14,809 --> 00:13:17,600 You're passing in just a function here, just an anonymous function. 268 00:13:17,600 --> 00:13:21,410 It doesn't have a name, but because Lua, and a lot of dynamic languages 269 00:13:21,410 --> 00:13:24,750 treat functions as first class citizens, as it 270 00:13:24,750 --> 00:13:30,770 called, because they are data types, you can just pass them into functions. 271 00:13:30,770 --> 00:13:33,320 This allows us to do behavior like this that would otherwise 272 00:13:33,320 --> 00:13:34,700 be a little bit tricky to do. 273 00:13:34,700 --> 00:13:37,640 We can just say after this block of time, 274 00:13:37,640 --> 00:13:41,180 assuming we've built some structure that is probably just storing 275 00:13:41,180 --> 00:13:45,650 a table with a bunch of things that have a length of time in them, 276 00:13:45,650 --> 00:13:47,840 just call this block of code later. 277 00:13:47,840 --> 00:13:49,730 It's called a callback function. 278 00:13:49,730 --> 00:13:52,688 We're just going to call it back, and then we're just going to do this. 279 00:13:52,688 --> 00:13:55,460 We're going to say counters i gets counters i plus 1. 280 00:13:55,460 --> 00:13:59,322 So we have all of these intervals, and all of these counters. 281 00:13:59,322 --> 00:14:01,280 So it will just, basically, manage that for us, 282 00:14:01,280 --> 00:14:04,430 and now we don't have five variables. 283 00:14:04,430 --> 00:14:07,630 You do have to set whatever you want those to be. 284 00:14:07,630 --> 00:14:09,630 That's your that's your primitive at this point. 285 00:14:09,630 --> 00:14:14,245 You just need the lengths of time, depending on your problem. 286 00:14:14,245 --> 00:14:15,620 In this case, that's all we need. 287 00:14:15,620 --> 00:14:18,160 You might need more than that, depending on what you want to do with timer. 288 00:14:18,160 --> 00:14:20,785 But in this case, we just want to increment in value over time. 289 00:14:20,785 --> 00:14:23,734 So keep counters, and then just keep track of the intervals, 290 00:14:23,734 --> 00:14:26,150 and then our code's gone from I don't know how many lines. 291 00:14:26,150 --> 00:14:27,860 It was a lot larger-- 292 00:14:27,860 --> 00:14:35,860 I think was 96 lines, down to 98 lines, down to 70, 293 00:14:35,860 --> 00:14:37,800 and this is incredibly scalable. 294 00:14:37,800 --> 00:14:41,550 If we wanted to add another one that's 8 for example, 295 00:14:41,550 --> 00:14:44,370 we just need to add 8, and then that. 296 00:14:44,370 --> 00:14:48,830 I guess I'd have to do this as well. 297 00:14:48,830 --> 00:14:54,750 I gets 5 to 6, and then you want to-- the computer that requires me 298 00:14:54,750 --> 00:14:58,260 to off my user so I can make changes. 299 00:14:58,260 --> 00:15:01,090 We'll just real quickly see if I didn't mess up. 300 00:15:01,090 --> 00:15:05,180 301 00:15:05,180 --> 00:15:08,190 And so yeah, basically we're deferring everything to timer now. 302 00:15:08,190 --> 00:15:12,327 We get the exact same behavior, but a much smaller length of code. 303 00:15:12,327 --> 00:15:14,160 And the nice thing is it's very declarative. 304 00:15:14,160 --> 00:15:18,330 We can just say OK, every something seconds, I want this chunk of behavior 305 00:15:18,330 --> 00:15:18,840 to happen. 306 00:15:18,840 --> 00:15:22,440 I don't have to see OK, I've got timers up here, I've got counters here. 307 00:15:22,440 --> 00:15:25,810 OK, down in my draw function, OK, I've got to draw all these. 308 00:15:25,810 --> 00:15:30,045 It's iterative, and it's declarative, and that's the ultimate goal. 309 00:15:30,045 --> 00:15:32,170 And here, at the very bottom, it did actually work. 310 00:15:32,170 --> 00:15:34,630 Now it's working every eight seconds, which is nice. 311 00:15:34,630 --> 00:15:37,200 One, two, there we go. 312 00:15:37,200 --> 00:15:39,570 Super easy to extend. 313 00:15:39,570 --> 00:15:42,510 We're going to be using it a lot in this problem set, 314 00:15:42,510 --> 00:15:46,350 and also in future lectures just because it's a lot easier than keeping 315 00:15:46,350 --> 00:15:50,550 track of a bunch of counter variables. 316 00:15:50,550 --> 00:15:52,780 And there's another function that we're seeing here-- 317 00:15:52,780 --> 00:15:56,670 timer.after because sometimes you just want to wait a certain length of time. 318 00:15:56,670 --> 00:16:00,720 Maybe you have every 1 second for 5 seconds you want a bomb to tick, 319 00:16:00,720 --> 00:16:03,521 and then after 5 seconds, you want it to blow up, 320 00:16:03,521 --> 00:16:06,520 and you could also model that with another function that we'll see soon, 321 00:16:06,520 --> 00:16:12,477 but these are probably the two core time-based functions. 322 00:16:12,477 --> 00:16:15,060 And you can go here to this URL able to see the knife library. 323 00:16:15,060 --> 00:16:17,950 There's a bunch of modules that are really nice. 324 00:16:17,950 --> 00:16:20,280 We just happen to be using timer, and it's 325 00:16:20,280 --> 00:16:24,240 tween, and every after functions primarily in this problem. 326 00:16:24,240 --> 00:16:28,020 But we'll use another one called the event in the Zelda [? p-set, ?] where 327 00:16:28,020 --> 00:16:31,250 we actually look at how to dispatch events, and triggers, and stuff, 328 00:16:31,250 --> 00:16:33,120 and to prevent us from checking every frame. 329 00:16:33,120 --> 00:16:34,770 Oh, what do we have to do? 330 00:16:34,770 --> 00:16:38,350 If some wall is broken, this frame, then do this. 331 00:16:38,350 --> 00:16:40,770 We can just dispatch an event that we blow up a wall. 332 00:16:40,770 --> 00:16:42,900 We'll get to that. 333 00:16:42,900 --> 00:16:46,970 Any questions at all about how those two models differ, and how they work? 334 00:16:46,970 --> 00:16:49,490 335 00:16:49,490 --> 00:16:51,480 OK, cool. 336 00:16:51,480 --> 00:16:56,070 So the next thing I want to look at-- so we can tie that back into also, 337 00:16:56,070 --> 00:16:58,550 real quick, if we want. 338 00:16:58,550 --> 00:17:02,940 Match 3-- whoops, and then there's a timer that's 339 00:17:02,940 --> 00:17:06,859 manipulating the text on the screen. 340 00:17:06,859 --> 00:17:12,318 All of those letters in the-- this is in the start state of the game code. 341 00:17:12,318 --> 00:17:14,609 All of those letters have a color associated with them, 342 00:17:14,609 --> 00:17:17,940 but they're on a timer so that after every 0.075 seconds, 343 00:17:17,940 --> 00:17:20,183 they'll go to another color, and to another color. 344 00:17:20,183 --> 00:17:22,349 And so we don't have to keep track of every letter's 345 00:17:22,349 --> 00:17:24,359 individual color, and a timer for it. 346 00:17:24,359 --> 00:17:27,630 We can just change them all. 347 00:17:27,630 --> 00:17:33,030 If we start the game, something else that's on a timer, the timer, 348 00:17:33,030 --> 00:17:36,060 actually, there, which is just decrementing some value. 349 00:17:36,060 --> 00:17:39,434 Every one second, decrement timer by 1, and that's it, 350 00:17:39,434 --> 00:17:42,600 and we don't have to keep any-- we don't have to say anything more than just 351 00:17:42,600 --> 00:17:47,350 that, and that's what's really nice about using that kind of model. 352 00:17:47,350 --> 00:17:51,420 So another thing that you probably also noticed, and I'll run it again, 353 00:17:51,420 --> 00:17:55,800 is this fade out, and fade in, and also that animation. 354 00:17:55,800 --> 00:17:57,900 Those are things that are happening over time. 355 00:17:57,900 --> 00:18:01,290 We don't actually-- we can just sort of manipulate them. 356 00:18:01,290 --> 00:18:03,660 We can keep track of some sort of counter for it. 357 00:18:03,660 --> 00:18:07,890 We can also just say over this length of time, change this value to this value, 358 00:18:07,890 --> 00:18:11,050 and that's a much easier way to model the problem mentally. 359 00:18:11,050 --> 00:18:14,220 And so we'll illustrate that. 360 00:18:14,220 --> 00:18:16,200 First, I'm going to go to tween0. 361 00:18:16,200 --> 00:18:19,300 So tween0 is the simple way to do something. 362 00:18:19,300 --> 00:18:23,760 So I'm going to illustrate tweening here with Flappy Bird just going 363 00:18:23,760 --> 00:18:24,830 left to right. 364 00:18:24,830 --> 00:18:29,070 So up there, that's what happens when you print out the number, by the way, 365 00:18:29,070 --> 00:18:29,850 just by default. 366 00:18:29,850 --> 00:18:32,910 And so if you wanted to truncate it, yeah, you 367 00:18:32,910 --> 00:18:37,829 could just g sub the first two, I guess, depending on how large it is, 368 00:18:37,829 --> 00:18:40,620 and that would have the effect of displaying it as just an integer. 369 00:18:40,620 --> 00:18:44,220 But we can see that over two seconds, we've had-- 370 00:18:44,220 --> 00:18:47,400 and there's a little bit of overlap just because delta time can 371 00:18:47,400 --> 00:18:51,420 go a little bit over two seconds when you're adding to it because it just 372 00:18:51,420 --> 00:18:55,439 adds whatever length of time as a float has elapsed since the last frame. 373 00:18:55,439 --> 00:18:58,480 In this case, we're just adding it until it's greater than or equal to 2. 374 00:18:58,480 --> 00:19:02,335 So in this case, we went 0.01 over 2 by the time that actually ended. 375 00:19:02,335 --> 00:19:03,960 Some iterations will be less than that. 376 00:19:03,960 --> 00:19:06,180 So this one will be-- 377 00:19:06,180 --> 00:19:08,370 yeah, see, that one was less than 2.01. 378 00:19:08,370 --> 00:19:11,010 It just depends on your computer, and your specs. 379 00:19:11,010 --> 00:19:13,320 But Flappy Bird starts on the very left. 380 00:19:13,320 --> 00:19:16,110 So he's got an x-coordinate, and then at the very end, 381 00:19:16,110 --> 00:19:17,590 he's got another x-coordinate. 382 00:19:17,590 --> 00:19:21,735 So the simple solution is what? 383 00:19:21,735 --> 00:19:28,750 384 00:19:28,750 --> 00:19:32,060 We know that we want this to elapse over two seconds. 385 00:19:32,060 --> 00:19:35,550 So what we can do is I'm going to pull up tween0. 386 00:19:35,550 --> 00:19:42,536 387 00:19:42,536 --> 00:19:44,910 And MOVE_DURATION here, it's a constant of 2 seconds just 388 00:19:44,910 --> 00:19:46,865 for the sake of this example. 389 00:19:46,865 --> 00:19:48,930 A sprite here, just a simple image. 390 00:19:48,930 --> 00:19:53,610 I'm putting everything in one code file this time, as opposed to breaking it 391 00:19:53,610 --> 00:19:57,849 out into subclasses just for simplicity because these are such small examples. 392 00:19:57,849 --> 00:19:59,140 But we're setting it's x and y. 393 00:19:59,140 --> 00:20:01,056 Oh, and this is another Lua trick, by the way. 394 00:20:01,056 --> 00:20:05,490 You can assign two variables to two values using a comma here. 395 00:20:05,490 --> 00:20:08,720 So flappyX comma flappyY gets 0, and then VIRTUAL_HEIGHT 396 00:20:08,720 --> 00:20:10,440 divided by 2 minus 8. 397 00:20:10,440 --> 00:20:15,484 Setting this x to 0, we have a timer here, and then it's end x. 398 00:20:15,484 --> 00:20:17,400 So we want it to end at the end of the screen. 399 00:20:17,400 --> 00:20:20,880 So we're going to say virtual width minus his width, an then 400 00:20:20,880 --> 00:20:24,150 the usual boilerplate for getting a project set to go. 401 00:20:24,150 --> 00:20:30,390 If it's less than the move duration-- so if timer is 0 going up to 2, 402 00:20:30,390 --> 00:20:37,950 but it's not quite 2 yet, we're going to add dt to it, and then we're going to, 403 00:20:37,950 --> 00:20:43,230 basically, assign it to either the lowest of end x, 404 00:20:43,230 --> 00:20:49,500 so it will never go higher than end x, or end x times the ratio of timer 405 00:20:49,500 --> 00:20:51,030 over move duration. 406 00:20:51,030 --> 00:20:54,480 So timer over move duration, if it's less than 2, 407 00:20:54,480 --> 00:20:59,070 that's going to be some value, some fractional amount less than 1. 408 00:20:59,070 --> 00:21:01,620 So it's going to basically just scale it, 409 00:21:01,620 --> 00:21:07,780 depending on how far we've moved the timer between 0 and 2. 410 00:21:07,780 --> 00:21:09,710 So just a scaling operation. 411 00:21:09,710 --> 00:21:13,680 This happens to only work in the context of moving something from left to right, 412 00:21:13,680 --> 00:21:18,480 or from 0 to something else, but it's a crude, basic way of illustrating 413 00:21:18,480 --> 00:21:20,261 a very basic tween operation. 414 00:21:20,261 --> 00:21:21,510 That's what it essentially is. 415 00:21:21,510 --> 00:21:25,440 It's a multiplier of some ratio of how much time has passed, 416 00:21:25,440 --> 00:21:28,770 versus how much time we're actually looking to elapse. 417 00:21:28,770 --> 00:21:31,830 And that has the effect, once again, of just-- 418 00:21:31,830 --> 00:21:35,750 it's scaling the ratio because it's timer over moved duration. 419 00:21:35,750 --> 00:21:38,130 It's something over 2, but it's not quite 2 over 2. 420 00:21:38,130 --> 00:21:42,690 Until it gets 2 over 2, and it's 1, then end x times 1 is going to be end x. 421 00:21:42,690 --> 00:21:47,670 But before that, it's going to be some fraction of end x between 0 and end x. 422 00:21:47,670 --> 00:21:51,960 So it has the effect of giving us a very basic tween, but it's a little bit-- 423 00:21:51,960 --> 00:21:54,810 we have a little bit to manage here. 424 00:21:54,810 --> 00:21:56,670 It doesn't really feel super clean. 425 00:21:56,670 --> 00:22:00,360 Do you guys have any questions about how this works? 426 00:22:00,360 --> 00:22:01,800 OK. 427 00:22:01,800 --> 00:22:04,450 So we're going to go here. 428 00:22:04,450 --> 00:22:11,460 So first of all, any thoughts about how that might not be super scalable, 429 00:22:11,460 --> 00:22:13,080 looking back at the last example? 430 00:22:13,080 --> 00:22:17,850 431 00:22:17,850 --> 00:22:20,699 AUDIENCE: I guess like the situation before, 432 00:22:20,699 --> 00:22:22,615 getting a lot of objects moving on the screen. 433 00:22:22,615 --> 00:22:25,698 SPEAKER 1: Yeah, and what if your index is different for every single one? 434 00:22:25,698 --> 00:22:28,470 Then you have kind of a mess. 435 00:22:28,470 --> 00:22:31,020 What if we had something like this? 436 00:22:31,020 --> 00:22:34,110 437 00:22:34,110 --> 00:22:39,090 You don't want to keep track of an end to x. 438 00:22:39,090 --> 00:22:41,596 They all happened to have the same end x, 439 00:22:41,596 --> 00:22:43,470 but notice they're moving at different rates. 440 00:22:43,470 --> 00:22:47,025 They're all moving at some sort of random amount. 441 00:22:47,025 --> 00:22:48,240 AUDIENCE: How many are there? 442 00:22:48,240 --> 00:22:52,680 SPEAKER 1: There's 1,000. 443 00:22:52,680 --> 00:22:54,840 We could go crazier if we wanted. 444 00:22:54,840 --> 00:22:58,540 This is a fun thing to do, is stress testing. 445 00:22:58,540 --> 00:23:04,000 So if I go to tween1, and I go to main, timer max is 10. 446 00:23:04,000 --> 00:23:06,540 So we're saying that the longest possible time 447 00:23:06,540 --> 00:23:11,130 any bird can take to get from left to right is going be 10 seconds. 448 00:23:11,130 --> 00:23:14,310 So right here, we're using a table based approach here. 449 00:23:14,310 --> 00:23:17,830 We're actually keeping track of 1,000 birds, and we're saying, 450 00:23:17,830 --> 00:23:20,220 OK, here's an empty table from 1 to 1,000. 451 00:23:20,220 --> 00:23:23,480 Add a new bird, and in this case, we're not adding a bird object, or anything. 452 00:23:23,480 --> 00:23:24,750 It's just a table. 453 00:23:24,750 --> 00:23:26,970 They all start x equals 0, left side. 454 00:23:26,970 --> 00:23:28,485 Their y is random. 455 00:23:28,485 --> 00:23:31,360 So they can be anywhere between the top and the bottom of the screen. 456 00:23:31,360 --> 00:23:32,484 So VIRTUAL_HEIGHT minus 24. 457 00:23:32,484 --> 00:23:34,710 24 happens to be the height of the sprite, 458 00:23:34,710 --> 00:23:37,677 and I should have probably put Flappy sprite get height right there. 459 00:23:37,677 --> 00:23:40,010 And then rate, they're all going to have their own rate. 460 00:23:40,010 --> 00:23:41,370 So rate gets math.random. 461 00:23:41,370 --> 00:23:44,790 Math.random without a value passed into it 462 00:23:44,790 --> 00:23:52,030 gives you a fractional value between 0 and 0.999999. 463 00:23:52,030 --> 00:23:55,500 What this has the effect of doing is math.random with just two values, 464 00:23:55,500 --> 00:23:58,500 if you pass in 10 and 50, it's going to give you 10 to 50, 465 00:23:58,500 --> 00:24:00,880 but they're always going to be integer values. 466 00:24:00,880 --> 00:24:03,830 You can't say like 10.0 and 50.0, and assume that it 467 00:24:03,830 --> 00:24:05,330 will know what you're talking about. 468 00:24:05,330 --> 00:24:06,790 It's just going to be integers. 469 00:24:06,790 --> 00:24:08,880 So if you give it one value, it will know. 470 00:24:08,880 --> 00:24:13,050 OK, you're asking me for a float between 0 and 0.999999. 471 00:24:13,050 --> 00:24:16,230 That's going to act as the fractional part of whatever value we 472 00:24:16,230 --> 00:24:20,500 might want to generate using a math.random with a value passed in. 473 00:24:20,500 --> 00:24:24,870 So here, we're saying OK, math.random, TIMER_MAX minus 1. 474 00:24:24,870 --> 00:24:26,580 So TIMER_MAX is 9. 475 00:24:26,580 --> 00:24:29,460 So our TIMER_MAX is 10, sorry. 476 00:24:29,460 --> 00:24:33,630 So if we subtract 1 from that, this is math.random 10. 477 00:24:33,630 --> 00:24:37,170 So we're going to get a value between 1 and 9. 478 00:24:37,170 --> 00:24:38,880 So TIMER_MAX minus 1 is 9. 479 00:24:38,880 --> 00:24:39,990 Sorry if I said 10. 480 00:24:39,990 --> 00:24:43,260 TIMER_MAX is 10, TIMER_MAX minus 1 is 9, but we're 481 00:24:43,260 --> 00:24:46,500 adding math.random, some fractional amount. 482 00:24:46,500 --> 00:24:49,110 So whatever value we choose between 1-- 483 00:24:49,110 --> 00:24:53,460 actually between-- yeah, between 1 and 9, 484 00:24:53,460 --> 00:24:58,170 it's going to be that value, point something. 485 00:24:58,170 --> 00:24:59,670 So this is how you get random-- 486 00:24:59,670 --> 00:25:01,378 basically, at the end of the day, this is 487 00:25:01,378 --> 00:25:07,265 how you get random floating point numbers in Lua and Love2D. 488 00:25:07,265 --> 00:25:08,140 Does that make sense? 489 00:25:08,140 --> 00:25:09,723 Do you guys have questions about that? 490 00:25:09,723 --> 00:25:12,420 AUDIENCE: So your final rate could be anywhere from 0 to-- 491 00:25:12,420 --> 00:25:15,461 SPEAKER 1: Final rate is going to be anywhere from 1-- in this case from, 492 00:25:15,461 --> 00:25:19,620 1 to 9.999999. 493 00:25:19,620 --> 00:25:22,450 If we wanted it to be 0, we could do that, 494 00:25:22,450 --> 00:25:26,520 and that'll give us the effect of taking whatever we get, and subtracting 1. 495 00:25:26,520 --> 00:25:32,070 So now it will be between 0 and 8.999999. 496 00:25:32,070 --> 00:25:32,970 And if we did this-- 497 00:25:32,970 --> 00:25:35,650 498 00:25:35,650 --> 00:25:39,890 AUDIENCE: Couldn't each math.random end up at 0? 499 00:25:39,890 --> 00:25:43,110 SPEAKER 1: No, because math.random, if you pass in a value, 500 00:25:43,110 --> 00:25:46,036 it'll always do from 1 to some value. 501 00:25:46,036 --> 00:25:50,310 The question was will math.random give you 0 if you pass in a value? 502 00:25:50,310 --> 00:25:54,560 And math.random, by default, gives you between 1 and something else. 503 00:25:54,560 --> 00:25:57,027 And so that's why we do this. 504 00:25:57,027 --> 00:25:58,110 That's not why we do this. 505 00:25:58,110 --> 00:26:00,990 We do this to add the fractional part so that we can get 506 00:26:00,990 --> 00:26:04,110 fractional floats between some value. 507 00:26:04,110 --> 00:26:07,132 But yeah, if you wanted it to be between 0, and something else, 508 00:26:07,132 --> 00:26:09,090 you would just subtract 1 from the final result 509 00:26:09,090 --> 00:26:12,900 because we know that we're always going to get from 1 to some value. 510 00:26:12,900 --> 00:26:15,120 If you minus from 1, you will never go below 0. 511 00:26:15,120 --> 00:26:17,799 It will always be 0 to something else, and then in that case, 512 00:26:17,799 --> 00:26:19,590 we probably would just take off the minus 1 513 00:26:19,590 --> 00:26:26,640 from TIMER_MAX so that it will be between 0 and 9.999999 in this case. 514 00:26:26,640 --> 00:26:29,732 But as a design decision, I made it so that we would always 515 00:26:29,732 --> 00:26:31,440 have at least a rate of 1 because then it 516 00:26:31,440 --> 00:26:36,820 could get really, really slow if it's like 0.005 or something like that. 517 00:26:36,820 --> 00:26:37,860 You wouldn't want that. 518 00:26:37,860 --> 00:26:38,651 It would take ages. 519 00:26:38,651 --> 00:26:42,510 520 00:26:42,510 --> 00:26:45,680 OK, so we have a timer. 521 00:26:45,680 --> 00:26:50,095 We're not using knife.timer in this case yet. 522 00:26:50,095 --> 00:26:53,220 Basically, in update, we're just saying as long as timer max is less than-- 523 00:26:53,220 --> 00:26:55,980 timer is less than timer max. 524 00:26:55,980 --> 00:27:00,560 This update logic will only run as long as we haven't gone over timer max. 525 00:27:00,560 --> 00:27:04,532 Increment it, and then for each bird, basically, we're 526 00:27:04,532 --> 00:27:06,990 doing the same thing that we did before, except we're using 527 00:27:06,990 --> 00:27:09,770 that bird's rate as the scale factor. 528 00:27:09,770 --> 00:27:13,560 Yeah, the denominator of that ratio, and that 529 00:27:13,560 --> 00:27:16,710 will have the effect of multiplying all of those birds 530 00:27:16,710 --> 00:27:19,230 individually, based on their own rate, rather than 531 00:27:19,230 --> 00:27:23,190 some global rate, if that makes sense. 532 00:27:23,190 --> 00:27:27,260 And then here, we're just drawing all of them at their own x and y. 533 00:27:27,260 --> 00:27:30,630 And just again, we're just storing birds are just 534 00:27:30,630 --> 00:27:32,670 a table with a few variables in this case. 535 00:27:32,670 --> 00:27:36,540 Just a very simple shell, and it has the effect of-- 536 00:27:36,540 --> 00:27:41,570 oh, and one thing I wanted to do is just add a 0 there. 537 00:27:41,570 --> 00:27:43,890 I've got to do this every time because I didn't 538 00:27:43,890 --> 00:27:45,802 set my permissions appropriately. 539 00:27:45,802 --> 00:27:47,510 But now there's going to be 10,000 birds. 540 00:27:47,510 --> 00:27:50,260 So let's see how this looks. 541 00:27:50,260 --> 00:27:53,820 So it looks pretty similar, actually, but it's a little more condensed now. 542 00:27:53,820 --> 00:27:55,950 I don't notice a frame rate drop. 543 00:27:55,950 --> 00:28:04,340 If we wanted, we could go down to love.draw, and love.graphics.printf 544 00:28:04,340 --> 00:28:15,396 at FPS, and then to string, love.timer.getFPS, and then 545 00:28:15,396 --> 00:28:24,330 let's set it to 4, and then VIRTUAL_HEIGHT minus 16, 546 00:28:24,330 --> 00:28:26,220 and then got to do this again. 547 00:28:26,220 --> 00:28:28,990 This should have the effect of giving us our frame rate. 548 00:28:28,990 --> 00:28:34,580 So we can really stress test this, and see what the-- 549 00:28:34,580 --> 00:28:35,080 oh. 550 00:28:35,080 --> 00:28:36,670 I made a mistake. 551 00:28:36,670 --> 00:28:37,440 OK, let's see. 552 00:28:37,440 --> 00:28:38,820 What did I do? 553 00:28:38,820 --> 00:28:40,830 Push.start. 554 00:28:40,830 --> 00:28:42,030 I'm guessing I missed a-- 555 00:28:42,030 --> 00:28:43,176 yeah, I missed a-- 556 00:28:43,176 --> 00:28:46,830 557 00:28:46,830 --> 00:28:51,970 do that, and then that, and then save it again. 558 00:28:51,970 --> 00:28:52,760 Sorry about that. 559 00:28:52,760 --> 00:28:54,968 There won't be too many of these edits, but I figured 560 00:28:54,968 --> 00:28:56,670 this would be fun to illustrate. 561 00:28:56,670 --> 00:28:59,100 So now, this should work. 562 00:28:59,100 --> 00:29:01,630 563 00:29:01,630 --> 00:29:05,224 Printf, so we have that. 564 00:29:05,224 --> 00:29:08,040 Oh, right, and then it just needs to be print. 565 00:29:08,040 --> 00:29:10,830 It doesn't need to be printf. 566 00:29:10,830 --> 00:29:12,750 Got to save again. 567 00:29:12,750 --> 00:29:14,450 Sorry. 568 00:29:14,450 --> 00:29:18,220 This will be worth it, I hope. 569 00:29:18,220 --> 00:29:20,326 There we go, 5160. 570 00:29:20,326 --> 00:29:21,700 OK, it takes a couple of seconds. 571 00:29:21,700 --> 00:29:24,540 It has to interpolate between the last couple of times 572 00:29:24,540 --> 00:29:26,964 that it's pulled for frames, and when you start up, 573 00:29:26,964 --> 00:29:28,380 it doesn't have the data it needs. 574 00:29:28,380 --> 00:29:31,620 So 10,000, easy. 575 00:29:31,620 --> 00:29:34,360 Let's do like a million. 576 00:29:34,360 --> 00:29:39,480 So we have 10,000, 100,000, a million. 577 00:29:39,480 --> 00:29:41,660 I really got to change those permissions. 578 00:29:41,660 --> 00:29:44,440 Getting good at practicing my password, though. 579 00:29:44,440 --> 00:29:46,868 Going to go ahead, and do that. 580 00:29:46,868 --> 00:29:48,150 Ooh. 581 00:29:48,150 --> 00:29:50,640 Oh, my laptop is suffering. 582 00:29:50,640 --> 00:29:53,700 Oh man, but they're all moving independent of frame rate. 583 00:29:53,700 --> 00:29:56,910 This is just a testament to how powerful delta time is. 584 00:29:56,910 --> 00:29:59,070 They all move there after 10 seconds. 585 00:29:59,070 --> 00:30:01,670 We've got to 10.6 seconds, which is not good. 586 00:30:01,670 --> 00:30:04,470 That means that's how long passed between the last frame, 587 00:30:04,470 --> 00:30:08,850 but my laptop clearly can not handle a million birds on the screen, 588 00:30:08,850 --> 00:30:12,450 but it can handle 10,000, or maybe even 100,000. 589 00:30:12,450 --> 00:30:13,740 And that's just a fun way-- 590 00:30:13,740 --> 00:30:15,420 a fun thing to do. 591 00:30:15,420 --> 00:30:18,210 In general, when you want to stress test your game, 592 00:30:18,210 --> 00:30:21,210 just put the frames per second on, and just go nuts. 593 00:30:21,210 --> 00:30:22,740 Just add a lot of stuff. 594 00:30:22,740 --> 00:30:25,710 Just see what your computer is capable of because you 595 00:30:25,710 --> 00:30:29,630 can find new, fun things that way, I guess, and maybe just 596 00:30:29,630 --> 00:30:32,840 see how good your code is too. 597 00:30:32,840 --> 00:30:35,100 So tween0, simple way. 598 00:30:35,100 --> 00:30:38,490 We have just variables, and one counter. 599 00:30:38,490 --> 00:30:40,110 No tables or anything. 600 00:30:40,110 --> 00:30:43,969 Tween2 is a good way for if we have a lot of things 601 00:30:43,969 --> 00:30:45,510 that we want to manipulate over time. 602 00:30:45,510 --> 00:30:49,650 But what if now we want some of them to change 603 00:30:49,650 --> 00:30:52,950 their opacity over time or something? 604 00:30:52,950 --> 00:30:55,241 It starts to get a little bit more complicated. 605 00:30:55,241 --> 00:30:57,990 And this is, by the way, I should've put this earlier in the code, 606 00:30:57,990 --> 00:31:03,360 but this is the knife library is responsible for timer, 607 00:31:03,360 --> 00:31:05,806 and a lot of other things that we'll be looking at, 608 00:31:05,806 --> 00:31:07,680 and it's got a bunch of modules here listed-- 609 00:31:07,680 --> 00:31:09,986 behavior for state machines, which is like what 610 00:31:09,986 --> 00:31:13,110 we've been doing for state machines, but they have their own version of it. 611 00:31:13,110 --> 00:31:16,290 Knife.bind, so you can pre-bind arguments to functions, 612 00:31:16,290 --> 00:31:18,230 and create subfunction. 613 00:31:18,230 --> 00:31:20,940 It's called currying, but create subfunctions of other functions 614 00:31:20,940 --> 00:31:23,750 that have pre-determined variables. 615 00:31:23,750 --> 00:31:28,740 Knife.chain, we'll see, actually, how that can be used coming up later. 616 00:31:28,740 --> 00:31:30,570 Convoke is for coroutines. 617 00:31:30,570 --> 00:31:32,520 We'll see coroutines in the context of Unity, 618 00:31:32,520 --> 00:31:36,570 but basically, they're functions that can pause their state for later. 619 00:31:36,570 --> 00:31:41,580 Knife.event we'll use in two weeks for Zelda, 620 00:31:41,580 --> 00:31:44,510 maybe even next week if I can fit it in for Mario. 621 00:31:44,510 --> 00:31:46,980 Memoize is for memoization. 622 00:31:46,980 --> 00:31:49,810 It's like a dynamic programming related thing. 623 00:31:49,810 --> 00:31:51,720 Serialized system. 624 00:31:51,720 --> 00:31:55,620 System is going to be useful to know about in context of Unity as well. 625 00:31:55,620 --> 00:31:59,230 Unity uses an entity component system for much of its structure. 626 00:31:59,230 --> 00:32:01,830 Knife.test, and then lastly, knife.timer, 627 00:32:01,830 --> 00:32:05,970 which is what we'll end up using, and this is probably my favorite library 628 00:32:05,970 --> 00:32:09,290 that exists in the Love2D ecosystem. 629 00:32:09,290 --> 00:32:12,540 And so with that said, we'll look at tween2 now. 630 00:32:12,540 --> 00:32:22,620 I'm going to go here into tween2, and so now we have not just movement, but also 631 00:32:22,620 --> 00:32:23,790 their opacity. 632 00:32:23,790 --> 00:32:26,460 They all start at different opacity levels, 633 00:32:26,460 --> 00:32:30,870 and we want to not only change their movement 634 00:32:30,870 --> 00:32:34,110 over time, but also the opacity. 635 00:32:34,110 --> 00:32:39,247 So it would get a little bit trickier if we decided 636 00:32:39,247 --> 00:32:40,830 to do that with our current situation. 637 00:32:40,830 --> 00:32:47,090 Totally doable, but how would we go about changing, just right now, 638 00:32:47,090 --> 00:32:50,370 their opacity just as is? 639 00:32:50,370 --> 00:32:54,555 How do you change a spite's opacity? 640 00:32:54,555 --> 00:33:01,897 AUDIENCE: The variable and the graphics [INAUDIBLE] 641 00:33:01,897 --> 00:33:04,438 SPEAKER 1: Is it a variable-- can you say that one more time? 642 00:33:04,438 --> 00:33:06,229 AUDIENCE: I forget the exact function name, 643 00:33:06,229 --> 00:33:13,365 but it's like love.graphics to put an image on the screen. 644 00:33:13,365 --> 00:33:15,390 SPEAKER 1: The love.graphics.draw. 645 00:33:15,390 --> 00:33:18,900 AUDIENCE: Wasn't there an argument in that? 646 00:33:18,900 --> 00:33:22,830 SPEAKER 1: So it's actually not an argument to that function. 647 00:33:22,830 --> 00:33:24,120 So I'll show you now. 648 00:33:24,120 --> 00:33:27,930 So in order to draw something at some different opacity, 649 00:33:27,930 --> 00:33:33,250 it's actually love.graphics.setcolor, and we do that here. 650 00:33:33,250 --> 00:33:38,760 So recall that Love2D is a state machine, and how it draws things. 651 00:33:38,760 --> 00:33:41,040 You can basically set a color onto anything 652 00:33:41,040 --> 00:33:47,520 that you draw, whether it's a font, an image, or a shape. 653 00:33:47,520 --> 00:33:53,432 And if you just pass in 255, 255, 255, that's white. 654 00:33:53,432 --> 00:33:55,140 And then if you give it an opacity, which 655 00:33:55,140 --> 00:33:58,590 is the fourth parameter, which is the alpha component of that, 656 00:33:58,590 --> 00:34:00,890 then that's how transparent it will be. 657 00:34:00,890 --> 00:34:03,570 And so we could have done this with other colors too. 658 00:34:03,570 --> 00:34:06,153 We could have done this with like if we wanted to tint it red, 659 00:34:06,153 --> 00:34:07,890 and also have it be sort of transparent. 660 00:34:07,890 --> 00:34:12,010 We could do that if we just did 25500 bird.opacity. 661 00:34:12,010 --> 00:34:14,580 But if you just want to manipulate opacity independent of-- 662 00:34:14,580 --> 00:34:18,389 or its transparency or its alpha independent of its color, 663 00:34:18,389 --> 00:34:21,469 and keep it the same exact color, you just do it white. 664 00:34:21,469 --> 00:34:25,139 If you did it black, nothing would show up. 665 00:34:25,139 --> 00:34:26,219 Is that true, actually? 666 00:34:26,219 --> 00:34:27,010 Let me verify that. 667 00:34:27,010 --> 00:34:29,940 668 00:34:29,940 --> 00:34:34,350 Pretty sure that's right, but I could be wrong. 669 00:34:34,350 --> 00:34:38,860 670 00:34:38,860 --> 00:34:40,340 I'm right, thankfully. 671 00:34:40,340 --> 00:34:41,830 OK. 672 00:34:41,830 --> 00:34:44,931 That or they're just black, and there's a black background too. 673 00:34:44,931 --> 00:34:46,389 Do you have a question, [? Tony? ?] 674 00:34:46,389 --> 00:34:46,930 AUDIENCE: No. 675 00:34:46,930 --> 00:34:49,300 SPEAKER 1: Oh, OK. 676 00:34:49,300 --> 00:34:58,780 So we'll take it on faith that that is correct. 677 00:34:58,780 --> 00:35:06,391 And back to the gist of this example. 678 00:35:06,391 --> 00:35:07,390 We have TIMER_MAX again. 679 00:35:07,390 --> 00:35:10,250 Actually, we really haven't changed much. 680 00:35:10,250 --> 00:35:14,560 What we have changed is we still have our birds. 681 00:35:14,560 --> 00:35:18,450 We need to keep track of their x, of their y, of their rate. 682 00:35:18,450 --> 00:35:19,887 Well, not necessarily their rate. 683 00:35:19,887 --> 00:35:21,970 Oh, well, their rate, yeah, because we're actually 684 00:35:21,970 --> 00:35:24,011 going to loop over each of these, and then create 685 00:35:24,011 --> 00:35:26,020 a timer between operations for them. 686 00:35:26,020 --> 00:35:28,160 And their opacity. 687 00:35:28,160 --> 00:35:29,980 Oh right, they start with an opacity of 0, 688 00:35:29,980 --> 00:35:35,500 and faded to 55, regardless of their-- 689 00:35:35,500 --> 00:35:38,820 690 00:35:38,820 --> 00:35:43,150 their opacity changes at the same rate as their x does. 691 00:35:43,150 --> 00:35:44,950 So the farther away, the longer they take, 692 00:35:44,950 --> 00:35:49,510 the slower they fade to fully opaque, and we see this here. 693 00:35:49,510 --> 00:35:51,855 So for k bird and pairs of birds. 694 00:35:51,855 --> 00:35:55,490 So for every bird, we're just going to set a tween, and then this is tween. 695 00:35:55,490 --> 00:36:00,550 So timer.tween is I think I have a slide on it here, right? 696 00:36:00,550 --> 00:36:05,710 A super cool useful function, super easy to use too, it 697 00:36:05,710 --> 00:36:10,940 takes iteration just like timer.every, timer.after, and it takes a definition. 698 00:36:10,940 --> 00:36:13,450 So in this case, it doesn't take an anonymous function 699 00:36:13,450 --> 00:36:15,450 like the other ones did because we're not really 700 00:36:15,450 --> 00:36:19,354 saying I want to do some sort of undefined behavior 701 00:36:19,354 --> 00:36:20,770 over the course of this operation. 702 00:36:20,770 --> 00:36:23,140 What I want to do is just change some values. 703 00:36:23,140 --> 00:36:25,070 I want to interpolate them. 704 00:36:25,070 --> 00:36:31,090 So what we're going to do is just pass in a-- this is the syntax for it. 705 00:36:31,090 --> 00:36:35,820 We pass in square brackets, the actual thing that we want to change. 706 00:36:35,820 --> 00:36:37,900 In this case, I want to change bird. 707 00:36:37,900 --> 00:36:41,620 I want bird to change in some way, and then 708 00:36:41,620 --> 00:36:44,590 what I want it's values to change toward are these. 709 00:36:44,590 --> 00:36:50,230 I want it's x to change to end x, and I want it's opacity to go to 255. 710 00:36:50,230 --> 00:36:54,019 And I wanted to do it over bird.rate, and so this bird.rate, 711 00:36:54,019 --> 00:36:55,060 every bird is storing it. 712 00:36:55,060 --> 00:36:57,850 So for birds that got a rate of 2, then it's 713 00:36:57,850 --> 00:37:01,630 x is going to go to end x over the course of 2 seconds, 714 00:37:01,630 --> 00:37:06,730 and it's opacity is going to go to 255 over the course of 2 seconds. 715 00:37:06,730 --> 00:37:10,620 And you can put as many things as you want, and as many-- 716 00:37:10,620 --> 00:37:15,334 you can put as many variables here, and as many entities. 717 00:37:15,334 --> 00:37:17,500 Entities being anything that you want to change that 718 00:37:17,500 --> 00:37:21,220 has a field, any table-based or class-based structure. 719 00:37:21,220 --> 00:37:25,810 You can pass any of those in here, and just tween them all at the same-- 720 00:37:25,810 --> 00:37:29,830 if they all have the same rate, and then just get that operation that way. 721 00:37:29,830 --> 00:37:33,040 And so that has the effect here of all we need to do is just add-- 722 00:37:33,040 --> 00:37:36,370 it's like two lines of code, but now we've easily changed it so 723 00:37:36,370 --> 00:37:40,067 that we can just tween two things at once, 724 00:37:40,067 --> 00:37:42,400 and that's the power of timer.tween, and we'll see that. 725 00:37:42,400 --> 00:37:47,140 So back to, actually, Match 3, if we want to look at that again. 726 00:37:47,140 --> 00:37:49,660 727 00:37:49,660 --> 00:37:54,190 This is a tween, that's a tween, that's a tween, and that's a tween. 728 00:37:54,190 --> 00:37:59,980 So the white, the foreground there, is just a rectangle 729 00:37:59,980 --> 00:38:01,320 that fills the whole screen. 730 00:38:01,320 --> 00:38:03,550 It's just a white rectangle. 731 00:38:03,550 --> 00:38:08,770 I have it set to timer.tween opacity from 0 to 255. 732 00:38:08,770 --> 00:38:13,570 Before that gets called, if we go from the start to the begin game state, 733 00:38:13,570 --> 00:38:18,550 and then if we go from at the beginning of the game state, 734 00:38:18,550 --> 00:38:23,160 before the level text comes down, it's going from 255 to 0. 735 00:38:23,160 --> 00:38:26,810 So it's just the reverse of that is the tween, and then all it's doing 736 00:38:26,810 --> 00:38:28,560 is just drawing a rectangle to the screen. 737 00:38:28,560 --> 00:38:32,502 But that's how you get a very simple transition. 738 00:38:32,502 --> 00:38:33,710 Same thing for fade to black. 739 00:38:33,710 --> 00:38:35,080 If you want to fade the whole screen to black, 740 00:38:35,080 --> 00:38:37,310 just draw a rectangle the size of the screen, 741 00:38:37,310 --> 00:38:42,995 and then just tween its opacity from 0 to 255, and then vise versa. 742 00:38:42,995 --> 00:38:44,620 That's how you get a simple transition. 743 00:38:44,620 --> 00:38:45,828 It can be any color you want. 744 00:38:45,828 --> 00:38:48,280 It can be a red transition. 745 00:38:48,280 --> 00:38:54,970 And then the level text, that's just a tween on the y, right? 746 00:38:54,970 --> 00:38:59,740 And then I just have some rectangle, love.graphics.rectangle with text, 747 00:38:59,740 --> 00:39:04,600 and it just says timer.tween to like VIRTUAL_HEIGHT divided by 2 minus 8, 748 00:39:04,600 --> 00:39:08,260 and then timer.after1. 749 00:39:08,260 --> 00:39:10,650 So we can actually pull this up if we want. 750 00:39:10,650 --> 00:39:14,070 We can see how this works. 751 00:39:14,070 --> 00:39:17,980 Today's going to be a little wider on the main distro code 752 00:39:17,980 --> 00:39:20,950 just because a lot of this is more conceptual. 753 00:39:20,950 --> 00:39:27,430 But in the begin game state-- well, actually, in the start state 754 00:39:27,430 --> 00:39:29,120 is when we go. 755 00:39:29,120 --> 00:39:33,130 So these colors, and letter table, and stuff that's all for the Match 3 text, 756 00:39:33,130 --> 00:39:34,060 if you're curious. 757 00:39:34,060 --> 00:39:37,960 So these are all back to what I said earlier about the beginning screen 758 00:39:37,960 --> 00:39:41,310 having Match 3 with the different colors going on a timer. 759 00:39:41,310 --> 00:39:43,250 These are just tables of colors. 760 00:39:43,250 --> 00:39:47,140 So notice this is RGBA, and then I'm just performing 761 00:39:47,140 --> 00:39:49,550 a shuffle on them every 0.075 seconds. 762 00:39:49,550 --> 00:39:52,630 So 2 will get 1, and vise versa. 763 00:39:52,630 --> 00:39:58,390 It'll all go down, and then 6 will come up here to 1 every 0.75 seconds. 764 00:39:58,390 --> 00:40:01,140 And then M gets mapped to this one, A gets mapped to this one, 765 00:40:01,140 --> 00:40:05,080 T to this one, C, H, 3, and that's it. 766 00:40:05,080 --> 00:40:09,190 That's done here at line 44 of the start state. 767 00:40:09,190 --> 00:40:16,120 But what I was going to show you was the tween for the transitions. 768 00:40:16,120 --> 00:40:21,730 So here in start state, in the update function says, 769 00:40:21,730 --> 00:40:24,690 it says if we press Enter, and our current menu item 770 00:40:24,690 --> 00:40:29,960 is 1, meaning that we're on start game, not quit game, timer.tween here. 771 00:40:29,960 --> 00:40:33,760 And notice that we have a finish function, which will show-- 772 00:40:33,760 --> 00:40:37,210 I'm actually going to show you in the next couple of examples, the chain 773 00:40:37,210 --> 00:40:38,350 examples. 774 00:40:38,350 --> 00:40:40,360 But finish is just a function that you can 775 00:40:40,360 --> 00:40:43,930 run after any timer that just says, hey, when this is finished, 776 00:40:43,930 --> 00:40:47,330 run this block of code, and notice that takes anonymous function here, 777 00:40:47,330 --> 00:40:48,070 just like that. 778 00:40:48,070 --> 00:40:52,337 So we can say OK, tween, over the course of one second, 779 00:40:52,337 --> 00:40:55,420 notice we're passing self into here because we want to manipulate ourself. 780 00:40:55,420 --> 00:40:57,211 We have a value that we want to manipulate. 781 00:40:57,211 --> 00:40:59,350 So self.transitionAlpha. 782 00:40:59,350 --> 00:41:02,290 So we're saying I want to take my transition alpha, 783 00:41:02,290 --> 00:41:07,240 and I want it to go to 255, and we set it to 0 by default. So at the very top, 784 00:41:07,240 --> 00:41:13,100 here, at line 60, transition alpha is just our white rectangle that 785 00:41:13,100 --> 00:41:14,160 fills the screen. 786 00:41:14,160 --> 00:41:17,256 I'm just saying set it to 0 so we don't see it at all. 787 00:41:17,256 --> 00:41:18,380 It's going to be invisible. 788 00:41:18,380 --> 00:41:20,150 It's still there no matter what. 789 00:41:20,150 --> 00:41:23,450 It's hidden, but after we press Enter, tween 790 00:41:23,450 --> 00:41:27,770 it to 255 over the course of 1 second, and then when that's finished, 791 00:41:27,770 --> 00:41:29,580 notice this is familiar, right? 792 00:41:29,580 --> 00:41:31,640 gStateMachine change begin game. 793 00:41:31,640 --> 00:41:33,990 We're going to go with the begin game state after that. 794 00:41:33,990 --> 00:41:35,150 Our passing level gets 1. 795 00:41:35,150 --> 00:41:38,810 We're starting the game, and then we're going to remove this color. 796 00:41:38,810 --> 00:41:41,780 Remove that timer from the-- this is actually 797 00:41:41,780 --> 00:41:47,330 unnecessary in this circumstance, but you can remove timers from timer. 798 00:41:47,330 --> 00:41:49,970 If you have something going constantly-- 799 00:41:49,970 --> 00:41:53,180 in this case, the color timer, and let's say we move from this state 800 00:41:53,180 --> 00:41:55,940 to the next state, the next state doesn't have all those colors, 801 00:41:55,940 --> 00:41:58,320 right, the Match 3 colors. 802 00:41:58,320 --> 00:42:01,100 So we don't need to keep-- because timer is a global object, 803 00:42:01,100 --> 00:42:05,120 it's going to keep updating over, and over again. 804 00:42:05,120 --> 00:42:07,940 We don't need certain timers to exist indefinitely. 805 00:42:07,940 --> 00:42:11,300 We can just remove this one because it's not relevant anymore. 806 00:42:11,300 --> 00:42:14,990 But this is all it takes just to give us a simple transition from one screen 807 00:42:14,990 --> 00:42:15,800 to another. 808 00:42:15,800 --> 00:42:23,320 Just give this transition alpha 255 down in the actual render function. 809 00:42:23,320 --> 00:42:24,510 Where is it? 810 00:42:24,510 --> 00:42:31,290 It is right here. 811 00:42:31,290 --> 00:42:34,779 So right here. 812 00:42:34,779 --> 00:42:35,820 Draw our transition rect. 813 00:42:35,820 --> 00:42:39,000 It's going to be drawn last so that it draws over everything when we finally 814 00:42:39,000 --> 00:42:42,540 do get a transition, but self.transitionAlpha, 815 00:42:42,540 --> 00:42:44,040 and that's all we really need. 816 00:42:44,040 --> 00:42:45,999 We need to keep the variable, and then whenever 817 00:42:45,999 --> 00:42:48,373 we want to perform like some sort of operation over time, 818 00:42:48,373 --> 00:42:49,480 just use timer.tween. 819 00:42:49,480 --> 00:42:51,510 It's that easy. 820 00:42:51,510 --> 00:42:52,920 But that was a little bit of a-- 821 00:42:52,920 --> 00:42:54,003 it was a relevant tangent. 822 00:42:54,003 --> 00:42:59,580 We would have talked about it anyway, but that's the first use case 823 00:42:59,580 --> 00:43:03,390 that I think of in this project, and then also the label. 824 00:43:03,390 --> 00:43:05,310 I'll show you the label in a little bit. 825 00:43:05,310 --> 00:43:08,760 But I think before we do that, let's talk about chaining. 826 00:43:08,760 --> 00:43:12,510 So you guys have probably played a lot of games 827 00:43:12,510 --> 00:43:15,302 where maybe there's a cut scene, and you're looking at a character, 828 00:43:15,302 --> 00:43:18,468 and they walk, and then maybe they turn, and they walk in another direction, 829 00:43:18,468 --> 00:43:20,440 and they walk up, and then they speak to you. 830 00:43:20,440 --> 00:43:23,940 There's a dialog box, and then maybe they do an animation or something, 831 00:43:23,940 --> 00:43:26,610 and then maybe some other things happen that are 832 00:43:26,610 --> 00:43:28,860 on some sort of predestined path. 833 00:43:28,860 --> 00:43:30,660 It's a very discrete path. 834 00:43:30,660 --> 00:43:32,259 It's not random. 835 00:43:32,259 --> 00:43:33,300 It's laid out in advance. 836 00:43:33,300 --> 00:43:37,320 It's a series of steps, one consecutive. 837 00:43:37,320 --> 00:43:42,120 That's the concept of chaining things together is relevant 838 00:43:42,120 --> 00:43:46,067 when we get to sort of timing things because when we finish timing 839 00:43:46,067 --> 00:43:48,150 something-- because usually, a lot of those things 840 00:43:48,150 --> 00:43:50,220 happen over the course of time. 841 00:43:50,220 --> 00:43:54,210 Over the course of five seconds, NPC1 will walk up north, 842 00:43:54,210 --> 00:43:58,934 and then they'll turn left, and then they'll say something. 843 00:43:58,934 --> 00:43:59,850 We want to model that. 844 00:43:59,850 --> 00:44:02,190 We don't want to basically have variables that say 845 00:44:02,190 --> 00:44:07,480 if NPC1 is at this tile, then do this. 846 00:44:07,480 --> 00:44:12,270 If NPC.dialogueOpen, then do this. 847 00:44:12,270 --> 00:44:15,970 We basically want to say walk here, do this, do this, 848 00:44:15,970 --> 00:44:24,780 do this in a flat, easy-- or at least semi-flat, easy sequence of steps. 849 00:44:24,780 --> 00:44:27,930 I have a few examples to illustrate how we can do that using timer 850 00:44:27,930 --> 00:44:30,810 for some semi-basic use cases. 851 00:44:30,810 --> 00:44:33,060 So chain0 is the first one. 852 00:44:33,060 --> 00:44:34,410 So this one is just Flappy Bird. 853 00:44:34,410 --> 00:44:38,700 He's going left to right, then he goes down, then he goes back left again, 854 00:44:38,700 --> 00:44:41,790 and then he goes up. 855 00:44:41,790 --> 00:44:46,570 What's the basic way that we model this-- 856 00:44:46,570 --> 00:44:49,680 that we implement this? 857 00:44:49,680 --> 00:44:50,430 Just off the cuff. 858 00:44:50,430 --> 00:44:55,210 859 00:44:55,210 --> 00:44:58,080 AUDIENCE: We can use that finish thing to do the-- 860 00:44:58,080 --> 00:45:00,330 SPEAKER 1: We would. 861 00:45:00,330 --> 00:45:05,610 If we didn't know about finish, how would we probably do it? 862 00:45:05,610 --> 00:45:08,570 I shouldn't have given away finish before I got to that example. 863 00:45:08,570 --> 00:45:09,820 I kind of got ahead of myself. 864 00:45:09,820 --> 00:45:12,640 865 00:45:12,640 --> 00:45:15,120 We can imagine somebody maybe saying OK, I 866 00:45:15,120 --> 00:45:19,110 want Flappy to move left to right, right to bottom, bottom to left, 867 00:45:19,110 --> 00:45:21,510 bottom to up. 868 00:45:21,510 --> 00:45:24,870 Maybe they're going to say if Flappy is less than-- 869 00:45:24,870 --> 00:45:31,680 or has reached first point, move left, else if he's reached bottom or point 2, 870 00:45:31,680 --> 00:45:34,500 move down, and then move left, move up. 871 00:45:34,500 --> 00:45:41,970 And in both of those cases, they're changing the x and y value of Flappy, 872 00:45:41,970 --> 00:45:45,870 and it's basically just a lot of ifs, and state variables. 873 00:45:45,870 --> 00:45:48,410 874 00:45:48,410 --> 00:45:50,460 I see it in a surprising amount of code. 875 00:45:50,460 --> 00:45:54,090 Just state being kept all over the place. 876 00:45:54,090 --> 00:45:58,750 The first implementation of that that we'll look at uses something similar. 877 00:45:58,750 --> 00:46:05,250 So in chain0, and there's only two examples here, actually, for chain. 878 00:46:05,250 --> 00:46:13,500 But chain0, there's a movement time, and then a timer. 879 00:46:13,500 --> 00:46:15,420 We're going to be semi-clean about it. 880 00:46:15,420 --> 00:46:16,830 We have some destinations. 881 00:46:16,830 --> 00:46:18,600 OK, so we have destination1. 882 00:46:18,600 --> 00:46:25,020 I know that I don't necessarily want to keep track of a bunch of if statements, 883 00:46:25,020 --> 00:46:26,940 but I'm going for-- 884 00:46:26,940 --> 00:46:30,930 assuming that I don't know what timer can do for us, 885 00:46:30,930 --> 00:46:34,380 here, I'm just saying OK, I want this first destination 886 00:46:34,380 --> 00:46:38,310 to be virtual width minus his width, and then 887 00:46:38,310 --> 00:46:43,140 keep him at y0 So right edge of the screen, assuming that he starts at 0,0. 888 00:46:43,140 --> 00:46:46,650 And then I want his second destination to be that same side on the x-axis, 889 00:46:46,650 --> 00:46:49,660 but I want the y to be virtual height minus his height. 890 00:46:49,660 --> 00:46:51,390 So go to the bottom of the screen. 891 00:46:51,390 --> 00:46:54,740 Then I want it to be 0 in his height from the bottom of the screen, 892 00:46:54,740 --> 00:46:56,550 and then back to 0,0. 893 00:46:56,550 --> 00:47:01,740 So we have those modeled, and then I want to keep a flag in each of those. 894 00:47:01,740 --> 00:47:04,060 I want to know whether he's reached that state yet. 895 00:47:04,060 --> 00:47:07,080 So I'm going to iterate over that table I just created, 896 00:47:07,080 --> 00:47:10,149 and just add a new key to each of these called reached, 897 00:47:10,149 --> 00:47:11,190 and just set it to false. 898 00:47:11,190 --> 00:47:14,670 Just by default, he hasn't reached all of them yet. 899 00:47:14,670 --> 00:47:17,520 And then in the update, basically, I'm going 900 00:47:17,520 --> 00:47:20,730 to set a timer to the min of movement time. 901 00:47:20,730 --> 00:47:26,760 So it will never go higher than movement time, and then timer plus delta time. 902 00:47:26,760 --> 00:47:32,260 And then for every destination in destinations, if it wasn't reached, 903 00:47:32,260 --> 00:47:36,280 then set its x and y, FlappyX and FlappyY, which are, in this case, 904 00:47:36,280 --> 00:47:40,170 we're uncleanly using global variables to keep track of this. 905 00:47:40,170 --> 00:47:43,140 FlappyX and FlappyY gets baseX. 906 00:47:43,140 --> 00:47:44,340 So notice another problem. 907 00:47:44,340 --> 00:47:49,890 We have to maintain where we are relative to our next spot in order 908 00:47:49,890 --> 00:47:57,420 for this math to work because before, we just took Flappy Birds-- 909 00:47:57,420 --> 00:47:59,670 basically, the timer divided by movement time 910 00:47:59,670 --> 00:48:02,610 was a ratio where we scaled the end destination, 911 00:48:02,610 --> 00:48:06,240 and assigned that to Flappy, which had the effect of moving 912 00:48:06,240 --> 00:48:07,470 Flappy left to right. 913 00:48:07,470 --> 00:48:10,540 But if we do that in the opposite, right to left, 914 00:48:10,540 --> 00:48:14,250 the math isn't the same because he's going backwards. 915 00:48:14,250 --> 00:48:19,650 He's getting negative values added to his x value. 916 00:48:19,650 --> 00:48:22,560 So we need to keep track of a base that he started at for each 917 00:48:22,560 --> 00:48:25,620 of these operations baseX, baseY. 918 00:48:25,620 --> 00:48:28,629 So at the very beginning, baseX, baseY is 0,0. 919 00:48:28,629 --> 00:48:30,420 So it's actually going to be much the same, 920 00:48:30,420 --> 00:48:32,836 but as soon as Flappy get to the right edge of the screen, 921 00:48:32,836 --> 00:48:36,300 we want baseX to be the right edge of the screen, baseY still 0, 922 00:48:36,300 --> 00:48:40,230 and then if he goes down, we want baseY to then be bottom edge of the screen, 923 00:48:40,230 --> 00:48:42,820 baseX to be right edge, and so forth. 924 00:48:42,820 --> 00:48:45,390 So what we do is we just scale. 925 00:48:45,390 --> 00:48:50,070 We're still using a timer over movement time as our scale factor, 926 00:48:50,070 --> 00:48:54,930 but we're adding the difference of our destination and our base, 927 00:48:54,930 --> 00:48:58,990 and we're multiplying by that scale factor instead. 928 00:48:58,990 --> 00:49:01,740 And so this difference, if we add it, whether we're 929 00:49:01,740 --> 00:49:05,190 moving left, or right, or down, or up, it's 930 00:49:05,190 --> 00:49:09,060 going to have the effect of filling in that gap of bridging that no matter 931 00:49:09,060 --> 00:49:11,840 where we are, no matter which direction we want to go. 932 00:49:11,840 --> 00:49:18,600 And so this is basically a fairly complete linear interpolation 933 00:49:18,600 --> 00:49:21,630 algorithm, which is the basis of tweening. 934 00:49:21,630 --> 00:49:26,010 Just interpolate some value between another value. 935 00:49:26,010 --> 00:49:29,085 It's usually modeled in geometry as the line between two segments. 936 00:49:29,085 --> 00:49:32,070 937 00:49:32,070 --> 00:49:35,510 And then if timer gets movement time, we've 938 00:49:35,510 --> 00:49:40,500 reached our destination, reset the timer, reset or baseX and Y, 939 00:49:40,500 --> 00:49:43,980 and that has the effect of just doing what we saw earlier, which was just 940 00:49:43,980 --> 00:49:47,290 putting him point by point. 941 00:49:47,290 --> 00:49:50,910 So any questions as to how this interpolation-- how 942 00:49:50,910 --> 00:49:53,100 this way of modeling the problem works? 943 00:49:53,100 --> 00:49:57,230 944 00:49:57,230 --> 00:50:06,360 All right, so there is a better way, a much better way thanks to timer.finish, 945 00:50:06,360 --> 00:50:11,250 which you can apply to any timer operation, including timer.tween. 946 00:50:11,250 --> 00:50:17,730 So we can basically say OK, once that operation is finished, do something. 947 00:50:17,730 --> 00:50:21,014 And this is all we have to do, we just have to say timer.tween. 948 00:50:21,014 --> 00:50:22,680 We no longer have to interpolate at all. 949 00:50:22,680 --> 00:50:24,780 That's taken care of for us by timer. 950 00:50:24,780 --> 00:50:29,970 So we're doing timer.tween over movement time. 951 00:50:29,970 --> 00:50:34,680 Flappy, set it to-- this was before we add all this in a destinations table 952 00:50:34,680 --> 00:50:36,490 with reached flags as well. 953 00:50:36,490 --> 00:50:40,710 Now, we just have the x and y here. 954 00:50:40,710 --> 00:50:45,030 So on the first movement, we want his x to be right edge of the screen, 955 00:50:45,030 --> 00:50:46,890 just like before-- y get zero. 956 00:50:46,890 --> 00:50:52,710 Once that's finished, anonymous function with another timer.tween. 957 00:50:52,710 --> 00:50:54,520 So we're saying OK, once you're finished, 958 00:50:54,520 --> 00:50:59,100 then tween him from the top right edge to the bottom right edge. 959 00:50:59,100 --> 00:51:03,000 So y gets VIRTUAL_HEIGHT minus FlappySprite getHeight. 960 00:51:03,000 --> 00:51:06,470 And then once that's finished, another anonymous function, 961 00:51:06,470 --> 00:51:09,750 another timer.tween, another finish, another anonymous function, 962 00:51:09,750 --> 00:51:10,920 another timer.tween. 963 00:51:10,920 --> 00:51:14,010 And this is, in its own way, unscalable. 964 00:51:14,010 --> 00:51:15,480 It's nested. 965 00:51:15,480 --> 00:51:17,400 There's a term for it called call back hell 966 00:51:17,400 --> 00:51:22,440 because you just get infinite downwards sloping anonymous functions with all 967 00:51:22,440 --> 00:51:23,820 this behavior. 968 00:51:23,820 --> 00:51:27,740 There are ways to flatten it, and we potentially will talk about it. 969 00:51:27,740 --> 00:51:29,500 It's part of knife.chain. 970 00:51:29,500 --> 00:51:32,355 Knife.chain has a way to turn all of these-- 971 00:51:32,355 --> 00:51:34,230 basically, it would look something like this. 972 00:51:34,230 --> 00:51:38,940 It would be chain, and then it would be like moveFlappy x, y. 973 00:51:38,940 --> 00:51:43,230 MoveFlappy x2-- it wouldn't be x2, y2. 974 00:51:43,230 --> 00:51:49,340 We'd actually write these out here, but it would have the exact same effect. 975 00:51:49,340 --> 00:51:55,800 This is if you're looking to maybe implement a cut scene system, or just 976 00:51:55,800 --> 00:51:57,960 some sort of scripting system for your game 977 00:51:57,960 --> 00:52:03,840 that's very declarative, and imperative in style. 978 00:52:03,840 --> 00:52:10,710 This is the holy grail of changing behavior, and getting it to work, 979 00:52:10,710 --> 00:52:12,790 and just making it look nice, and readable. 980 00:52:12,790 --> 00:52:13,290 Yeah? 981 00:52:13,290 --> 00:52:16,713 AUDIENCE: Well, you could also pass in-- 982 00:52:16,713 --> 00:52:21,603 you could pass in a table to your function of x's and y's [INAUDIBLE] 983 00:52:21,603 --> 00:52:25,040 simpler for [INAUDIBLE] to chain a lot of things. 984 00:52:25,040 --> 00:52:27,190 SPEAKER 1: Yes, you could do that too. 985 00:52:27,190 --> 00:52:30,980 The response was you could pass in a table to-- 986 00:52:30,980 --> 00:52:33,350 you could iterate over a table, and within that table, 987 00:52:33,350 --> 00:52:36,110 generate a timer.tween. 988 00:52:36,110 --> 00:52:45,380 The only issue comes about with finish, and there is a way-- 989 00:52:45,380 --> 00:52:49,130 I guess you could get a reference back to the timer, 990 00:52:49,130 --> 00:52:55,770 and then add a finish block to it, but then you would lose out on-- 991 00:52:55,770 --> 00:53:03,200 that does work for the same function if all you're doing 992 00:53:03,200 --> 00:53:07,200 is moving something to a bunch of locations, it's absolutely true. 993 00:53:07,200 --> 00:53:19,130 But if we wanted Flappy say something, and hero disappear, and then 994 00:53:19,130 --> 00:53:23,102 hero flash, it gets a little bit trickier to do stuff like that. 995 00:53:23,102 --> 00:53:23,810 But yes, I agree. 996 00:53:23,810 --> 00:53:28,190 There are ways of modeling-- this particular example is a little bit 997 00:53:28,190 --> 00:53:31,160 repetitive, and could be modeled, I think, better 998 00:53:31,160 --> 00:53:34,550 with a function that takes advantage of the fact 999 00:53:34,550 --> 00:53:39,847 that timers can be returned, and then given new finish variables. 1000 00:53:39,847 --> 00:53:42,430 I'd have to experiment with it to see because I'm actually not 1001 00:53:42,430 --> 00:53:46,620 100% sure that you can add a finish. 1002 00:53:46,620 --> 00:53:47,870 No, I think you can, actually. 1003 00:53:47,870 --> 00:53:50,591 I think you can add a finish function to a reference 1004 00:53:50,591 --> 00:53:52,340 because it's just a function on an object. 1005 00:53:52,340 --> 00:53:58,670 So yeah, but independent of that, I think the goal probably 1006 00:53:58,670 --> 00:54:04,640 is one, knowing how we can now chain behavior, and then two, 1007 00:54:04,640 --> 00:54:06,680 striving towards flattening it. 1008 00:54:06,680 --> 00:54:10,880 But in the purpose of this problem set, we'll see this a couple of times, 1009 00:54:10,880 --> 00:54:14,780 and it's just worlds better than before. 1010 00:54:14,780 --> 00:54:16,310 What's this, 76 lines? 1011 00:54:16,310 --> 00:54:22,490 And then tween1 or chain0 was 96. 1012 00:54:22,490 --> 00:54:25,490 OK, so 20 lines of code. 1013 00:54:25,490 --> 00:54:29,032 And also the fact that now we have a declarative interface for modeling 1014 00:54:29,032 --> 00:54:31,490 asynchronous behavior, that's really the fundamental thing, 1015 00:54:31,490 --> 00:54:37,460 is not having some value that models your duration, or your counter, 1016 00:54:37,460 --> 00:54:40,984 or whatever value, but just saying, hey, over this length of time, 1017 00:54:40,984 --> 00:54:41,900 I want you to do this. 1018 00:54:41,900 --> 00:54:42,660 I want you to do this. 1019 00:54:42,660 --> 00:54:43,350 I want to do this. 1020 00:54:43,350 --> 00:54:43,880 I want you to do this. 1021 00:54:43,880 --> 00:54:45,921 After this length of time, I want you to do this. 1022 00:54:45,921 --> 00:54:49,910 1023 00:54:49,910 --> 00:54:53,309 I always like to try and strive towards making code as declarative as possible 1024 00:54:53,309 --> 00:54:55,100 just so that you can read it in the future, 1025 00:54:55,100 --> 00:54:58,130 and then the people working on your code base 1026 00:54:58,130 --> 00:55:01,040 can also read it well in the future, and I 1027 00:55:01,040 --> 00:55:03,114 think timer does a pretty awesome job of that. 1028 00:55:03,114 --> 00:55:05,030 And this is just a reference for timer finish. 1029 00:55:05,030 --> 00:55:08,510 So it just takes a callback, and then once a timer function 1030 00:55:08,510 --> 00:55:13,760 tween every or after has completed, it triggers that callback. 1031 00:55:13,760 --> 00:55:17,340 So we're going to take a break for five minutes now, and then once we get back, 1032 00:55:17,340 --> 00:55:21,740 we'll talk about swapping, and some of the algorithms we use in Match 3, 1033 00:55:21,740 --> 00:55:25,490 starting with just rendering a board, getting tiles to swap, tweening them, 1034 00:55:25,490 --> 00:55:29,150 and then we'll actually look at how we take falling tiles, 1035 00:55:29,150 --> 00:55:31,210 and account for them, and then repopulate them. 1036 00:55:31,210 --> 00:55:36,080 1037 00:55:36,080 --> 00:55:37,430 All right, we're back. 1038 00:55:37,430 --> 00:55:41,930 So recall, before break we were looking at timer, 1039 00:55:41,930 --> 00:55:47,090 and how to take code that was previously managed by timers, and asynchronous, 1040 00:55:47,090 --> 00:55:50,720 but also very stateful, and sort of messy, and all over the place, 1041 00:55:50,720 --> 00:55:53,160 and putting it into a more declarative, clean, 1042 00:55:53,160 --> 00:55:59,290 easy to express format via timer.tween, timer.every, timer.after, timer.finish, 1043 00:55:59,290 --> 00:56:02,360 timer;finish for any timer objects. 1044 00:56:02,360 --> 00:56:04,370 So with all that out of the way, now we'll 1045 00:56:04,370 --> 00:56:07,010 start talking about the actual Match 3 mechanics. 1046 00:56:07,010 --> 00:56:11,000 And the very first thing that we'll look at is swap0, 1047 00:56:11,000 --> 00:56:15,110 and this is the sprite sheet for Match 3 that's included in the distro. 1048 00:56:15,110 --> 00:56:20,930 So as we can see, it's something that we can easily chop up with generate quads, 1049 00:56:20,930 --> 00:56:21,710 as we saw before. 1050 00:56:21,710 --> 00:56:24,080 Just a function provided in util.lua. 1051 00:56:24,080 --> 00:56:25,647 These are all 32 by 32 pixels. 1052 00:56:25,647 --> 00:56:27,980 So it would be very easy just to go through all of them, 1053 00:56:27,980 --> 00:56:32,450 and basically just generate quads with the sprite sheet 32, 32, 1054 00:56:32,450 --> 00:56:36,310 and just get a table with all of these individual things. 1055 00:56:36,310 --> 00:56:41,960 But notice that they're blocked up into patterns of colors, 1056 00:56:41,960 --> 00:56:44,870 and this has actual meaning, and value for our game 1057 00:56:44,870 --> 00:56:47,990 because when something is the same color, 1058 00:56:47,990 --> 00:56:51,800 and only when something is the same color, a tile is the same color, 1059 00:56:51,800 --> 00:56:54,110 are we allowed to trigger a match with it. 1060 00:56:54,110 --> 00:56:56,120 If we get any three or four-- 1061 00:56:56,120 --> 00:56:59,450 anything higher than three together in a line, vertically 1062 00:56:59,450 --> 00:57:04,070 or horizontally, that's a match, and we need to remove it from the table. 1063 00:57:04,070 --> 00:57:07,580 So we need some sort of way of identifying these tiles as being 1064 00:57:07,580 --> 00:57:11,990 of some color, and then they also happen to have a different pattern on them. 1065 00:57:11,990 --> 00:57:15,470 This one's got nothing, but then an x, and then a circle, and a square. 1066 00:57:15,470 --> 00:57:18,316 So those patterns-- it's not implemented in the distro, 1067 00:57:18,316 --> 00:57:19,440 but part of the assignment. 1068 00:57:19,440 --> 00:57:22,070 It's actually going to make them relevant. 1069 00:57:22,070 --> 00:57:27,650 But the part that is implemented is the actual matching of the colors. 1070 00:57:27,650 --> 00:57:31,220 And so the first thing that we'll need to do, probably, when we actually 1071 00:57:31,220 --> 00:57:34,730 get into the core code of the distribution 1072 00:57:34,730 --> 00:57:40,010 is instead of just putting them into one table, categorizing them. 1073 00:57:40,010 --> 00:57:44,105 Splitting it up into maybe one, two, three, four, five, six, seven, eight, 1074 00:57:44,105 --> 00:57:45,590 nine times two-- 1075 00:57:45,590 --> 00:57:50,810 18 tables, so that we can just say gframes at color. 1076 00:57:50,810 --> 00:57:54,440 So color being one to 18, and then get the index into that. 1077 00:57:54,440 --> 00:57:56,310 So there's six within each one. 1078 00:57:56,310 --> 00:57:57,620 So it'll be one to six. 1079 00:57:57,620 --> 00:58:01,577 One to six will be the variety, with one being the base variety. 1080 00:58:01,577 --> 00:58:03,410 And part of the assignment will be make sure 1081 00:58:03,410 --> 00:58:08,600 that the base variety is the only one that we start with on level one, 1082 00:58:08,600 --> 00:58:11,450 but then gradually introduce these other varieties. 1083 00:58:11,450 --> 00:58:14,330 And you can put them in whatever hierarchy 1084 00:58:14,330 --> 00:58:17,450 you want to, but make them have some sort of value 1085 00:58:17,450 --> 00:58:20,812 later on top of a few other things the assignment will cover. 1086 00:58:20,812 --> 00:58:22,520 But that's the spreadsheet in a nutshell, 1087 00:58:22,520 --> 00:58:23,978 and we'll be splitting it that way. 1088 00:58:23,978 --> 00:58:29,180 So 18 tables of quads, instead of one quad of whatever 1089 00:58:29,180 --> 00:58:31,280 this amount is-- eight by 16. 1090 00:58:31,280 --> 00:58:33,970 Not sure how many that is off the top of my head. 1091 00:58:33,970 --> 00:58:38,790 But let's take a look at swap0 in the distribution 1092 00:58:38,790 --> 00:58:41,840 so we can get a sense of what we need to do 1093 00:58:41,840 --> 00:58:46,800 to begin implementing our Match 3 game. 1094 00:58:46,800 --> 00:58:49,460 Notice we have require util for GenerateQuads. 1095 00:58:49,460 --> 00:58:51,650 We're just going to generate for this basic example. 1096 00:58:51,650 --> 00:58:54,816 We're not going to differentiate between colors, and varieties, or anything. 1097 00:58:54,816 --> 00:58:58,127 We're just going to put them all into one quad, or one table of quads. 1098 00:58:58,127 --> 00:59:00,710 So we're just going to use the regular GenerateQuads function. 1099 00:59:00,710 --> 00:59:03,070 We're not going to differentiate them. 1100 00:59:03,070 --> 00:59:05,400 We're just going to use our sprite here, our match3.png 1101 00:59:05,400 --> 00:59:08,150 provided in the distro, which is the exact same image that we just 1102 00:59:08,150 --> 00:59:09,470 saw on the screen. 1103 00:59:09,470 --> 00:59:11,290 I'm going to just generate them. 1104 00:59:11,290 --> 00:59:12,384 They're 32 by 32-- 1105 00:59:12,384 --> 00:59:13,550 generate the quads for them. 1106 00:59:13,550 --> 00:59:15,320 They're 32 by 32 pixels. 1107 00:59:15,320 --> 00:59:19,310 I'm assigning it to a table here called TileQuads. 1108 00:59:19,310 --> 00:59:21,830 And then here, we're calling generateBoard, 1109 00:59:21,830 --> 00:59:25,700 and so generateBoard isn't all that dissimilar to what we saw before 1110 00:59:25,700 --> 00:59:30,830 with maybe the level maker in Breakout, where we just spawn a bunch of bricks, 1111 00:59:30,830 --> 00:59:33,440 or a bunch of tiles, in this case. 1112 00:59:33,440 --> 00:59:37,220 Except in this case, they're kept in a nice 2D array that's 1113 00:59:37,220 --> 00:59:39,860 always going to be eight by eight, and that's never 1114 00:59:39,860 --> 00:59:43,437 going to change just by one of the constraints of the game. 1115 00:59:43,437 --> 00:59:45,770 Match 3, traditionally, is an eight by eight grid that's 1116 00:59:45,770 --> 00:59:48,540 always full of tiles of some variety. 1117 00:59:48,540 --> 00:59:51,680 So local tiles, it's going to be an empty table, 1118 00:59:51,680 --> 00:59:53,980 and then we're going to do a nested for loop here-- 1119 00:59:53,980 --> 00:59:54,980 y to x. 1120 00:59:54,980 --> 00:59:58,520 The standard is usually y first, and then x, 1121 00:59:58,520 --> 01:00:05,480 and then we index y before x just because the individual rows in a 2D 1122 01:00:05,480 --> 01:00:13,370 array, or sprite, or table will be such that, for example, if our table was 1123 01:00:13,370 --> 01:00:15,020 equal to this-- oops, sorry. 1124 01:00:15,020 --> 01:00:18,560 Syntax bug. 1125 01:00:18,560 --> 01:00:25,040 If we did this, and then we have a table here, and a table here, and a table 1126 01:00:25,040 --> 01:00:35,070 here, and we had like 0, 1, 1, 1, 1, 1, 1, 1, and then 1, 1, 1, 1. 1127 01:00:35,070 --> 01:00:37,210 If we index into this table-- 1128 01:00:37,210 --> 01:00:43,410 so table at 0, that's going to give us another table. 1129 01:00:43,410 --> 01:00:45,060 That's not going to give us-- 1130 01:00:45,060 --> 01:00:56,040 let's say we wanted to get the value at table 2, 3. 1131 01:00:56,040 --> 01:01:00,990 The instinct might be to think I'm going to index at x, y 1132 01:01:00,990 --> 01:01:04,350 just because x, y tends to be more commonly seen. 1133 01:01:04,350 --> 01:01:08,100 But if we did that, and assumed that x was horizontal, 1134 01:01:08,100 --> 01:01:13,080 and y is vertical in this arrangement, which is how we have it, 1135 01:01:13,080 --> 01:01:20,350 then table2 wouldn't be this value here table2 would be this table here. 1136 01:01:20,350 --> 01:01:26,700 The first value you passed into indexing some table when it's a nested table 1137 01:01:26,700 --> 01:01:29,100 is just, in fact, the table itself, which 1138 01:01:29,100 --> 01:01:33,300 is why we actually need to do-- when we want to get some value, 1139 01:01:33,300 --> 01:01:35,850 we have to index at table y, x. 1140 01:01:35,850 --> 01:01:40,395 So it's flipped for that reason because x is actually going to be-- 1141 01:01:40,395 --> 01:01:46,680 the first index is going to be these sub tables, 1142 01:01:46,680 --> 01:01:51,309 or sub arrays if you're in C, or Java, or something like that. 1143 01:01:51,309 --> 01:01:54,225 So when you see table y, x, and you're wondering why it's not table x, 1144 01:01:54,225 --> 01:01:56,790 y, that's the reason. 1145 01:01:56,790 --> 01:02:01,700 So any questions as to why that is, or how that works? 1146 01:02:01,700 --> 01:02:05,810 AUDIENCE: [INAUDIBLE] 1147 01:02:05,810 --> 01:02:10,400 SPEAKER 1: In this case, I was using zero based indexing, 1148 01:02:10,400 --> 01:02:11,802 but Lua is one index. 1149 01:02:11,802 --> 01:02:12,635 That was just habit. 1150 01:02:12,635 --> 01:02:15,434 1151 01:02:15,434 --> 01:02:18,350 It was pointed out that I was using zero based indexing in my example. 1152 01:02:18,350 --> 01:02:22,940 You want to use one based indexing when you're actually programming, 1153 01:02:22,940 --> 01:02:25,550 and not zero based. 1154 01:02:25,550 --> 01:02:27,350 But the same principle applies. 1155 01:02:27,350 --> 01:02:31,310 Zero would be one in that case. 1156 01:02:31,310 --> 01:02:34,490 In a general purpose language-- 1157 01:02:34,490 --> 01:02:42,500 most languages, if we were to abstract the problem out in a C 2D array, 1158 01:02:42,500 --> 01:02:45,250 or C++, or Java, zero would be appropriate there. 1159 01:02:45,250 --> 01:02:49,370 But anyways, we have a nested for loop. 1160 01:02:49,370 --> 01:02:51,870 We're starting at y, and then we're going to x, 1161 01:02:51,870 --> 01:02:55,270 and then basically, that has the effect of y, 1162 01:02:55,270 --> 01:02:59,150 and then x, x, x, x, x, y, x, x, x, x, x. 1163 01:02:59,150 --> 01:03:00,380 Just insert a blank table. 1164 01:03:00,380 --> 01:03:05,300 Fill it with-- we're just using tables here. 1165 01:03:05,300 --> 01:03:07,850 So we're not using any sort of tile class, 1166 01:03:07,850 --> 01:03:10,190 or board class, or anything fancy. 1167 01:03:10,190 --> 01:03:11,990 We're just using raw data types here. 1168 01:03:11,990 --> 01:03:16,760 So we're just saying insert into tiles y, which 1169 01:03:16,760 --> 01:03:22,670 by the way, if we're at x equals 1, 8, here, 1170 01:03:22,670 --> 01:03:27,170 and we're in any given iteration of our outer y loop, 1171 01:03:27,170 --> 01:03:30,640 tiles y will be the last table that we just inserted-- 1172 01:03:30,640 --> 01:03:35,630 the last blank table on the first iteration of this x loop. 1173 01:03:35,630 --> 01:03:39,710 So basically, it's saying, in the inner table that I just 1174 01:03:39,710 --> 01:03:47,810 put into the table that's going to represent our board, the tiles table, 1175 01:03:47,810 --> 01:03:51,650 insert a new table. 1176 01:03:51,650 --> 01:03:55,820 So we have a table of tables of tables. 1177 01:03:55,820 --> 01:03:59,150 In the third table are the actual tiles themselves. 1178 01:03:59,150 --> 01:04:02,480 You can think of this table as being a tile data type, more or less. 1179 01:04:02,480 --> 01:04:04,430 Just implemented using a table. 1180 01:04:04,430 --> 01:04:07,610 That has an x-coordinate, a y-coordinate, and then a tile, 1181 01:04:07,610 --> 01:04:11,000 and the tile is going to be a random number that's 1182 01:04:11,000 --> 01:04:13,280 going to be the index into our quads. 1183 01:04:13,280 --> 01:04:17,030 So each tile holds x and y, and then notice 1184 01:04:17,030 --> 01:04:18,950 that we're multiplying by 32 because we're 1185 01:04:18,950 --> 01:04:23,780 going to use this to draw the tile, and the tiles are 32 pixels tall by high-- 1186 01:04:23,780 --> 01:04:26,340 sorry, wide by tall. 1187 01:04:26,340 --> 01:04:29,300 We are going to multiply x minus 1, recall, 1188 01:04:29,300 --> 01:04:35,510 because even though tables are one indexed, coordinates are zero indexed. 1189 01:04:35,510 --> 01:04:39,320 So x gets that times 32, y gets that times 32, 1190 01:04:39,320 --> 01:04:44,600 and then get a random number between 1, and the number of quads 1191 01:04:44,600 --> 01:04:46,040 in our tile quads table. 1192 01:04:46,040 --> 01:04:51,264 So recall this number sign here is just a shorthand for length of the table, 1193 01:04:51,264 --> 01:04:52,680 and then we're going to return it. 1194 01:04:52,680 --> 01:04:54,290 So we generated our board. 1195 01:04:54,290 --> 01:05:01,660 It's a y by x grid of table rows of little tables 1196 01:05:01,660 --> 01:05:05,450 that all have an x, y, and a tile ID, and the tile ID maps to the quads 1197 01:05:05,450 --> 01:05:09,350 that we just generated. 1198 01:05:09,350 --> 01:05:11,630 OK, that's it for the init function. 1199 01:05:11,630 --> 01:05:14,450 Sorry, love.load in this example. 1200 01:05:14,450 --> 01:05:20,620 The love.draw uses a function called drawBoard, and we pass in 128 by 16. 1201 01:05:20,620 --> 01:05:23,330 The 128 by 16 is just xy offsets. 1202 01:05:23,330 --> 01:05:25,640 We're just going to draw our board at 128, 16, 1203 01:05:25,640 --> 01:05:28,460 and is it going to center our board. 1204 01:05:28,460 --> 01:05:31,190 And then if we go down to drawBoard at line 89, 1205 01:05:31,190 --> 01:05:34,130 gets an offsetX, offsetY, nested for loop again. 1206 01:05:34,130 --> 01:05:37,520 We're just iterating back over the tiles that we got, 1207 01:05:37,520 --> 01:05:40,820 and recall, actually, generateBoard returns tiles, 1208 01:05:40,820 --> 01:05:45,350 and then we set board equal to the result of generateBoard. 1209 01:05:45,350 --> 01:05:50,210 So down here in line 89, again, in drawBoard-- actually at line 95. 1210 01:05:50,210 --> 01:05:56,255 Within this nested for loop, we're going to get a tile at board y, x, 1211 01:05:56,255 --> 01:05:58,130 just so we have a shorthand reference for it. 1212 01:05:58,130 --> 01:06:01,760 We don't have to say board y, x several times, which you would have to hear. 1213 01:06:01,760 --> 01:06:04,040 We're going to draw the sprite-- 1214 01:06:04,040 --> 01:06:07,319 the quad at tile, tile, tile.tile, which, recall, 1215 01:06:07,319 --> 01:06:09,110 is a random number between one and whatever 1216 01:06:09,110 --> 01:06:13,170 the number of quads we have in our tile quads table. 1217 01:06:13,170 --> 01:06:16,940 And then that x plus offsetX, and the y plus the offsetY, which 1218 01:06:16,940 --> 01:06:22,040 has the effect of drawing every single tile in our grid at some given offset. 1219 01:06:22,040 --> 01:06:23,180 And that has the result-- 1220 01:06:23,180 --> 01:06:26,600 and I probably should have run this, actually, in advance 1221 01:06:26,600 --> 01:06:28,950 just so I could illustrate it. 1222 01:06:28,950 --> 01:06:31,800 1223 01:06:31,800 --> 01:06:34,340 But we have a simple board. 1224 01:06:34,340 --> 01:06:35,080 Looks nice. 1225 01:06:35,080 --> 01:06:37,580 It's colorful, but it's very, very basic. 1226 01:06:37,580 --> 01:06:39,697 Just a 2D render of our game. 1227 01:06:39,697 --> 01:06:41,030 There's no behavior or anything. 1228 01:06:41,030 --> 01:06:43,070 This is just how we draw the board. 1229 01:06:43,070 --> 01:06:46,510 So any questions as to how just the drawing, and the creation of the board 1230 01:06:46,510 --> 01:06:47,010 work? 1231 01:06:47,010 --> 01:06:50,340 1232 01:06:50,340 --> 01:06:51,890 OK. 1233 01:06:51,890 --> 01:06:56,010 So swap1 is a little bit more complicated. 1234 01:06:56,010 --> 01:06:58,820 It builds on what we did before, what we just 1235 01:06:58,820 --> 01:07:02,569 built, which was getting the board implemented, and drawn onto the screen. 1236 01:07:02,569 --> 01:07:03,860 But there's no behavior at all. 1237 01:07:03,860 --> 01:07:05,870 It's just a static-- basically, the same thing 1238 01:07:05,870 --> 01:07:07,640 as drawing an image onto the screen. 1239 01:07:07,640 --> 01:07:13,070 And so for that, what we want to do is implement swapping. 1240 01:07:13,070 --> 01:07:17,810 So how do we think we can accomplish this? 1241 01:07:17,810 --> 01:07:20,660 Anybody have any ideas as to how we can swap? 1242 01:07:20,660 --> 01:07:23,618 1243 01:07:23,618 --> 01:07:27,570 AUDIENCE: [INAUDIBLE] using tweening to have it go in opposite directions. 1244 01:07:27,570 --> 01:07:30,060 SPEAKER 1: Well, we could. 1245 01:07:30,060 --> 01:07:32,970 That will have the effect of-- 1246 01:07:32,970 --> 01:07:34,890 the response was we could use tweeting. 1247 01:07:34,890 --> 01:07:38,790 We could, and we actually will for swap2, 1248 01:07:38,790 --> 01:07:41,400 but it's going to be a little bit more complicated than that 1249 01:07:41,400 --> 01:07:44,447 because they're in a 2D array. 1250 01:07:44,447 --> 01:07:45,780 So if we just tween their x, y-- 1251 01:07:45,780 --> 01:07:50,140 AUDIENCE: [INAUDIBLE] 1252 01:07:50,140 --> 01:07:53,670 SPEAKER 1: They will be in the same place in the array. 1253 01:07:53,670 --> 01:07:54,462 But yes, ultimate-- 1254 01:07:54,462 --> 01:07:56,670 AUDIENCE: You could switch the position in the array, 1255 01:07:56,670 --> 01:07:57,870 and then reload the array. 1256 01:07:57,870 --> 01:08:00,330 SPEAKER 1: Switch their position in the array, and then reload the array. 1257 01:08:00,330 --> 01:08:01,496 We will switch the position. 1258 01:08:01,496 --> 01:08:04,679 We don't have to reload the array, but we will switch their positions. 1259 01:08:04,679 --> 01:08:05,970 That's effectively, what it is. 1260 01:08:05,970 --> 01:08:09,990 Literally just take two tiles, and swap in CS50, 1261 01:08:09,990 --> 01:08:13,560 where we just take two variables, and get a temp variable that 1262 01:08:13,560 --> 01:08:16,080 points that one variable, gets its values 1263 01:08:16,080 --> 01:08:22,689 while the second variable gets the values of that one, or vise versa, 1264 01:08:22,689 --> 01:08:23,189 I think. 1265 01:08:23,189 --> 01:08:27,479 This one gets this one's values, this one gets this one's values, 1266 01:08:27,479 --> 01:08:29,700 and then this one comes down to this one, basically. 1267 01:08:29,700 --> 01:08:32,910 There's the middleman that keep-- because if this one gets this one's 1268 01:08:32,910 --> 01:08:35,966 values, it's going to get overridden by this one's value. 1269 01:08:35,966 --> 01:08:38,340 So there would be no reference to it's x, y, or anything. 1270 01:08:38,340 --> 01:08:42,180 So that's why you need to store this one up here, so this one can come here, 1271 01:08:42,180 --> 01:08:43,750 and this and come back down here. 1272 01:08:43,750 --> 01:08:45,630 So we've done a swap, effectively. 1273 01:08:45,630 --> 01:08:47,910 And there's ways in Lua to do swaps, as we saw before, 1274 01:08:47,910 --> 01:08:49,659 without even needing a temporary variable. 1275 01:08:49,659 --> 01:08:54,130 You can just do xy get some other xy, which sort of bypasses that. 1276 01:08:54,130 --> 01:08:57,510 But when you start to do four things getting swapped at once, 1277 01:08:57,510 --> 01:09:01,830 and you have four commas, it can get a little tricky, a little bit unwieldy. 1278 01:09:01,830 --> 01:09:04,779 I'm actually not 100% sure you can unpack more than two things in Lua. 1279 01:09:04,779 --> 01:09:09,060 I'll have to double check on that, but right off the gate, 1280 01:09:09,060 --> 01:09:11,850 we're seeing that double assignment here on line 32, 1281 01:09:11,850 --> 01:09:15,069 highlighted x, highlighted y gets 1, 1. 1282 01:09:15,069 --> 01:09:17,069 And let me actually run just so we can see. 1283 01:09:17,069 --> 01:09:20,460 There's actually a couple of pieces here besides just that. 1284 01:09:20,460 --> 01:09:24,569 1285 01:09:24,569 --> 01:09:25,930 Swap1. 1286 01:09:25,930 --> 01:09:29,279 So we have the board as before, we also have 1287 01:09:29,279 --> 01:09:32,069 something to show us where to swipe because we have 1288 01:09:32,069 --> 01:09:34,380 to know where we're swapping the tiles. 1289 01:09:34,380 --> 01:09:39,057 In an ideal implementation, which is an optional part of the assignment, 1290 01:09:39,057 --> 01:09:40,890 you would have mouse behavior for your game. 1291 01:09:40,890 --> 01:09:43,899 So you could just click on two tiles, or click, and drag, and swap them. 1292 01:09:43,899 --> 01:09:45,357 In this case, we're not doing that. 1293 01:09:45,357 --> 01:09:47,430 We're just implementing key based behavior. 1294 01:09:47,430 --> 01:09:50,760 So when I press left, right, up, or down, I can move. 1295 01:09:50,760 --> 01:09:55,950 If I press Enter on a tile, and then move around, it's an indicator to me 1296 01:09:55,950 --> 01:09:58,290 that I've selected that tile to swap with something else 1297 01:09:58,290 --> 01:10:01,300 because it needs to keep track of OK, you want to swap this tile. 1298 01:10:01,300 --> 01:10:02,675 What do you want to swap it with? 1299 01:10:02,675 --> 01:10:04,850 I want to swap it with this tile. 1300 01:10:04,850 --> 01:10:06,210 So they get swapped. 1301 01:10:06,210 --> 01:10:08,910 I want to swap it with this tile. 1302 01:10:08,910 --> 01:10:10,230 So they get swapped. 1303 01:10:10,230 --> 01:10:11,387 Or this tile. 1304 01:10:11,387 --> 01:10:13,470 So you can swap it with whatever tile you want to. 1305 01:10:13,470 --> 01:10:16,020 There's no constraints. 1306 01:10:16,020 --> 01:10:21,150 The actual distro code implements a constraint, and so offhand, 1307 01:10:21,150 --> 01:10:24,342 what do you think a constraint would be for making sure that we can't-- 1308 01:10:24,342 --> 01:10:25,800 AUDIENCE: They have to be adjacent. 1309 01:10:25,800 --> 01:10:27,550 SPEAKER 1: Yeah, they have to be adjacent. 1310 01:10:27,550 --> 01:10:31,020 So what would that entail? 1311 01:10:31,020 --> 01:10:34,450 AUDIENCE: That their x [INAUDIBLE] 1312 01:10:34,450 --> 01:10:35,950 SPEAKER 1: Exactly. 1313 01:10:35,950 --> 01:10:41,880 And the shorthand for that, really, is if the absolute value of their x's 1314 01:10:41,880 --> 01:10:48,910 minus their y's is equal to 1. 1315 01:10:48,910 --> 01:10:52,320 Because if you subtract one's x from another one's x, 1316 01:10:52,320 --> 01:10:54,510 and then one's y from another one's y, and then 1317 01:10:54,510 --> 01:10:56,400 you add the differences together, that'll 1318 01:10:56,400 --> 01:10:58,860 tell you whether they're directly adjacent to each other. 1319 01:10:58,860 --> 01:10:59,950 It has to equal one. 1320 01:10:59,950 --> 01:11:02,750 If equals zero, then their x's and y's are the same. 1321 01:11:02,750 --> 01:11:07,350 If equals two, then it's two tiles away on the x-axis, 1322 01:11:07,350 --> 01:11:13,660 or it's away on the x and the y, in which case it would be diagonal to it. 1323 01:11:13,660 --> 01:11:16,780 So the only way is it's x's minus it's x's. 1324 01:11:16,780 --> 01:11:21,210 Tile1.x minus tile2.x, and tile1.y minus tile2.y, 1325 01:11:21,210 --> 01:11:24,840 if they're absolute value of their difference is one, 1326 01:11:24,840 --> 01:11:26,100 then they're adjacent. 1327 01:11:26,100 --> 01:11:27,846 That's in the implementation. 1328 01:11:27,846 --> 01:11:33,120 1329 01:11:33,120 --> 01:11:36,305 So this is why we have these variables here, highlighted tile. 1330 01:11:36,305 --> 01:11:39,180 Basically we're setting a flag saying, do we have a highlighted tile? 1331 01:11:39,180 --> 01:11:45,090 If we do, we're going to perform some drawing logic later down in the draw 1332 01:11:45,090 --> 01:11:46,620 function. 1333 01:11:46,620 --> 01:11:52,554 Basically, how would we draw a highlighted tile, do you think? 1334 01:11:52,554 --> 01:11:55,239 AUDIENCE: Add a rectangle with transparency. 1335 01:11:55,239 --> 01:11:56,030 SPEAKER 1: Exactly. 1336 01:11:56,030 --> 01:11:58,260 So the answer was add a rectangle with transparency. 1337 01:11:58,260 --> 01:11:59,910 That's exactly what we do. 1338 01:11:59,910 --> 01:12:07,050 I'm going to go down to this part here. 1339 01:12:07,050 --> 01:12:10,900 So on line 173, if we have a highlighted tile, 1340 01:12:10,900 --> 01:12:12,930 and basically, this is in the middle of a loop-- 1341 01:12:12,930 --> 01:12:14,610 our y, x before. 1342 01:12:14,610 --> 01:12:16,160 We've put it into a draw board. 1343 01:12:16,160 --> 01:12:19,980 We have the drawBoard function, but x, y, or y, x, 1344 01:12:19,980 --> 01:12:22,540 the tile is going to be whatever tile we're currently on, 1345 01:12:22,540 --> 01:12:27,200 and if we do have a highlighted tile, and that tile's gridX-- 1346 01:12:27,200 --> 01:12:31,019 notice we now have a new variable called gridX, as opposed to it's regular x 1347 01:12:31,019 --> 01:12:34,310 so that we can check for these sorts of things to see where it is in the array. 1348 01:12:34,310 --> 01:12:39,500 If it's gridX is equal to whatever we've set highlightedX to, 1349 01:12:39,500 --> 01:12:45,400 and gridY is equal to highlightedY, then love.graphics.setColor 1350 01:12:45,400 --> 01:12:50,000 half transparency, and then just draw a rectangle with this 4 1351 01:12:50,000 --> 01:12:53,920 at the end of it, which actually draws a rounded rectangle. 1352 01:12:53,920 --> 01:12:56,550 If you pass in no 4, it will just draw straight rectangle, 1353 01:12:56,550 --> 01:12:58,970 but if you pass in an int at the very end, that's how many 1354 01:12:58,970 --> 01:13:01,597 rounded segments basically that rectangle will have. 1355 01:13:01,597 --> 01:13:03,680 So you can get rounded corners on your rectangles, 1356 01:13:03,680 --> 01:13:07,040 and it's good for UI drawing, and stuff like that. 1357 01:13:07,040 --> 01:13:10,910 We use it a little bit in the distro. 1358 01:13:10,910 --> 01:13:13,010 So that's how you get a highlighted tile. 1359 01:13:13,010 --> 01:13:15,740 There was also a selected tile, and a selected tile 1360 01:13:15,740 --> 01:13:19,847 is just draw a rectangle, same thing, but it's a line this time, 1361 01:13:19,847 --> 01:13:22,430 and there's always going to be a selected tile no matter what. 1362 01:13:22,430 --> 01:13:25,430 So we're always going to draw it here at the end of our render function. 1363 01:13:25,430 --> 01:13:26,410 It's just 255-- 1364 01:13:26,410 --> 01:13:30,080 234 for the opacity so that it's just kind of transparent, but not super 1365 01:13:30,080 --> 01:13:31,670 transparent. 1366 01:13:31,670 --> 01:13:37,800 Set line width to 4 so that it's not just a very thin rectangle. 1367 01:13:37,800 --> 01:13:44,990 If you set the line width, and then you draw a rectangle with the line format-- 1368 01:13:44,990 --> 01:13:48,530 the line mode of drawing, it will use whatever the current line 1369 01:13:48,530 --> 01:13:50,370 width is when drawing the rectangle. 1370 01:13:50,370 --> 01:13:54,740 So we set it to 4, then draw a line rect at selectedTile.x 1371 01:13:54,740 --> 01:13:59,039 plus offsetX selectedTile.y offsetY, and we draw it 32 by 32 1372 01:13:59,039 --> 01:14:00,830 because that's the size of a tile, and then 1373 01:14:00,830 --> 01:14:05,360 we set our color-- remember to always set your color back to 255, 255, 255, 1374 01:14:05,360 --> 01:14:09,770 255 because if you don't, and I did this when I was debugging, actually, 1375 01:14:09,770 --> 01:14:16,200 you get some fun stuff. 1376 01:14:16,200 --> 01:14:18,172 Wait, was that the right one? 1377 01:14:18,172 --> 01:14:23,650 1378 01:14:23,650 --> 01:14:27,240 Oh, I might have fixed it up above where we-- 1379 01:14:27,240 --> 01:14:28,600 there was an issue. 1380 01:14:28,600 --> 01:14:34,260 If you don't set, basically, your color, and you set it to red, 1381 01:14:34,260 --> 01:14:36,840 everything will draw red after you've done something. 1382 01:14:36,840 --> 01:14:42,640 So if it ever happens, remember to set your color back to 255, 255, 255, 255, 1383 01:14:42,640 --> 01:14:46,503 anytime you change the color in some way, like I'm doing here. 1384 01:14:46,503 --> 01:14:48,336 AUDIENCE: Alternatively, you could also just 1385 01:14:48,336 --> 01:14:50,820 make sure to always set the color before you draw something. is that right? 1386 01:14:50,820 --> 01:14:51,962 SPEAKER 1: Yes. 1387 01:14:51,962 --> 01:14:53,670 The response was make sure you always set 1388 01:14:53,670 --> 01:14:55,170 the color before you draw something. 1389 01:14:55,170 --> 01:14:57,540 I think that's what I ended up doing in this distro, which 1390 01:14:57,540 --> 01:14:58,873 is why it's not working anymore. 1391 01:14:58,873 --> 01:14:59,880 I think it was-- 1392 01:14:59,880 --> 01:15:01,870 where was it? 1393 01:15:01,870 --> 01:15:05,130 It was here, but I must have fixed it because I accidentally 1394 01:15:05,130 --> 01:15:08,130 left that out when I was debugging, and it ended up drawing-- everything 1395 01:15:08,130 --> 01:15:08,629 was red. 1396 01:15:08,629 --> 01:15:12,660 So just as an aside just because Love2D is a state machine. 1397 01:15:12,660 --> 01:15:16,440 Drawing it beforehand is definitely the safer way to go too. 1398 01:15:16,440 --> 01:15:19,522 1399 01:15:19,522 --> 01:15:22,230 So the core of this, because we're running a little low on time-- 1400 01:15:22,230 --> 01:15:28,300 the core of this overall block of code is just the swap here. 1401 01:15:28,300 --> 01:15:30,480 So if there is no highlighted tile-- so basically, 1402 01:15:30,480 --> 01:15:32,250 if we pressed Enter or Return-- 1403 01:15:32,250 --> 01:15:36,510 now, we have all input handling in love.keypressed key. 1404 01:15:36,510 --> 01:15:38,910 And by the way, this is input handling to change 1405 01:15:38,910 --> 01:15:40,500 the x and y of our selected tile. 1406 01:15:40,500 --> 01:15:43,680 1407 01:15:43,680 --> 01:15:46,170 If we press Enter, and we don't have a highlighted tile, 1408 01:15:46,170 --> 01:15:49,470 then we need to have a highlighted tile, otherwise we should swap them. 1409 01:15:49,470 --> 01:15:53,724 So we get a reference to tile one and two, we swap, we create temp variables. 1410 01:15:53,724 --> 01:15:55,890 Recall, we need to have that middle man up here that 1411 01:15:55,890 --> 01:15:57,910 keeps track of this tile's information. 1412 01:15:57,910 --> 01:16:00,285 So it's going to keep track of all of tile2's information 1413 01:16:00,285 --> 01:16:03,480 with tempX, tempY, tempgridX, and tempgridY because we 1414 01:16:03,480 --> 01:16:05,880 need to not only change their x-coordinates, 1415 01:16:05,880 --> 01:16:08,190 but also their grid positions. 1416 01:16:08,190 --> 01:16:16,110 And then we need to create a temp tile here. 1417 01:16:16,110 --> 01:16:19,470 Basically, here's where we actually swap their places in the board. 1418 01:16:19,470 --> 01:16:24,600 So tile1.gridY, tile1.gridX gets tile2, and then we're getting a reference 1419 01:16:24,600 --> 01:16:27,090 to temp tile so that we can-- 1420 01:16:27,090 --> 01:16:35,940 because if we set board at wherever tile1 is to tile2, 1421 01:16:35,940 --> 01:16:37,890 we won't have anything where tile2 is. 1422 01:16:37,890 --> 01:16:40,250 We need to have a temp tile to keep track of-- 1423 01:16:40,250 --> 01:16:46,170 sorry, we won't have anything at tile1 if we overwrite it with tile2. 1424 01:16:46,170 --> 01:16:49,410 So we need a reference to tile1 here, so that we can put it 1425 01:16:49,410 --> 01:16:52,780 into where tile2's spot is, right here. 1426 01:16:52,780 --> 01:16:58,486 And then we need to do all that before we end up swapping their coordinates 1427 01:16:58,486 --> 01:17:01,110 and tile grid positions, otherwise you get weird buggy behavior 1428 01:17:01,110 --> 01:17:03,880 when you're moving the selected tile around. 1429 01:17:03,880 --> 01:17:06,960 And then we can on the highlight, and then reset our selection 1430 01:17:06,960 --> 01:17:10,330 because their selection is also going to get changed after we do the swap. 1431 01:17:10,330 --> 01:17:15,090 So we need to put it to the second tile because it gets swapped with whatever 1432 01:17:15,090 --> 01:17:18,110 tile we highlighted. 1433 01:17:18,110 --> 01:17:19,940 And that's the overall gist. 1434 01:17:19,940 --> 01:17:22,830 It's basically taking two tiles, flipping the information, 1435 01:17:22,830 --> 01:17:23,970 storing a middleman. 1436 01:17:23,970 --> 01:17:26,260 Same thing in swap in CS50, a little more complicated, 1437 01:17:26,260 --> 01:17:30,210 though because these all have subfields that all need to get manipulated. 1438 01:17:30,210 --> 01:17:32,530 And a lot of this can actually be done mathematically. 1439 01:17:32,530 --> 01:17:37,407 You can actually have its x and y mathematically derived 1440 01:17:37,407 --> 01:17:38,490 from it's gridX and gridY. 1441 01:17:38,490 --> 01:17:40,620 Just multiply by 32. 1442 01:17:40,620 --> 01:17:43,920 In this case, I just kept them as variables, and separate. 1443 01:17:43,920 --> 01:17:47,430 But yeah, you could just do that too, and that 1444 01:17:47,430 --> 01:17:51,930 has the effect of swapping the variables whenever we move them, 1445 01:17:51,930 --> 01:17:56,490 and then that's the fundamental first step in Match 3, 1446 01:17:56,490 --> 01:17:58,900 is just swapping any two tiles in a given position. 1447 01:17:58,900 --> 01:18:01,770 So does that make sense altogether? 1448 01:18:01,770 --> 01:18:03,630 OK. 1449 01:18:03,630 --> 01:18:11,070 So this example is actually not that much different at all from swap2. 1450 01:18:11,070 --> 01:18:13,200 I'm going to show you swap 2 right now. 1451 01:18:13,200 --> 01:18:19,530 So if we go to swap2, the only change we really have made 1452 01:18:19,530 --> 01:18:26,090 is that now tiles flipped instead of instantly changing, they tween. 1453 01:18:26,090 --> 01:18:27,840 And this is a piece of cake at this point. 1454 01:18:27,840 --> 01:18:31,030 We already know-- what's the function we need to do? 1455 01:18:31,030 --> 01:18:32,742 Just timer.tween. 1456 01:18:32,742 --> 01:18:34,950 All we need to do is just take the two, and then just 1457 01:18:34,950 --> 01:18:40,030 tween tile1.x and tile1.y to tile2.x, and tile2.y, 1458 01:18:40,030 --> 01:18:41,700 and do the same thing in reverse. 1459 01:18:41,700 --> 01:18:46,210 Tween tile2.x, and tile2.y to tile1.x, and tile1.y. 1460 01:18:46,210 --> 01:18:52,740 And so if we open up swap2, go to main, nothing in this program 1461 01:18:52,740 --> 01:18:58,050 really changes, except in update, where we go to line 99, 1462 01:18:58,050 --> 01:18:59,294 and we're just doing it here. 1463 01:18:59,294 --> 01:19:00,210 Notice the definition. 1464 01:19:00,210 --> 01:19:03,479 Over 0.2 seconds, it takes in the definition table, here, 1465 01:19:03,479 --> 01:19:06,270 and it's taking in two entities because we're modifying two things. 1466 01:19:06,270 --> 01:19:08,640 We're modifying tile2, and tile1. 1467 01:19:08,640 --> 01:19:13,230 We're just setting x to tile1.x, and y to tile1.y, 1468 01:19:13,230 --> 01:19:15,967 and then tile1 is getting the tempX and tempY 1469 01:19:15,967 --> 01:19:18,550 because before, it was just getting it directly from the temp, 1470 01:19:18,550 --> 01:19:22,270 and now it's just tweening it over time. 1471 01:19:22,270 --> 01:19:26,830 But that was before just a bunch of tile2.x equals tile1.x, 1472 01:19:26,830 --> 01:19:33,310 tile2.y equals tile2.y, tile1.y equals tile2.y. 1473 01:19:33,310 --> 01:19:34,070 That's all it is. 1474 01:19:34,070 --> 01:19:35,528 That's what's really nice about it. 1475 01:19:35,528 --> 01:19:38,050 Now we don't have to really work hard at all 1476 01:19:38,050 --> 01:19:41,890 to get nice, smooth transitions in whatever we do, 1477 01:19:41,890 --> 01:19:43,870 whether it's a UI, or the game. 1478 01:19:43,870 --> 01:19:47,249 It's just super nice, and convenient. 1479 01:19:47,249 --> 01:19:49,540 So that's all we need to do to get basic swapping done. 1480 01:19:49,540 --> 01:19:51,840 That was swap2, the tween swap. 1481 01:19:51,840 --> 01:19:54,070 And so I put together a set of slides here just 1482 01:19:54,070 --> 01:19:58,180 to illustrate the algorithm that we use to calculate the matches. 1483 01:19:58,180 --> 01:20:02,080 So right now we've got swapping in, but we 1484 01:20:02,080 --> 01:20:03,880 don't know when we've gotten a match. 1485 01:20:03,880 --> 01:20:06,850 So just offhand, does anybody have any idea as to maybe 1486 01:20:06,850 --> 01:20:09,732 how we can go about calculating whether we've got any matches? 1487 01:20:09,732 --> 01:20:15,188 1488 01:20:15,188 --> 01:20:18,660 AUDIENCE: Well, we already figured out how to track if a thing is adjacent. 1489 01:20:18,660 --> 01:20:21,636 So you, I guess, have a table of adjacent-- 1490 01:20:21,636 --> 01:20:24,612 you go through [INAUDIBLE] block, and if you have an adjacent-- 1491 01:20:24,612 --> 01:20:29,076 or for every adjacent block, you check if that color equals your color. 1492 01:20:29,076 --> 01:20:31,824 And if it does, you check if-- 1493 01:20:31,824 --> 01:20:34,532 well, then I guess you need to figure out what direction it's in, 1494 01:20:34,532 --> 01:20:37,508 and then you check, continuing in that direction, 1495 01:20:37,508 --> 01:20:40,050 if there's another of the same color. 1496 01:20:40,050 --> 01:20:42,840 SPEAKER 1: So their response was when you're 1497 01:20:42,840 --> 01:20:46,920 looking at tiles, look at all adjacent tiles, 1498 01:20:46,920 --> 01:20:52,470 and if there is a color that's the same one, then figure out its direction, 1499 01:20:52,470 --> 01:20:55,130 and then move from there. 1500 01:20:55,130 --> 01:20:56,950 So like a recursive style. 1501 01:20:56,950 --> 01:20:59,934 I guess you could implement it recursively. 1502 01:20:59,934 --> 01:21:02,850 It probably would be a little bit trickier to understand, and probably 1503 01:21:02,850 --> 01:21:05,130 not as efficient. 1504 01:21:05,130 --> 01:21:07,950 The way that we are actually going to implement it 1505 01:21:07,950 --> 01:21:13,320 is going to be a little bit more iterative. 1506 01:21:13,320 --> 01:21:19,290 So all we really need to do is check every row, and every column one time, 1507 01:21:19,290 --> 01:21:21,450 and then go basically, left to right. 1508 01:21:21,450 --> 01:21:25,412 So in this case, we have to check every row and column one 1509 01:21:25,412 --> 01:21:27,870 time in this direction, and then one time in this direction 1510 01:21:27,870 --> 01:21:33,420 because we can get vertical and horizontal matches. 1511 01:21:33,420 --> 01:21:35,350 So we start off. 1512 01:21:35,350 --> 01:21:40,450 Let's just arbitrarily decide we want to start going left to right down the data 1513 01:21:40,450 --> 01:21:41,250 structure. 1514 01:21:41,250 --> 01:21:43,950 So we'll go, what color is this? 1515 01:21:43,950 --> 01:21:44,600 That's brown. 1516 01:21:44,600 --> 01:21:46,200 OK, check the next one. 1517 01:21:46,200 --> 01:21:47,820 Is it the same color? 1518 01:21:47,820 --> 01:21:52,680 If it is, then say OK, the number of matching tiles that we've found so far 1519 01:21:52,680 --> 01:21:54,090 is two. 1520 01:21:54,090 --> 01:21:57,060 If it's greater than three, then later on we'll 1521 01:21:57,060 --> 01:22:03,130 need to add that group as a match to our list of matches, basically. 1522 01:22:03,130 --> 01:22:07,340 But if it's not, OK, then the number matches is one again. 1523 01:22:07,340 --> 01:22:09,510 So set it to one, and then do the same thing. 1524 01:22:09,510 --> 01:22:10,211 Same color? 1525 01:22:10,211 --> 01:22:10,710 No. 1526 01:22:10,710 --> 01:22:12,780 OK, number of matches is one. 1527 01:22:12,780 --> 01:22:16,680 In this case, here we have the number of matches is going to be two 1528 01:22:16,680 --> 01:22:19,770 because this is blue, and then we're going to go ahead, 1529 01:22:19,770 --> 01:22:20,865 and then same color again. 1530 01:22:20,865 --> 01:22:25,450 The number matches is three, and then we've gotten to the end of the row. 1531 01:22:25,450 --> 01:22:28,680 So we can say OK, what was our last number of matches? 1532 01:22:28,680 --> 01:22:31,050 Was it greater than or equal to three? 1533 01:22:31,050 --> 01:22:34,080 If it was, add that group of tiles to our table of 1534 01:22:34,080 --> 01:22:37,650 matches if we've gotten a match, and then move on. 1535 01:22:37,650 --> 01:22:40,950 And we do that over, and over again, and if it's in the middle of a group, 1536 01:22:40,950 --> 01:22:43,200 like it is here-- so this isn't at the end of the row. 1537 01:22:43,200 --> 01:22:44,783 This is just in the middle of the row. 1538 01:22:44,783 --> 01:22:49,170 What we do is number of matches one, two, three, and then we go here, 1539 01:22:49,170 --> 01:22:50,434 and it's set to one. 1540 01:22:50,434 --> 01:22:52,350 Well, first of all, we check number of matches 1541 01:22:52,350 --> 01:22:53,724 when we get to a different color. 1542 01:22:53,724 --> 01:22:56,180 We say, OK, this isn't the same color as this tile. 1543 01:22:56,180 --> 01:23:00,960 This is purple, and this is gray, but number of matches is three. 1544 01:23:00,960 --> 01:23:06,880 So what we do is we just add these three tiles to our-- 1545 01:23:06,880 --> 01:23:09,960 we're keeping a table of matches because we're going to go through, 1546 01:23:09,960 --> 01:23:11,550 and we're going to delete all of them. 1547 01:23:11,550 --> 01:23:15,090 And then, eventually, we're going to do some tweening as well, 1548 01:23:15,090 --> 01:23:17,100 but we're going to delete all of these. 1549 01:23:17,100 --> 01:23:20,220 And then in order to do that, we need to walk backwards. 1550 01:23:20,220 --> 01:23:24,240 We need to say, basically, for x gets position 1551 01:23:24,240 --> 01:23:28,742 minus number of tiles in the match, just add that to a match, 1552 01:23:28,742 --> 01:23:30,450 add that to a match, add that to a match, 1553 01:23:30,450 --> 01:23:32,850 and then add the match to our table of matches. 1554 01:23:32,850 --> 01:23:34,685 And that's it for the x direction. 1555 01:23:34,685 --> 01:23:36,810 And for the y direction, it's the exact same thing. 1556 01:23:36,810 --> 01:23:39,643 Going down here-- different color, different color, different color, 1557 01:23:39,643 --> 01:23:42,490 different color, and then same color, same color, different color, 1558 01:23:42,490 --> 01:23:46,470 but number of matches is three because one, two, three, and then 1559 01:23:46,470 --> 01:23:50,290 it's going to walk backwards, up to the top, add that match, 1560 01:23:50,290 --> 01:23:51,750 and then just continue down here. 1561 01:23:51,750 --> 01:23:54,180 Same thing, same thing, and then same thing there. 1562 01:23:54,180 --> 01:23:56,350 This is at the end of the column. 1563 01:23:56,350 --> 01:23:57,690 So it's going to get to the end. 1564 01:23:57,690 --> 01:24:00,900 It's not actually going to look for the next tile 1565 01:24:00,900 --> 01:24:03,270 because there are no more tiles, but every time 1566 01:24:03,270 --> 01:24:07,122 we complete a row, or a column, we check at the very end, 1567 01:24:07,122 --> 01:24:09,580 do we have the number of matches equal to three or greater? 1568 01:24:09,580 --> 01:24:11,520 If we do, then we need to do the same logic 1569 01:24:11,520 --> 01:24:14,880 as we did before by adding that match to our list of matches. 1570 01:24:14,880 --> 01:24:19,440 So it's actually quite a simple algorithm, and this is the set of steps 1571 01:24:19,440 --> 01:24:21,630 that I just illustrated. 1572 01:24:21,630 --> 01:24:23,295 We have a match found there. 1573 01:24:23,295 --> 01:24:24,420 Oh, sorry. [? Tony, ?] yes? 1574 01:24:24,420 --> 01:24:30,030 AUDIENCE: If you complete two matches at once, would it see both? 1575 01:24:30,030 --> 01:24:31,680 SPEAKER 1: It would. 1576 01:24:31,680 --> 01:24:34,680 The question was if you complete two matches at once, would it see both? 1577 01:24:34,680 --> 01:24:35,280 Yes. 1578 01:24:35,280 --> 01:24:39,570 If you complete-- and it wouldn't if you deleted 1579 01:24:39,570 --> 01:24:43,790 them as you went because let's say you had like one, two, three here. 1580 01:24:43,790 --> 01:24:46,890 I'm assuming that's what you mean, one, two, three, one, two, three. 1581 01:24:46,890 --> 01:24:52,080 If you just deleted them as you went, then no, it wouldn't see them. 1582 01:24:52,080 --> 01:24:55,450 It would go here, it would get these three, delete them, 1583 01:24:55,450 --> 01:24:57,180 and then it would just see these two. 1584 01:24:57,180 --> 01:24:59,730 But because we walk over the entire thing, 1585 01:24:59,730 --> 01:25:03,030 and then we only delete matches after all of the matches have processed, 1586 01:25:03,030 --> 01:25:06,314 we're going to add this one first, and then when we do our vertical one, 1587 01:25:06,314 --> 01:25:09,480 we're also going to see this one, and so it's going to count as two matches. 1588 01:25:09,480 --> 01:25:12,330 And you could make your code a little bit more complicated if you wanted to, 1589 01:25:12,330 --> 01:25:14,820 and say if there's an intersection between two matches, 1590 01:25:14,820 --> 01:25:16,900 I want to give the player more points. 1591 01:25:16,900 --> 01:25:20,364 Or I want to give him some sort of effect like in Candy Crush, 1592 01:25:20,364 --> 01:25:22,280 I think you get like explosions, or Bejeweled, 1593 01:25:22,280 --> 01:25:25,450 you get explosions if you get like a T pattern. 1594 01:25:25,450 --> 01:25:29,530 And if you get four in a row, you get a laser or something across the screen. 1595 01:25:29,530 --> 01:25:32,380 And actually, part of assignment is clear a row. 1596 01:25:32,380 --> 01:25:37,990 If you get four in a row, you should clear that row, or call them. 1597 01:25:37,990 --> 01:25:40,360 If you do that, then yeah, you can have logic. 1598 01:25:40,360 --> 01:25:44,290 But currently, all the distro does is just this simple iteration-- 1599 01:25:44,290 --> 01:25:46,990 horizontally, then vertically, and adding matches as you go. 1600 01:25:46,990 --> 01:25:49,690 And actually, there is an optimization that you can make. 1601 01:25:49,690 --> 01:25:54,700 If you go here, for example, let's say we're going here, here, 1602 01:25:54,700 --> 01:25:59,860 and then we're here, and we're at a different color than the last one. 1603 01:25:59,860 --> 01:26:01,870 We can just go to the next one. 1604 01:26:01,870 --> 01:26:05,440 We can just skip because we know we only have two left. 1605 01:26:05,440 --> 01:26:10,090 There's no point in looking for a match if you're at the n minus 2 1606 01:26:10,090 --> 01:26:12,170 because there's no possible way to get a match. 1607 01:26:12,170 --> 01:26:13,060 So that's just a shortcut. 1608 01:26:13,060 --> 01:26:15,893 A little optimization you can make, and that's actually in the code. 1609 01:26:15,893 --> 01:26:17,690 Just break off if you're at-- 1610 01:26:17,690 --> 01:26:21,910 in the code, it's x or y equals 7. 1611 01:26:21,910 --> 01:26:23,830 Just break out of that for loop basically, 1612 01:26:23,830 --> 01:26:28,780 and go to the next row, or column. 1613 01:26:28,780 --> 01:26:32,500 1614 01:26:32,500 --> 01:26:34,810 Any more questions as to how that works? 1615 01:26:34,810 --> 01:26:38,170 1616 01:26:38,170 --> 01:26:41,770 If you're actually looking in the code, we won't go over it 1617 01:26:41,770 --> 01:26:44,152 in too much detail in class. 1618 01:26:44,152 --> 01:26:46,360 It's fairly straightforward, I think, once I walk you 1619 01:26:46,360 --> 01:26:52,060 through the algorithm a little bit, but I'll point you to the relevant lines. 1620 01:26:52,060 --> 01:26:53,150 It's in the play state. 1621 01:26:53,150 --> 01:26:53,650 No, sorry. 1622 01:26:53,650 --> 01:26:59,020 It's in the board in the calculate matches function. 1623 01:26:59,020 --> 01:27:04,840 Here, on line 50, calculate matches. 1624 01:27:04,840 --> 01:27:08,180 So horizontal matches, y gets 1 to 8. 1625 01:27:08,180 --> 01:27:10,337 You keep a color to match, and basically, you just 1626 01:27:10,337 --> 01:27:11,920 keep track of how many you've matched. 1627 01:27:11,920 --> 01:27:16,090 Match numbers one always when you're doing a brand new color, 1628 01:27:16,090 --> 01:27:18,310 and then starting at x 2 to 8, because we already 1629 01:27:18,310 --> 01:27:24,490 got the first tile, basically, if the color is the same, increment matchNum. 1630 01:27:24,490 --> 01:27:29,800 Otherwise, set our current color to that color, the next tile. 1631 01:27:29,800 --> 01:27:36,010 If we've done this, and our match is greater than or equal to 3, 1632 01:27:36,010 --> 01:27:37,019 then we found a match. 1633 01:27:37,019 --> 01:27:37,810 We can add a match. 1634 01:27:37,810 --> 01:27:39,090 We create a new table. 1635 01:27:39,090 --> 01:27:43,030 We go backwards from where we are with x 2 gets x minus 1, 1636 01:27:43,030 --> 01:27:44,380 and then x minus matchNum. 1637 01:27:44,380 --> 01:27:46,780 So it works for no matter how long the match is, 1638 01:27:46,780 --> 01:27:49,420 whether it's three, four, or five. 1639 01:27:49,420 --> 01:27:51,490 And then we're subtracting 1, and then you just 1640 01:27:51,490 --> 01:27:56,560 insert into that match, the tile at that x 2 position 1641 01:27:56,560 --> 01:27:58,570 because the matches are made of tiles. 1642 01:27:58,570 --> 01:28:01,400 So a match is just a group of tiles put together, 1643 01:28:01,400 --> 01:28:04,660 and so you can intersect to any given match just by comparing the tiles, 1644 01:28:04,660 --> 01:28:06,951 and just seeing if they have the same tiles, basically. 1645 01:28:06,951 --> 01:28:09,940 That's how you'd get a cross match. 1646 01:28:09,940 --> 01:28:14,440 And then after that's all done, just insert into matches that match. 1647 01:28:14,440 --> 01:28:15,940 Here's a little optimization. 1648 01:28:15,940 --> 01:28:19,120 If x is greater than or equal to 7, and this is in part of the loop 1649 01:28:19,120 --> 01:28:23,210 where we already know that we're on a new color from the last color, 1650 01:28:23,210 --> 01:28:27,880 we'll just break, and then set matchNum to 1 if we haven't gotten to that point 1651 01:28:27,880 --> 01:28:28,600 yet. 1652 01:28:28,600 --> 01:28:33,700 And then this is the part of the code that accounts for a last row-- 1653 01:28:33,700 --> 01:28:37,330 the row ending with a match because we're not going to be on the next loop 1654 01:28:37,330 --> 01:28:39,880 to see whether we're going to a different color. 1655 01:28:39,880 --> 01:28:45,414 We just need to check to make sure at the end of any row iteration, 1656 01:28:45,414 --> 01:28:47,830 or column iteration when we go to the next row, or column. 1657 01:28:47,830 --> 01:28:51,310 Before we go to the next row or column, that matchNum 1658 01:28:51,310 --> 01:28:53,860 is greater than or equal to 3, and if so, 1659 01:28:53,860 --> 01:28:57,430 then do the same logic here, but start x at 8. 1660 01:28:57,430 --> 01:28:58,950 And same thing for vertical matches. 1661 01:28:58,950 --> 01:29:02,260 Exact same logic, just x and y are inverted. 1662 01:29:02,260 --> 01:29:03,970 And then that's it. 1663 01:29:03,970 --> 01:29:08,080 And then self.matches, we keep a reference to self.matches in the board 1664 01:29:08,080 --> 01:29:12,670 so that later we can remove them here, and I 1665 01:29:12,670 --> 01:29:15,750 believe we use it for something else. 1666 01:29:15,750 --> 01:29:21,070 And then we return, basically, if the number of matches is greater than 0, 1667 01:29:21,070 --> 01:29:24,937 we're going to return matches, else we're just going to return false. 1668 01:29:24,937 --> 01:29:26,020 And we can use this later. 1669 01:29:26,020 --> 01:29:29,470 We can say if matches from our play state, 1670 01:29:29,470 --> 01:29:32,320 then we can call a few other functions, and bring 1671 01:29:32,320 --> 01:29:34,330 in new tiles, and stuff like that. 1672 01:29:34,330 --> 01:29:39,950 But just for the sake of being thorough as an illustration, 1673 01:29:39,950 --> 01:29:41,650 this is how the algorithm works. 1674 01:29:41,650 --> 01:29:44,750 In this case, actually, this was before I made the optimization. 1675 01:29:44,750 --> 01:29:47,575 We wouldn't actually do this in this particular case. 1676 01:29:47,575 --> 01:29:52,330 This would have shorted down to the next column before it even checked this, 1677 01:29:52,330 --> 01:29:55,560 but if your algorithm didn't make that optimization, then yeah, 1678 01:29:55,560 --> 01:29:56,950 I would just see two tiles there. 1679 01:29:56,950 --> 01:30:00,070 Go to the next one, nothing there, no matches. 1680 01:30:00,070 --> 01:30:02,200 Same thing here. 1681 01:30:02,200 --> 01:30:04,600 There is a match there, and the match would 1682 01:30:04,600 --> 01:30:09,470 be found not at the end of the diagram here, 1683 01:30:09,470 --> 01:30:11,950 it would be calculated when it's pointed here, 1684 01:30:11,950 --> 01:30:17,400 but it knows matchNum is greater than or equal to 3 at that point. 1685 01:30:17,400 --> 01:30:19,780 And it does the exact same thing here. 1686 01:30:19,780 --> 01:30:22,540 We just go column wise, and then nothing there, 1687 01:30:22,540 --> 01:30:25,790 nothing there, and then we've got one right there. 1688 01:30:25,790 --> 01:30:27,530 And so the next part-- 1689 01:30:27,530 --> 01:30:29,845 oh, any questions on how that works at all? 1690 01:30:29,845 --> 01:30:34,310 1691 01:30:34,310 --> 01:30:36,652 The next part-- we have the matches now. 1692 01:30:36,652 --> 01:30:37,610 We have them in tables. 1693 01:30:37,610 --> 01:30:38,360 We have the tiles. 1694 01:30:38,360 --> 01:30:39,890 We have references to the tiles. 1695 01:30:39,890 --> 01:30:42,470 How do we remove the tiles once we have-- 1696 01:30:42,470 --> 01:30:45,686 how do we get rid of them as soon as we have the matches? 1697 01:30:45,686 --> 01:30:52,200 1698 01:30:52,200 --> 01:30:59,640 Assuming that our board is a table, a 2D table, and each array within there just 1699 01:30:59,640 --> 01:31:04,691 has a tile object, how would we clear the board of our tiles? 1700 01:31:04,691 --> 01:31:08,130 AUDIENCE: Are you including what you're shifting [INAUDIBLE]?? 1701 01:31:08,130 --> 01:31:11,640 SPEAKER 1: No, just remove it from-- just like like. 1702 01:31:11,640 --> 01:31:12,770 Just remove it from play. 1703 01:31:12,770 --> 01:31:15,590 AUDIENCE: Oh. 1704 01:31:15,590 --> 01:31:21,326 I guess you can [INAUDIBLE] 1705 01:31:21,326 --> 01:31:22,450 SPEAKER 1: Yeah, you could. 1706 01:31:22,450 --> 01:31:24,699 Yeah, with a little bit of finagling, you could get it 1707 01:31:24,699 --> 01:31:27,790 to where you could set a tile to be invisible, 1708 01:31:27,790 --> 01:31:31,790 and then you could just give it a new tile ID, I guess, 1709 01:31:31,790 --> 01:31:36,550 and then shift it up above, and then make it come. 1710 01:31:36,550 --> 01:31:40,600 Well, I don't know if that approach necessarily 1711 01:31:40,600 --> 01:31:42,730 works super well for this because of gravity 1712 01:31:42,730 --> 01:31:44,290 because the tiles have to come down. 1713 01:31:44,290 --> 01:31:48,970 So then you'd have to bring the lower ones, if they were at the bottom here. 1714 01:31:48,970 --> 01:31:50,560 Those would have to come down. 1715 01:31:50,560 --> 01:31:52,672 1716 01:31:52,672 --> 01:31:54,630 That kind of approach would be a little tricky. 1717 01:31:54,630 --> 01:31:58,090 You could make it work, I think. 1718 01:31:58,090 --> 01:32:01,450 The simple approach, which we used in this distro, 1719 01:32:01,450 --> 01:32:05,050 is actually just setting them to nil because if you set something to nil, 1720 01:32:05,050 --> 01:32:07,206 it's just not going to render, in this case. 1721 01:32:07,206 --> 01:32:10,330 So we're just setting all of these tiles that were previously there to nil. 1722 01:32:10,330 --> 01:32:12,310 They're nothing at this point. 1723 01:32:12,310 --> 01:32:16,300 They effectively would render like this if you tried to render them, 1724 01:32:16,300 --> 01:32:20,930 assuming that your code accounted for it, or it didn't break. 1725 01:32:20,930 --> 01:32:27,670 And then the next stage would be the actual getting the board fixed 1726 01:32:27,670 --> 01:32:30,310 because we have the tiles removed. 1727 01:32:30,310 --> 01:32:34,250 So now, we have this thing here, but there 1728 01:32:34,250 --> 01:32:37,810 is a step that has to happen before we get new tiles, and that's gravity. 1729 01:32:37,810 --> 01:32:40,000 We have to actually shift everything down. 1730 01:32:40,000 --> 01:32:44,072 So how do we go about shifting tiles down? 1731 01:32:44,072 --> 01:32:46,780 So this first column, we don't really have to do anything, right? 1732 01:32:46,780 --> 01:32:49,049 This column is all set, but what about this column? 1733 01:32:49,049 --> 01:32:49,840 How would we shift? 1734 01:32:49,840 --> 01:32:52,968 How would we get that tile to go down? 1735 01:32:52,968 --> 01:32:54,292 AUDIENCE: [INAUDIBLE] 1736 01:32:54,292 --> 01:32:55,000 SPEAKER 1: Sorry? 1737 01:32:55,000 --> 01:32:56,170 AUDIENCE: Tweens again? 1738 01:32:56,170 --> 01:32:57,220 SPEAKER 1: Tweens. 1739 01:32:57,220 --> 01:33:00,790 Yes, we could do it with tweens, but from a data structure 1740 01:33:00,790 --> 01:33:02,050 standpoint, how would we-- 1741 01:33:02,050 --> 01:33:05,262 because that will just tween the xy, but that won't necessarily 1742 01:33:05,262 --> 01:33:06,970 fix-- the underlying data structure still 1743 01:33:06,970 --> 01:33:09,820 has to represent-- because we're going to do iterations over it, 1744 01:33:09,820 --> 01:33:12,520 we have to have references to the tiles in the right spots. 1745 01:33:12,520 --> 01:33:15,130 AUDIENCE: So just shifting it was the table 1746 01:33:15,130 --> 01:33:17,260 from the fourth row to the fifth row. 1747 01:33:17,260 --> 01:33:20,890 SPEAKER 1: So how would you start by getting this tile down 1748 01:33:20,890 --> 01:33:23,704 to this position? 1749 01:33:23,704 --> 01:33:26,470 AUDIENCE: Switching it from the fourth row to the fifth row. 1750 01:33:26,470 --> 01:33:27,655 SPEAKER 1: You would. 1751 01:33:27,655 --> 01:33:31,939 How would your algorithm work step by step to making sure that would happen? 1752 01:33:31,939 --> 01:33:36,669 1753 01:33:36,669 --> 01:33:41,019 AUDIENCE: Is it start from the bottom, and if that's nil, it would go up more 1754 01:33:41,019 --> 01:33:41,810 SPEAKER 1: Exactly. 1755 01:33:41,810 --> 01:33:43,660 That's exactly you do. 1756 01:33:43,660 --> 01:33:49,790 You start from the bottom, and then whenever we have anything that's nil, 1757 01:33:49,790 --> 01:33:53,910 we need to look for the first tile above it that's not nil, and shift it down. 1758 01:33:53,910 --> 01:33:57,350 So in this case, we start from the bottom, and we go up this way. 1759 01:33:57,350 --> 01:34:00,380 Not nil, not nil, not nil, not nil, not nil. 1760 01:34:00,380 --> 01:34:02,630 So none of those are spaces in the code. 1761 01:34:02,630 --> 01:34:07,626 It's called spaceY, or space and spaceY. 1762 01:34:07,626 --> 01:34:09,500 So we go to the next column over, and we only 1763 01:34:09,500 --> 01:34:11,610 have to check vertically in this case. 1764 01:34:11,610 --> 01:34:13,735 We don't have to do a horizontal check for anything 1765 01:34:13,735 --> 01:34:15,870 because gravity can only follow in one direction. 1766 01:34:15,870 --> 01:34:17,120 So we just go over here. 1767 01:34:17,120 --> 01:34:21,770 So we're only looping through this code, effectively, in this case, five times, 1768 01:34:21,770 --> 01:34:24,770 but in our code, eight times. 1769 01:34:24,770 --> 01:34:28,400 But it needs to be a while loop rather than a for loop, 1770 01:34:28,400 --> 01:34:29,820 and we'll see why in a second. 1771 01:34:29,820 --> 01:34:31,460 But start here. 1772 01:34:31,460 --> 01:34:33,650 We see oh, we have a space there. 1773 01:34:33,650 --> 01:34:39,080 So what we need to do is say, OK, the lowest space is here. 1774 01:34:39,080 --> 01:34:42,764 So we need to look for the next tile above it, and shift it down. 1775 01:34:42,764 --> 01:34:44,930 So we keep a reference to this, and we look up here, 1776 01:34:44,930 --> 01:34:46,520 and we say oh, this is a tile. 1777 01:34:46,520 --> 01:34:47,300 Perfect. 1778 01:34:47,300 --> 01:34:49,510 So I'm just going to take this tile, and I'm 1779 01:34:49,510 --> 01:34:52,460 going to set that space index to that tile, 1780 01:34:52,460 --> 01:34:55,010 and then I'm going to set this index to nil. 1781 01:34:55,010 --> 01:34:58,460 And then we just have to start again, though, from here 1782 01:34:58,460 --> 01:35:01,670 because this tile is now space. 1783 01:35:01,670 --> 01:35:06,770 So we have to look up here, and say OK, so basically, our y counter 1784 01:35:06,770 --> 01:35:10,670 stays at that thing, and then just goes back up because our y counter could, 1785 01:35:10,670 --> 01:35:13,310 theoretically, come all the way up here before it finds a tile, 1786 01:35:13,310 --> 01:35:17,450 and then shift it all the way down, but we can't just-- or here, let's 1787 01:35:17,450 --> 01:35:19,220 say there are two tiles right here. 1788 01:35:19,220 --> 01:35:22,400 Our y counter might end up here because these are all spaces, 1789 01:35:22,400 --> 01:35:25,220 and the tile gets shifted down here, but we can't just 1790 01:35:25,220 --> 01:35:28,670 start our y counter back here again, and go up to the next tile, 1791 01:35:28,670 --> 01:35:31,580 and look for spaces because we have all these spaces down here. 1792 01:35:31,580 --> 01:35:32,520 So it's a while loop. 1793 01:35:32,520 --> 01:35:36,690 So while, basically, there are no spaces on any of these points, 1794 01:35:36,690 --> 01:35:39,080 we need to make sure that we keep lowering the tile. 1795 01:35:39,080 --> 01:35:43,010 So keep a reference here, tile here, bring it down, space here. 1796 01:35:43,010 --> 01:35:44,690 So we keep a reference with space. 1797 01:35:44,690 --> 01:35:46,460 We say oh, there's a space here now. 1798 01:35:46,460 --> 01:35:48,935 We can look all the way up, but there's no tiles anywhere. 1799 01:35:48,935 --> 01:35:51,810 So we know that we can just move onto the next iteration of the loop. 1800 01:35:51,810 --> 01:35:52,935 We haven't found any tiles. 1801 01:35:52,935 --> 01:35:54,300 We don't need to bother with it. 1802 01:35:54,300 --> 01:35:55,370 Same thing here. 1803 01:35:55,370 --> 01:35:59,450 We have a space reference here, tile, found a tile, 1804 01:35:59,450 --> 01:36:04,970 shift it down, space here, tile here, shift it down, space here, tile here, 1805 01:36:04,970 --> 01:36:09,240 shift it down, space, space, done, and then we rinse, and repeat that. 1806 01:36:09,240 --> 01:36:13,010 It's kind of almost like a bubble sort type of algorithm. 1807 01:36:13,010 --> 01:36:18,180 Not a sort, but it has the same sort of look and behavior to it, more or less. 1808 01:36:18,180 --> 01:36:20,780 Here's just a visual illustration of it. 1809 01:36:20,780 --> 01:36:24,050 So start from the bottom, go up, we're looking for spaces here. 1810 01:36:24,050 --> 01:36:26,510 No spaces; column is perfectly stable. 1811 01:36:26,510 --> 01:36:30,440 We found a space here, tile is there, shift it down. 1812 01:36:30,440 --> 01:36:35,650 Restart the loop from the tile, space, space, space, no more spaces; 1813 01:36:35,650 --> 01:36:36,710 column stable. 1814 01:36:36,710 --> 01:36:42,350 Space found, tile found, shift, space found, tile found, shift, space found, 1815 01:36:42,350 --> 01:36:46,100 tile found, shift, and so on, and so forth. 1816 01:36:46,100 --> 01:36:47,960 And so that's the gist. 1817 01:36:47,960 --> 01:36:50,160 Super, super basic. 1818 01:36:50,160 --> 01:36:54,705 But now we actually have to replace the tiles. 1819 01:36:54,705 --> 01:36:56,330 AUDIENCE: You don't even need to check. 1820 01:36:56,330 --> 01:36:58,330 Once you shift a block down, you don't even 1821 01:36:58,330 --> 01:37:00,162 need to check the space above it, whether it's a space 1822 01:37:00,162 --> 01:37:02,911 or not because you know that's automatically a space when you just 1823 01:37:02,911 --> 01:37:05,294 shifted a block, right? 1824 01:37:05,294 --> 01:37:05,960 SPEAKER 1: Yeah. 1825 01:37:05,960 --> 01:37:06,980 Actually, that's true. 1826 01:37:06,980 --> 01:37:10,460 Yeah, I guess in that case, you wouldn't need to. 1827 01:37:10,460 --> 01:37:16,530 But we do need a reference to that space, and keep checking above it. 1828 01:37:16,530 --> 01:37:19,430 But yeah, I guess you probably don't need, necessarily, 1829 01:37:19,430 --> 01:37:21,200 to check whether it's a space or not. 1830 01:37:21,200 --> 01:37:25,460 You can just assume it's a space, and I actually think my code does that. 1831 01:37:25,460 --> 01:37:28,790 I'm not 100% sure off the top of my head. 1832 01:37:28,790 --> 01:37:29,840 We can check, and see. 1833 01:37:29,840 --> 01:37:35,882 1834 01:37:35,882 --> 01:37:37,840 I think it's down here. 1835 01:37:37,840 --> 01:37:38,920 No? 1836 01:37:38,920 --> 01:37:39,420 Is it? 1837 01:37:39,420 --> 01:37:42,260 1838 01:37:42,260 --> 01:37:48,920 Oh no, it's in get falling tiles, I think, which is on line 177. 1839 01:37:48,920 --> 01:37:54,890 So for 1 to 8 in x, we keep a spaceY. 1840 01:37:54,890 --> 01:37:57,617 So spaceY, we set it zero because that's just a variable. 1841 01:37:57,617 --> 01:37:58,700 We don't have a space yet. 1842 01:37:58,700 --> 01:38:01,100 So just because you can't index a tile-- 1843 01:38:01,100 --> 01:38:04,910 you can index Lua tables by zero, but because they're not by default, 1844 01:38:04,910 --> 01:38:09,740 we're just setting the zero as like our false space flag. 1845 01:38:09,740 --> 01:38:12,170 y gets 8, starting at the bottom. 1846 01:38:12,170 --> 01:38:17,090 So while y is greater than or equal to 1, tile gets self.tiles y of x. 1847 01:38:17,090 --> 01:38:21,230 In that case, it's going to be at the eighth position. 1848 01:38:21,230 --> 01:38:23,930 So space is set to false, but space is our space 1849 01:38:23,930 --> 01:38:27,830 found flag, and also whether or not the tile that we just looked at 1850 01:38:27,830 --> 01:38:29,360 was a space. 1851 01:38:29,360 --> 01:38:32,552 Sorry, no, it's just our space flag. 1852 01:38:32,552 --> 01:38:35,010 We check to see if there is a tile at our current position. 1853 01:38:35,010 --> 01:38:37,370 So recall, everything gets set to nil. 1854 01:38:37,370 --> 01:38:41,050 So we can just say local tile gets self.tiles y x. 1855 01:38:41,050 --> 01:38:42,910 This will be nil if there was no tile there. 1856 01:38:42,910 --> 01:38:49,450 So if tile, which means if it's not nil, if it equal something, spaceY of x 1857 01:38:49,450 --> 01:38:52,240 is going to equal that tile. 1858 01:38:52,240 --> 01:38:56,230 We keep a reference to spaceY, which is our last space. 1859 01:38:56,230 --> 01:39:03,340 We set tile.gridY to spaceY because we have to reset it to gridY. 1860 01:39:03,340 --> 01:39:04,620 We're going to tween it here. 1861 01:39:04,620 --> 01:39:07,720 This is how we actually get the falling, tweening behavior. 1862 01:39:07,720 --> 01:39:12,070 We're going to tween it's y to tile.gridY minus 1 times 32, 1863 01:39:12,070 --> 01:39:19,970 recall, because coordinates are zero based, but Lua tables are one indexed. 1864 01:39:19,970 --> 01:39:25,745 Space is false, y is spaceY, and then spaceY gets zero. 1865 01:39:25,745 --> 01:39:28,390 1866 01:39:28,390 --> 01:39:32,050 Basically, we're going to start at the-- 1867 01:39:32,050 --> 01:39:37,360 we're going to put spaceY to that tile, and then we're 1868 01:39:37,360 --> 01:39:41,980 going to set spaceY to 0. 1869 01:39:41,980 --> 01:39:46,780 I think it actually does, in this case, it is actually checking that tile 1870 01:39:46,780 --> 01:39:49,160 to make sure that it's-- 1871 01:39:49,160 --> 01:39:52,086 yeah, because it's just getting set to the tile-- 1872 01:39:52,086 --> 01:39:54,460 spaceY being the tile that we just replaced, and just put 1873 01:39:54,460 --> 01:39:55,660 into an actual spot. 1874 01:39:55,660 --> 01:39:58,701 So it does actually make the check up above to see whether that's a space 1875 01:39:58,701 --> 01:40:00,220 or not. 1876 01:40:00,220 --> 01:40:04,050 Only one caveat though actually is-- 1877 01:40:04,050 --> 01:40:05,550 actually, no, that wouldn't be true. 1878 01:40:05,550 --> 01:40:07,841 I was going to say, if you're at the top of the screen, 1879 01:40:07,841 --> 01:40:12,850 but no because there's no way we can be at the top of the screen, 1880 01:40:12,850 --> 01:40:17,590 and have-- yeah, I don't think it would work. 1881 01:40:17,590 --> 01:40:20,710 A small optimization you could make is you just assume always a space. 1882 01:40:20,710 --> 01:40:21,209 Yeah. 1883 01:40:21,209 --> 01:40:24,580 1884 01:40:24,580 --> 01:40:26,980 That's the get falling tiles in a nut shell, 1885 01:40:26,980 --> 01:40:30,460 or at least the ones that are falling from gravity. 1886 01:40:30,460 --> 01:40:35,020 And then we also have tiles that we want to add to replace them, 1887 01:40:35,020 --> 01:40:38,240 and so we'll see that here. 1888 01:40:38,240 --> 01:40:39,790 So this code. 1889 01:40:39,790 --> 01:40:44,310 So what we need to do to replace-- 1890 01:40:44,310 --> 01:40:47,868 what do you guys think we need to do to get replacement tiles? 1891 01:40:47,868 --> 01:40:52,708 1892 01:40:52,708 --> 01:40:56,580 AUDIENCE: Check response, and check if it's empty, [INAUDIBLE] 1893 01:40:56,580 --> 01:40:58,709 but if it's not, then you're done. 1894 01:40:58,709 --> 01:40:59,750 SPEAKER 1: Yeah, exactly. 1895 01:40:59,750 --> 01:41:03,050 So the response was check to see from the top 1896 01:41:03,050 --> 01:41:06,830 if there are any tiles that are empty, and if there are, 1897 01:41:06,830 --> 01:41:11,360 then spawn some tiles, and then ideally, tween them to their new positions. 1898 01:41:11,360 --> 01:41:15,419 You can basically just assign them to their values here. 1899 01:41:15,419 --> 01:41:17,210 So what we need to do, actually, though, is 1900 01:41:17,210 --> 01:41:21,920 if we spawn a tile up here to put into any of these positions, their gridY's 1901 01:41:21,920 --> 01:41:23,690 need to be set in advance because they're 1902 01:41:23,690 --> 01:41:25,740 going to occupy that space anyway. 1903 01:41:25,740 --> 01:41:31,490 Their actual y position needs to be tweened. 1904 01:41:31,490 --> 01:41:35,150 So because the x and the y are separate from the gridY, and the gridX, 1905 01:41:35,150 --> 01:41:38,692 those are just table indices, but not their coordinates. 1906 01:41:38,692 --> 01:41:40,400 We can tween those, and it won't actually 1907 01:41:40,400 --> 01:41:41,983 have any effect on the data structure. 1908 01:41:41,983 --> 01:41:46,070 The data structure itself can maintain-- we can still use the data structure-- 1909 01:41:46,070 --> 01:41:48,350 put a tile in its right spot in our table, 1910 01:41:48,350 --> 01:41:53,667 and then give it the right gridX, and gridY, but tween the x and y value. 1911 01:41:53,667 --> 01:41:55,250 We can do whatever we want with those. 1912 01:41:55,250 --> 01:41:58,220 We can make them spin around, and stuff as long 1913 01:41:58,220 --> 01:42:01,430 as the data structure is intact, and ideally, 1914 01:42:01,430 --> 01:42:04,100 as long as we can't input while it's doing it's movement, 1915 01:42:04,100 --> 01:42:06,770 and stuff like that because that could create some visual bugs. 1916 01:42:06,770 --> 01:42:10,670 And so what we do is we actually disable input when a swap is taking place, 1917 01:42:10,670 --> 01:42:14,240 and you'll see that in the distribution code. 1918 01:42:14,240 --> 01:42:16,880 But yes, count how many spaces there are. 1919 01:42:16,880 --> 01:42:19,670 Spawn four tiles, spawn two tiles, spawn two tiles 1920 01:42:19,670 --> 01:42:24,110 spawn four tiles that have already been given their right gridX, gridY, 1921 01:42:24,110 --> 01:42:27,170 and then just tween their y to wherever it needs to go. 1922 01:42:27,170 --> 01:42:30,580 It's gridY times 32-- 1923 01:42:30,580 --> 01:42:33,110 gridY minus 1 times 32. 1924 01:42:33,110 --> 01:42:34,610 And so that's what we're doing here. 1925 01:42:34,610 --> 01:42:39,980 We're just count, and then boop. 1926 01:42:39,980 --> 01:42:43,624 That was my favorite part of putting this show together. 1927 01:42:43,624 --> 01:42:46,790 And so we're going to get into a couple of minutes of talking about sprites, 1928 01:42:46,790 --> 01:42:50,164 and palettes, but I think the one thing-- 1929 01:42:50,164 --> 01:42:51,080 blanking for a second. 1930 01:42:51,080 --> 01:42:53,600 I was going to talk about one last thing. 1931 01:42:53,600 --> 01:42:57,590 Let me see if I can figure out what that was. 1932 01:42:57,590 --> 01:43:02,960 Oh, right, so in the board-- 1933 01:43:02,960 --> 01:43:08,360 sorry, in the play state, I believe, is where this is, there is a function. 1934 01:43:08,360 --> 01:43:12,460 1935 01:43:12,460 --> 01:43:15,980 So play state has it's own calculateMatches, basically, 1936 01:43:15,980 --> 01:43:17,360 where it waits for you to-- 1937 01:43:17,360 --> 01:43:20,690 where once you've basically swapped any two tiles, 1938 01:43:20,690 --> 01:43:23,390 it will calculate whether those tiles have made a match. 1939 01:43:23,390 --> 01:43:26,150 1940 01:43:26,150 --> 01:43:29,480 And we're going to get matches via self.board calculateMatches, 1941 01:43:29,480 --> 01:43:31,520 the function that we were looking at before. 1942 01:43:31,520 --> 01:43:32,810 If there are any matches-- 1943 01:43:32,810 --> 01:43:35,609 well, we play a sound effect here for every match. 1944 01:43:35,609 --> 01:43:37,400 This is where you also calculate the score. 1945 01:43:37,400 --> 01:43:41,312 You just multiply the number of tiles in a match by 50, 1946 01:43:41,312 --> 01:43:43,880 and part of the assignment will be adding some value 1947 01:43:43,880 --> 01:43:45,890 to the individual varieties of the tiles. 1948 01:43:45,890 --> 01:43:48,890 1949 01:43:48,890 --> 01:43:52,190 Here, we tween. 1950 01:43:52,190 --> 01:43:58,220 So we return also from the board class a table 1951 01:43:58,220 --> 01:44:02,810 of tweens for all of the new tiles that we just spawned, 1952 01:44:02,810 --> 01:44:07,740 and so what we're going to end up doing is tweening all of them here. 1953 01:44:07,740 --> 01:44:10,100 So notice that we're passing in a timer.tween, 1954 01:44:10,100 --> 01:44:11,870 this variable, tilesToFall. 1955 01:44:11,870 --> 01:44:15,650 That's a definition file that we're just returning from our board class. 1956 01:44:15,650 --> 01:44:21,950 And so once those are all finished, then we get new tiles, 1957 01:44:21,950 --> 01:44:25,620 and then we tween here. 1958 01:44:25,620 --> 01:44:28,074 I think this line is redundant, actually. 1959 01:44:28,074 --> 01:44:29,990 I think this might have been a debugging line. 1960 01:44:29,990 --> 01:44:31,220 I don't think we need this. 1961 01:44:31,220 --> 01:44:33,750 1962 01:44:33,750 --> 01:44:35,000 No, we don't need this at all. 1963 01:44:35,000 --> 01:44:36,650 So sorry. 1964 01:44:36,650 --> 01:44:39,260 This is the important part. 1965 01:44:39,260 --> 01:44:41,720 We're going to tween-- 1966 01:44:41,720 --> 01:44:42,560 wait, we do need it. 1967 01:44:42,560 --> 01:44:45,480 Self.board getNewTiles. 1968 01:44:45,480 --> 01:44:47,338 What am I thinking of? 1969 01:44:47,338 --> 01:44:53,570 1970 01:44:53,570 --> 01:44:55,320 Sorry, a little bit confused for a second. 1971 01:44:55,320 --> 01:44:58,012 I thought this was an empty function that I defined. 1972 01:44:58,012 --> 01:44:59,970 Get new tiles. 1973 01:44:59,970 --> 01:45:02,770 Yeah, this returns an empty table. 1974 01:45:02,770 --> 01:45:06,940 But basically, the gist of it is the play 1975 01:45:06,940 --> 01:45:13,485 state, when it calls this function, it will call itself every time. 1976 01:45:13,485 --> 01:45:15,884 1977 01:45:15,884 --> 01:45:18,300 And I think this is actually having the result of doing it 1978 01:45:18,300 --> 01:45:20,591 instantly here because newTiles is just an empty table. 1979 01:45:20,591 --> 01:45:28,620 I think all this should be is just this inside all of this like that. 1980 01:45:28,620 --> 01:45:31,980 But that has the result of calling itself again 1981 01:45:31,980 --> 01:45:35,520 because when we get new tiles coming from the top of the screen, 1982 01:45:35,520 --> 01:45:40,170 we could potentially have a case where we've gotten some matches, 1983 01:45:40,170 --> 01:45:45,090 and it's not shown here, but new falling tiles could give us new matches. 1984 01:45:45,090 --> 01:45:48,840 So after we calculate matches, let's say maybe this tile dropped here, 1985 01:45:48,840 --> 01:45:51,135 but it was a purple, and these two were already there. 1986 01:45:51,135 --> 01:45:53,010 We've already calculated matches, but then we 1987 01:45:53,010 --> 01:45:56,690 need to do it again, and then do it again if it keeps happening. 1988 01:45:56,690 --> 01:45:59,790 And so you should be recursively call self calculateMatches 1989 01:45:59,790 --> 01:46:06,510 in that case, which will have the effect of accomplishing that because this 1990 01:46:06,510 --> 01:46:07,980 will always look for matches. 1991 01:46:07,980 --> 01:46:11,580 And so when we call self calculateMatches here, over, and over 1992 01:46:11,580 --> 01:46:14,096 again, until there are no matches-- 1993 01:46:14,096 --> 01:46:16,470 as long as there are matches, this should keep happening. 1994 01:46:16,470 --> 01:46:19,980 You should keep getting scores, and tiles should keep getting cleared. 1995 01:46:19,980 --> 01:46:22,470 But as soon as that's not the case anymore, 1996 01:46:22,470 --> 01:46:27,005 then self.canInput equals true, and we're not calculating matches anymore. 1997 01:46:27,005 --> 01:46:29,630 We don't recursively call the function anymore, and we're done. 1998 01:46:29,630 --> 01:46:31,230 And so that's just the point I wanted to illustrate. 1999 01:46:31,230 --> 01:46:34,500 Got slightly confused by, I think, what was a vestige of my old code. 2000 01:46:34,500 --> 01:46:37,109 Maybe I was trying something, but I think this, ultimately, 2001 01:46:37,109 --> 01:46:39,900 should just be this, and I'll test it, and make sure, and then push 2002 01:46:39,900 --> 01:46:40,410 the change. 2003 01:46:40,410 --> 01:46:42,960 2004 01:46:42,960 --> 01:46:44,972 And it doesn't need to be over 0.25 seconds. 2005 01:46:44,972 --> 01:46:45,930 It can just be instant. 2006 01:46:45,930 --> 01:46:48,102 2007 01:46:48,102 --> 01:46:50,560 Palettes, really quickly, with something I wanted to cover, 2008 01:46:50,560 --> 01:46:53,606 which was just the idea of taking art, and then just-- and I 2009 01:46:53,606 --> 01:46:55,230 have a couple of cool examples to show. 2010 01:46:55,230 --> 01:46:58,080 Just taking some sort of picture, and then giving it-- 2011 01:46:58,080 --> 01:47:03,060 only using or some sort of image, and only using 32, in this case, 2012 01:47:03,060 --> 01:47:05,160 or some arbitrary number of colors. 2013 01:47:05,160 --> 01:47:09,390 This is some fancy stuff that some person named DawnBringer online did. 2014 01:47:09,390 --> 01:47:13,170 He generated a very famous 32 color palette called DawnBringer's 32 color 2015 01:47:13,170 --> 01:47:14,760 palette. 2016 01:47:14,760 --> 01:47:16,380 But basically, it allows-- 2017 01:47:16,380 --> 01:47:18,990 this is done with just 32 colors we see on the screen. 2018 01:47:18,990 --> 01:47:21,750 Those are all dithered. 2019 01:47:21,750 --> 01:47:27,120 Dithering is a term which means to just draw two colors pixel by pixel, 2020 01:47:27,120 --> 01:47:31,590 interleaved, so that from far away it looks like a brand new color, 2021 01:47:31,590 --> 01:47:32,880 and this is a dithering chart. 2022 01:47:32,880 --> 01:47:35,550 This just shows you every color here at the very top. 2023 01:47:35,550 --> 01:47:37,570 These are all 32 colors. 2024 01:47:37,570 --> 01:47:42,420 These are 32, and those are 32 intersected with each other such 2025 01:47:42,420 --> 01:47:45,030 that they're just like dot, dot, dot, dot, dot. 2026 01:47:45,030 --> 01:47:47,027 Every other dot is every other color. 2027 01:47:47,027 --> 01:47:49,860 And so you can do some pretty amazing things with just a few colors. 2028 01:47:49,860 --> 01:47:52,140 This is actually done with 16 colors. 2029 01:47:52,140 --> 01:47:56,940 All four of those are only 16 colors. 2030 01:47:56,940 --> 01:48:00,500 This is just to show you what it looks like when you do it to an actual image. 2031 01:48:00,500 --> 01:48:04,159 This is an example of what using a color palette on an image that 2032 01:48:04,159 --> 01:48:05,700 doesn't work well with it looks like. 2033 01:48:05,700 --> 01:48:07,533 So this is a regular image with I don't know 2034 01:48:07,533 --> 01:48:10,080 how many colors, thousands of millions of colors, and this 2035 01:48:10,080 --> 01:48:12,760 is using DawnBringer's 32 color palette. 2036 01:48:12,760 --> 01:48:15,390 So still looks very similar to what it should. 2037 01:48:15,390 --> 01:48:19,800 It's a cat, but there's a lot of weird things going on in the background 2038 01:48:19,800 --> 01:48:24,240 because taking an image with a lot of blur, and a lot of distorted color, 2039 01:48:24,240 --> 01:48:28,230 has the effect of giving you blotchy patterns when you go down 2040 01:48:28,230 --> 01:48:30,640 to a few colors. 2041 01:48:30,640 --> 01:48:34,807 But this is an example of an image that has a lot of flatter colors. 2042 01:48:34,807 --> 01:48:36,640 There's still a lot of colors in this image. 2043 01:48:36,640 --> 01:48:40,800 There are some shades, and stuff like that, but this is thousands of colors, 2044 01:48:40,800 --> 01:48:42,490 and this is 32 colors. 2045 01:48:42,490 --> 01:48:45,509 So clearly, if you do it on the right thing, 2046 01:48:45,509 --> 01:48:47,550 you can actually get really good effects with it. 2047 01:48:47,550 --> 01:48:52,004 And so again, not a whole lot of difference, but this one's 2048 01:48:52,004 --> 01:48:54,420 got I don't know how many hundreds of thousands of colors, 2049 01:48:54,420 --> 01:48:57,450 and this one's only got 32. 2050 01:48:57,450 --> 01:49:00,150 And so how it ties back into what we're doing 2051 01:49:00,150 --> 01:49:06,910 is this is using a 32-bit color or 32 color palette on purpose. 2052 01:49:06,910 --> 01:49:09,060 This is actually DawnBringer's 32 color palette. 2053 01:49:09,060 --> 01:49:12,510 Breakout used the same palette, 32 colors, 2054 01:49:12,510 --> 01:49:17,770 and a lot of our 2D future lectures will use limited color palettes. 2055 01:49:17,770 --> 01:49:22,890 If you're trying to draw sprite art, and you want some quick, and easy ways just 2056 01:49:22,890 --> 01:49:26,100 to give your work a little bit of consistency, 2057 01:49:26,100 --> 01:49:30,180 I recommend trying to pick 8, or 16, or 32 colors, 2058 01:49:30,180 --> 01:49:32,570 and just adhering to using just those. 2059 01:49:32,570 --> 01:49:35,580 And you'd be surprised at how much you get out 2060 01:49:35,580 --> 01:49:39,240 of it, and how much more cohesive your work will look just 2061 01:49:39,240 --> 01:49:41,200 by imposing that constraint on you. 2062 01:49:41,200 --> 01:49:46,170 It's an artifact of a real world constraint of former hardware. 2063 01:49:46,170 --> 01:49:48,720 The NES only had so many colors it could color each sprite, 2064 01:49:48,720 --> 01:49:51,570 like four colors, or something that. 2065 01:49:51,570 --> 01:49:55,530 And so you also get a-- if you're going for an authentic retro look, 2066 01:49:55,530 --> 01:49:56,920 it will help you in that sense. 2067 01:49:56,920 --> 01:49:59,580 And then different from palettes, but related 2068 01:49:59,580 --> 01:50:02,550 is palette swapping, which is another term you've probably heard, 2069 01:50:02,550 --> 01:50:05,295 which is basically all of these Mario sprites-- 2070 01:50:05,295 --> 01:50:07,950 2071 01:50:07,950 --> 01:50:12,600 they'll probably start with a gray scale Mario, some like gray version 2072 01:50:12,600 --> 01:50:15,990 where each of these separate colors are mapped out 2073 01:50:15,990 --> 01:50:20,430 to some table where one equals red, two equals blue, or whatever. 2074 01:50:20,430 --> 01:50:23,340 And then you can just shift all of them, and then you 2075 01:50:23,340 --> 01:50:25,470 get all of these different nice effects, assuming 2076 01:50:25,470 --> 01:50:30,690 that you've created a good palette. 2077 01:50:30,690 --> 01:50:33,480 You can get a lot of reuse, and this is actually 2078 01:50:33,480 --> 01:50:38,310 how Super Mario Bros. used to do some of its programming. 2079 01:50:38,310 --> 01:50:41,310 The clouds and the bushes were the same sprite. 2080 01:50:41,310 --> 01:50:42,960 One was just colored green. 2081 01:50:42,960 --> 01:50:48,780 It was palette swapped green from the white that the cloud was colored. 2082 01:50:48,780 --> 01:50:51,830 So that's the gist of Match 3. 2083 01:50:51,830 --> 01:50:54,150 Assignment 3 is going to have a few parts to it. 2084 01:50:54,150 --> 01:50:55,740 So time addition on matches. 2085 01:50:55,740 --> 01:50:58,800 So when you get a match, you should get time added to the clock. 2086 01:50:58,800 --> 01:51:01,290 Currently, right now, you only get 60 seconds. 2087 01:51:01,290 --> 01:51:05,130 It's a little bit hard to actually get past level two at this point. 2088 01:51:05,130 --> 01:51:08,880 So getting points for every tile in a match. 2089 01:51:08,880 --> 01:51:11,490 Make it so that level one starts with simple flat blocks. 2090 01:51:11,490 --> 01:51:14,580 So earlier, we saw the array of tiles, and it 2091 01:51:14,580 --> 01:51:18,625 was flat tiles on the first index of every color row, 2092 01:51:18,625 --> 01:51:21,750 but there were several other patterns like x's, and circles, and triangles, 2093 01:51:21,750 --> 01:51:22,410 and stuff. 2094 01:51:22,410 --> 01:51:27,780 Make those worth some higher amount of value, each one. 2095 01:51:27,780 --> 01:51:31,324 Create random shiny variants of blocks that will destroy an entire row when 2096 01:51:31,324 --> 01:51:31,990 you get a match. 2097 01:51:31,990 --> 01:51:32,930 So have a block. 2098 01:51:32,930 --> 01:51:35,160 It should have some field, shiny or something. 2099 01:51:35,160 --> 01:51:38,310 If it's shiny, render it with something to make it look shiny. 2100 01:51:38,310 --> 01:51:41,370 You can use particle effect if you want. 2101 01:51:41,370 --> 01:51:48,000 You can put a very opaque, or a very transparent maybe yellowish or whitish 2102 01:51:48,000 --> 01:51:50,430 rectangle on it to give it a brighter look. 2103 01:51:50,430 --> 01:51:53,820 And then if it's in a match, that entire row 2104 01:51:53,820 --> 01:51:58,312 should get cleared instead of just that match. 2105 01:51:58,312 --> 01:52:00,270 Only allow swapping when it results in a match. 2106 01:52:00,270 --> 01:52:03,150 This is an important thing because right now, mathematically, 2107 01:52:03,150 --> 01:52:05,850 it's actually very unlikely that you'll get a board that 2108 01:52:05,850 --> 01:52:10,660 has matches on it to begin with. 2109 01:52:10,660 --> 01:52:16,350 So you're going to have to pick a subset of tiles in your implementation, 2110 01:52:16,350 --> 01:52:20,250 and actually use those instead of just using all of them. 2111 01:52:20,250 --> 01:52:25,470 Pick six tiles, which you can get variants on, or just whatever flat 2112 01:52:25,470 --> 01:52:28,920 colors, and then use only those to spawn your board. 2113 01:52:28,920 --> 01:52:32,600 Don't use all 18, or however many there are. 2114 01:52:32,600 --> 01:52:35,520 And then optional, if you're curious, if you want, probably, 2115 01:52:35,520 --> 01:52:38,250 an arguably better gaming experience with this, 2116 01:52:38,250 --> 01:52:41,490 just implement actually playing with the mouse. 2117 01:52:41,490 --> 01:52:44,880 Being able to click and drag, or just click individual tiles. 2118 01:52:44,880 --> 01:52:47,220 And to do that, you will need to convert-- 2119 01:52:47,220 --> 01:52:49,620 because we use the push library for virtual resolution, 2120 01:52:49,620 --> 01:52:53,340 you'll need to convert the window mouse coordinates 2121 01:52:53,340 --> 01:52:56,584 to push coordinates so that they'll map into the game space appropriately, 2122 01:52:56,584 --> 01:52:58,875 and so you'll use a function called push to game, where 2123 01:52:58,875 --> 01:53:03,780 it takes an x and y, where the x and the y will be your mouse coordinates. 2124 01:53:03,780 --> 01:53:06,450 Next time, we're actually going to get into a little bit 2125 01:53:06,450 --> 01:53:11,880 more robust of a game, arguably, like a Mario clone. 2126 01:53:11,880 --> 01:53:14,910 This is actually where this course started 2127 01:53:14,910 --> 01:53:16,920 was I taught a seminar on Super Mario Bros. 2128 01:53:16,920 --> 01:53:20,186 We won't be using Super Mario Bros. assets because of copyright, 2129 01:53:20,186 --> 01:53:22,810 but we'll be using this tile sheet here, which is very similar. 2130 01:53:22,810 --> 01:53:23,950 It's got a nice aesthetic. 2131 01:53:23,950 --> 01:53:25,230 We'll cover tile maps. 2132 01:53:25,230 --> 01:53:27,990 So how to generate levels using individual tiles. 2133 01:53:27,990 --> 01:53:30,187 2D animation, so rather than just like static things 2134 01:53:30,187 --> 01:53:33,270 that we've had going on so far, you'll have characters that actually walk, 2135 01:53:33,270 --> 01:53:35,241 and jump, and do different things. 2136 01:53:35,241 --> 01:53:36,990 We'll talk about how to actually procedure 2137 01:53:36,990 --> 01:53:40,710 generate platformer levels, which isn't terribly difficult. 2138 01:53:40,710 --> 01:53:43,630 It sounds kind of difficult, but it's actually pretty-- 2139 01:53:43,630 --> 01:53:46,650 for very simple stuff, it's not too bad. 2140 01:53:46,650 --> 01:53:49,097 Basic platformer physics, so hitting blocks, and jumping, 2141 01:53:49,097 --> 01:53:49,930 and stuff like that. 2142 01:53:49,930 --> 01:53:54,780 We've covered a lot of that with Flappy Bird, actually, and actually, 2143 01:53:54,780 --> 01:53:57,890 the bricks from Breakout kind of tie into it a little bit. 2144 01:53:57,890 --> 01:54:01,890 Hurt boxes so we can have enemies that hurt you, and visa versa. 2145 01:54:01,890 --> 01:54:05,100 And power ups so that you can change your state in some way to make you 2146 01:54:05,100 --> 01:54:07,620 larger, or invincible, or whatnot. 2147 01:54:07,620 --> 01:54:08,520 That was Match 3. 2148 01:54:08,520 --> 01:54:11,270 Thanks a lot, and see you next time. 2149 01:54:11,270 --> 01:54:12,091