Subtitles section Play video Print subtitles [MUSIC PLAYING] SPEAKER 1: Hello. Welcome to lecture three of GD50. Today, we're going be talking about Match 3, as shown by the little cubes here on the slide. Match 3 originated a little earlier than 2001, but the first big game that came out that was a sort of genre staple of Match 3 was Bejeweled, shown here on the screen. This is a more modern incarnation of Bejeweled, but it came out originally in 2001. It was actually a web browser game, and the formula is very simple. The premise is you have a grid of different colored or shaped items, usually pretty small, like eight by eight, or so. And your goal is just to simply, like the name says, match three or more of them in a row. If you do, you get a certain number of points. Matching usually more than three gives you more points, or a bonus. And whenever you match three, the blocks will disappear from the grid, and they'll be replaced by more blocks. And the ones that you made holes for, the blocks above them will come down via gravity. This is a more modern incarnation of the formula. This is Candy Crush, which I think most people know. It was a very big hit on mobile devices, and otherwise around 2013, 2012, and that's probably the most recent big Match 3 style game that's come out, but there are a lot of other takes on it-- different versions that try to add new features, and stuff. This is the game that we'll be putting together today, and I'll show you how, and we'll be covering a few other things as well. So the topics today, we'll be covering, first of all, a fundamental concept in dynamic languages, a lot of dynamic languages, and also Lua. It's called anonymous functions, which are functions that are first class, meaning that they operate as data types, and so we can do some fancy stuff with those. Tweening, which means just taking one thing, and interpolating its value between two values from 1, to a destination value over time, which is a very important thing in games. You can do things like move objects. We can also tween their opacity. Just sort of asynchronous behavior, and asynchronous variable manipulation. Timers, very important. We can time something to happen at certain intervals, or after a certain length of time has passed to get us past the idea of storing different timed variables, or different counters, and break away, and keep timer objects that will take care of this for us. We'll see how we do that with a specific library. And then we'll get to the actual details of Match 3, and how to solve matches, and how to account for that. Fill in the grid, account for when we actually solve a match, and repopulate it once we've done so. We'll talk about how to do this procedurally. It's very simple compared to, I think, Breakout's more procedural layout system, but it's still randomisation, and we'll talk about that. And then last, if we have time, we'll talk about sprite art, and palettes, which is a big fundamental thing when you're doing 2D game development, and something that this, and Breakout's sprite sheet took advantage of was the idea of using, on purpose, a restricted set of colors, a palette for creating your 2D art, and there are a lot of really cool, and impressive things we can do with that. But first, I'd like to actually show what we'll be running today in class. So I'm going to come here into my directory. Make sure I'm in the right place, which I am. So this is part of the distribution code, which is online. So there's a Match 3 directory. And would anybody like to come demo it in class? All right, [? Tony. ?] Come on up. All right, so whenever you're ready, go ahead, and just hit Return here. [GAME MUSIC PLAYING] All right, and so this is my implementation of Match 3. It uses a different set of tiles. We have things that are moving over time. It's arrow key based. So if you press Enter on any tile, you can flip it with another tile. It doesn't have to be a match, in this case. So you can-- yeah. Yeah, you kind of got an unlucky board. There, at the very bottom, I see there's a few that-- some brown ones you can match together. So once you match them together, the tiles come down to repopulate. You get new tiles up top. And so notice, we have a timer on the left as well. It's something that's counting down. We'll see how this is actually done with the library we'll be using, as opposed to managing a counter variable keeping track of it over time. A lot of games will actually implement it so you have to-- you can only, and this will be part of the assignment, actually, where you can only move a tile if it creates a match. In this case, there's a-- and we can see the timer counting down, and then once you-- yeah, if you don't get past the goal, there's a game over. But thanks, [? Tony. ?] I appreciate it. AUDIENCE: No problem. SPEAKER 1: So that's the game in a nutshell. And another thing I want to point out to is the transition, the white transitions, and then the level text. Those are all done with timers that we'll be using, and tweens, which we'll be covering in class here as some of our early examples. But there's a lot of stuff that we haven't touched on, but also a lot that we have. It uses sprites, and a sprite sheet, and we've done that thing before. We chop up a sprite sheet, and then take out the whatever individual quads you need, and draw them to the screen. Here's what our goal is, which is we have a title screen with Match 3, start, and quit game in this case. A little bit simpler. No high scores this time just because we've already covered that, but we also have a level screen. It tells us what level we're on before we can actually play, and there will be a transition box with text in it. It'll come down, stop, and then come down again. So almost like chain behavior, which we'll see how we implement that too. And then lastly, on the bottom there is our main game screen, where we have a level, a score, and then a goal. If you get the goal amount of points before the timer runs out, then you go to level 2, and level 3, and level 4, and the score increases by a multiplied factor each time. So the first thing I'd like to start talking about today is how we actually get timer behavior using something a little bit more than just keeping track of some variable that we set to 0, and then adding dt to it every update. There's a better way to do that, but first, why don't we go ahead, and look at timer0. And so what I'm going to do is go into the timer0 directory. I'm going run it, and we can see here, in the middle of the screen, just a very simple-- just a label that just says timer, and then x seconds, where obviously the x is incrementing over time every second. So a crude way, what would be an easy way to implement this? AUDIENCE: Do you like [INAUDIBLE] random in Flappy Bird [INAUDIBLE] randomizer [INAUDIBLE] if you just keep track of your delta prime and add it to some variable outside [INAUDIBLE] you do something else? You could even just display the variable [INAUDIBLE].. SPEAKER 1: Yes. So the response was keep some variable that you modify with dt in update, or display the variable. Yeah, that's definitely a way. Did you have-- AUDIENCE: Yeah, I was just going to say, keep a float variable, and constantly add a dt to it, and display it, but display the truncated version. SPEAKER 1: Yeah. So keep a float variable, but just truncate the delta time off of it. You could do that, definitely. We'll take a look here as to actually how I did do it. It's very similar to that. This is the wrong directory, though. So it's in timer0 in main. So we do have a variable. So the current second here, which we are going to keep track of 0, 1, 2. Lua doesn't really have the notion of truncate a float because when you take a number that's floating point, and you make it into a string, you actually have to do string substitution on it where you use a function called g sub to take off the last part manually because it doesn't really differentiate between ints and floats. It just has a number data type. But we can do this by just keeping track of whether or not we've passed a certain length of time because we know dt is given to us in seconds. We can just add to our variable, and then every time we've gone over 1, because it gives us-- it gives you usually like .013, whatever 1/60 or approximately 1/60 of a second is. Once our timer-- we're going to keep a timer variable-- equals 1, we'll just increment current second by 1, and then we'll set that timer back to 0, and then we'll just repeat over, and over again.