WEBVTT X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 00:00:16.511 --> 00:00:17.510 COLTON OGDEN: All right. 00:00:17.510 --> 00:00:18.510 Good evening, everybody. 00:00:18.510 --> 00:00:19.600 Welcome back to GD50. 00:00:19.600 --> 00:00:21.040 This is lecture six. 00:00:21.040 --> 00:00:23.980 And today we're going to be venturing out of the 8-bit world 00:00:23.980 --> 00:00:26.350 and back into a more modern era of gaming. 00:00:26.350 --> 00:00:28.432 We're talking about Angry Birds today. 00:00:28.432 --> 00:00:30.640 I have pretty fond memories of Angry Birds, actually. 00:00:30.640 --> 00:00:33.640 It was the first mobile game that I remember 00:00:33.640 --> 00:00:38.870 playing where I realized that mobile was actually a viable platform for gaming. 00:00:38.870 --> 00:00:42.100 I played it, I think, back in 2009, was when it was first released. 00:00:42.100 --> 00:00:43.440 And I really enjoyed it. 00:00:43.440 --> 00:00:45.340 It has a very simple formula. 00:00:45.340 --> 00:00:47.870 The goal, if you're unfamiliar, is you have 00:00:47.870 --> 00:00:52.030 birds that you control by a sling shot on the left side of the screen. 00:00:52.030 --> 00:00:54.610 And then these pigs that have stolen your eggs, 00:00:54.610 --> 00:00:56.830 you're trying to destroy them or kill them 00:00:56.830 --> 00:01:01.080 by knocking down their fortresses made out of various materials, wood, glass, 00:01:01.080 --> 00:01:02.195 metal. 00:01:02.195 --> 00:01:03.820 And you get a few different bird types. 00:01:03.820 --> 00:01:08.350 But the gist of it is, basically, just sling shot a bird into some structure, 00:01:08.350 --> 00:01:09.280 knock it down. 00:01:09.280 --> 00:01:12.850 And the whole entire underlying mechanism 00:01:12.850 --> 00:01:15.130 for how things work is via a physics engine, 00:01:15.130 --> 00:01:18.190 which we'll talk about today in lecture, called Box2D Probably 00:01:18.190 --> 00:01:21.280 the most ubiquitous 2D physics engine. 00:01:21.280 --> 00:01:24.070 But that's the overall structure of the game. 00:01:24.070 --> 00:01:27.960 It's literally just throwing things into structures, knocking them down. 00:01:27.960 --> 00:01:32.906 And then that tactile and fun game play makes for really great mobile gaming. 00:01:32.906 --> 00:01:34.530 And I enjoyed it a lot back in the day. 00:01:34.530 --> 00:01:38.980 This is a screenshot of the first level in the first Angry Birds, which 00:01:38.980 --> 00:01:41.410 most people I think have probably seen. 00:01:41.410 --> 00:01:44.020 This is a sample from one of their newer games. 00:01:44.020 --> 00:01:48.020 As you can see, it's taken a whole new layer here. 00:01:48.020 --> 00:01:54.400 There's stone and a bunch of intricately varying structures and new creatures 00:01:54.400 --> 00:01:55.330 and stuff like that. 00:01:55.330 --> 00:01:57.996 The game has changed a lot, but the formula has stayed the same. 00:01:57.996 --> 00:02:02.250 And today we'll explore the foundation of what makes this game work. 00:02:02.250 --> 00:02:04.960 And the topics today, a smaller than usual. 00:02:04.960 --> 00:02:09.009 But Box2D, we can consider as being a pretty large topic. 00:02:09.009 --> 00:02:11.200 We'll be talking about Box2D, which is the physics 00:02:11.200 --> 00:02:13.430 engine we'll be using today in lecture. 00:02:13.430 --> 00:02:16.674 And via Love2D, which has its own wrapper for Box2D. 00:02:16.674 --> 00:02:19.840 And we'll also talk a little bit about mouse input, which you haven't really 00:02:19.840 --> 00:02:20.560 done a lot. 00:02:20.560 --> 00:02:23.680 But it's very apt, especially in the context of mobile gaming. 00:02:23.680 --> 00:02:28.960 Because mouse input and touch input are synonymous. 00:02:28.960 --> 00:02:30.460 But first, let's get a lecture demo. 00:02:30.460 --> 00:02:34.750 If we have a volunteer come up on stage to showcase 00:02:34.750 --> 00:02:35.990 what I've put together here. 00:02:35.990 --> 00:02:38.395 So let me make sure I'm in the right directory here. 00:02:42.960 --> 00:02:45.220 So whenever you're ready, go ahead and press Enter. 00:02:49.450 --> 00:02:54.727 So this is a little demo I put together to demonstrate the concepts we'll 00:02:54.727 --> 00:02:55.810 talk about today in class. 00:02:55.810 --> 00:02:57.700 This is just the Start screen, but it already 00:02:57.700 --> 00:03:02.950 shows Box2D representing a bunch of these square shaped aliens, which 00:03:02.950 --> 00:03:05.880 we'll actually be what we're trying to target in the game. 00:03:05.880 --> 00:03:08.740 But notice that they all fell and had their own collision 00:03:08.740 --> 00:03:12.970 and their own physics that took place, and I didn't have to manually code 00:03:12.970 --> 00:03:14.290 rotation and stuff like this. 00:03:14.290 --> 00:03:17.539 This is all stuff that Box2D takes care of for us. 00:03:17.539 --> 00:03:19.330 And we'll see it used to great effect soon. 00:03:19.330 --> 00:03:20.960 If you go ahead and just click anywhere on the screen, 00:03:20.960 --> 00:03:22.970 we'll go to the main part of the game. 00:03:22.970 --> 00:03:26.422 So this is a very simple representation of what Angry Birds is. 00:03:26.422 --> 00:03:28.130 You start on the left side of the screen. 00:03:28.130 --> 00:03:29.880 You have a bird, in this case an alien, we 00:03:29.880 --> 00:03:33.100 used a free art pack that uses aliens instead of birds, 00:03:33.100 --> 00:03:34.540 but it's the same concept. 00:03:34.540 --> 00:03:36.487 You have an alien that you can click and drag. 00:03:36.487 --> 00:03:38.320 So if you click it and then drag around, you 00:03:38.320 --> 00:03:43.070 can see the trajectory that you'll have when you let go of the mouse. 00:03:43.070 --> 00:03:46.840 So we're simulating where it's going to go via these purple circles. 00:03:46.840 --> 00:03:50.605 And then the goal in Angry Birds is to throw the bird into, 00:03:50.605 --> 00:03:53.980 or the alien, into the fortress guarding the pigs, 00:03:53.980 --> 00:03:56.170 or in this case, square shaped aliens. 00:03:56.170 --> 00:03:59.086 So if you go ahead and just launch the bird by letting go of the mouse 00:03:59.086 --> 00:04:00.124 you'll see. 00:04:00.124 --> 00:04:00.790 Oh, there we go. 00:04:00.790 --> 00:04:02.980 And we knocked down the. 00:04:02.980 --> 00:04:04.330 OK. 00:04:04.330 --> 00:04:08.890 What happened was we shot the alien into the structure. 00:04:08.890 --> 00:04:16.360 It destroyed one of the wooden blocks guarding the other alien. 00:04:16.360 --> 00:04:19.540 And then, as soon as that happened, the top box, 00:04:19.540 --> 00:04:23.590 because these are all being simulated via Box2D's physics engine, 00:04:23.590 --> 00:04:27.190 that other box was detected as being unsupported. 00:04:27.190 --> 00:04:29.290 So it fell down, it hit the other alien. 00:04:29.290 --> 00:04:31.960 And we've coded it so that when a collision occurs 00:04:31.960 --> 00:04:35.950 between an obstacle and our alien of sufficient speed, 00:04:35.950 --> 00:04:37.060 it should kill the alien. 00:04:37.060 --> 00:04:38.800 Which is how it works in Angry Birds. 00:04:38.800 --> 00:04:40.210 So if you'll try it again. 00:04:40.210 --> 00:04:42.470 And this time we hit both of those at the same time. 00:04:42.470 --> 00:04:44.890 So it triggered both of those being deleted. 00:04:44.890 --> 00:04:46.540 But this guy is still alive. 00:04:46.540 --> 00:04:50.110 So after it stops moving, which is similar to how 00:04:50.110 --> 00:04:54.430 it behaves in the original game, it's going to let us try again to shoot. 00:04:54.430 --> 00:04:57.440 So if we try one more time. 00:04:57.440 --> 00:05:00.800 And then we launch and hit it, we kill it and then we get a victory. 00:05:00.800 --> 00:05:04.690 So that's the overall underlying foundation for what Angry Birds is. 00:05:04.690 --> 00:05:06.850 Obviously we're using a very simple representation. 00:05:06.850 --> 00:05:09.340 It doesn't have a lot of the frill that Angry Birds does. 00:05:09.340 --> 00:05:13.000 But we could easily build upon this and create a fully fleshed out 00:05:13.000 --> 00:05:14.811 game very similar to Angry Birds. 00:05:14.811 --> 00:05:15.560 So thanks, Steven. 00:05:15.560 --> 00:05:17.300 I appreciate the demonstration. 00:05:25.800 --> 00:05:26.880 So that's our goal today. 00:05:26.880 --> 00:05:33.540 We'll be talking about how to construct a very basic but functional simulation 00:05:33.540 --> 00:05:35.610 of what Angry Birds is at its core. 00:05:35.610 --> 00:05:38.760 Which is just flinging things into obstacles, destroying them, 00:05:38.760 --> 00:05:41.820 and ultimately destroying the things that they're protecting, 00:05:41.820 --> 00:05:46.364 the aliens, the pigs that are in the base game. 00:05:46.364 --> 00:05:49.530 So here's a shot of what the different sprite sheets we're going to be using 00:05:49.530 --> 00:05:50.250 are. 00:05:50.250 --> 00:05:53.730 There's a really great sprite sheet that I got off of Open Game Art. 00:05:53.730 --> 00:05:54.690 Kenny is the artist. 00:05:54.690 --> 00:05:56.040 He makes a lot of great art. 00:05:56.040 --> 00:05:58.260 If you notice, it's very similar looking to the art 00:05:58.260 --> 00:06:01.020 that we use in the Mario lecture. 00:06:01.020 --> 00:06:02.520 Actually, it's the same artist. 00:06:02.520 --> 00:06:06.210 So if you're ever looking for assets, he's got a ton of awesome assets 00:06:06.210 --> 00:06:07.200 on open game art. 00:06:07.200 --> 00:06:10.110 So we have a set of aliens, square and round shaped. 00:06:10.110 --> 00:06:14.130 I decided just arbitrarily we made the round shaped aliens the birds. 00:06:14.130 --> 00:06:17.880 So we shoot those into the structures that are 00:06:17.880 --> 00:06:19.380 protecting the square shaped aliens. 00:06:19.380 --> 00:06:23.662 The square shape aliens will be the bad guys in this case. 00:06:23.662 --> 00:06:26.620 And then we have another sprite sheet down here below on the left side. 00:06:26.620 --> 00:06:30.360 Which just, I used the tile here just to make a ground element. 00:06:30.360 --> 00:06:33.510 The rest of these you could easily include in the game if you wanted to, 00:06:33.510 --> 00:06:36.060 but we're only using the ground here. 00:06:36.060 --> 00:06:38.400 And then notice here, we have this large sprite sheet 00:06:38.400 --> 00:06:42.930 which has a bunch of different shapes and sizes of materials. 00:06:42.930 --> 00:06:47.040 The whole sprite sheet comes with metal and explosive and glass sheets as well. 00:06:47.040 --> 00:06:49.500 But just for simplicity we only use the wood here. 00:06:49.500 --> 00:06:53.190 But notice that we have entirely whole pieces 00:06:53.190 --> 00:06:55.470 and then we have pieces that are partially destroyed 00:06:55.470 --> 00:06:57.120 and then pieces that are hollow. 00:06:57.120 --> 00:07:00.540 You could easily model all of these in your game and use them. 00:07:00.540 --> 00:07:04.200 But we only decided to use just a couple of these, 00:07:04.200 --> 00:07:07.020 which was just the horizontal and the vertical ones that 00:07:07.020 --> 00:07:09.630 are completely whole. 00:07:09.630 --> 00:07:14.370 These, unfortunately, don't have quite the same systematic layout 00:07:14.370 --> 00:07:16.170 as the sprites that we used before. 00:07:16.170 --> 00:07:18.820 They're not laid out in a grid evenly spaced. 00:07:18.820 --> 00:07:22.740 So in this case, in util dot Lua, I ended up hard 00:07:22.740 --> 00:07:26.160 coding the different XY width and height quads 00:07:26.160 --> 00:07:29.160 for each of these, which is what you have to do in a situation 00:07:29.160 --> 00:07:31.780 where you're interacting not with tiles per se, 00:07:31.780 --> 00:07:33.960 but with more organic shaped objects. 00:07:33.960 --> 00:07:36.390 So it can take a little more time to end up 00:07:36.390 --> 00:07:39.205 constructing all of the quads for your objects 00:07:39.205 --> 00:07:40.830 when you have a sprite sheet like this. 00:07:40.830 --> 00:07:43.560 But, fortunately, you only have to do it once. 00:07:43.560 --> 00:07:46.890 Here's a few useful links before we get started in talking about what Box2D is 00:07:46.890 --> 00:07:50.190 and how to use it, and basically how it's called love dot 00:07:50.190 --> 00:07:52.670 physics, effectively, in love2D. 00:07:52.670 --> 00:07:56.325 The first two links are documentation for love 2D, 00:07:56.325 --> 00:07:58.950 what the functions and objects are that we'll be talking about. 00:07:58.950 --> 00:08:01.324 And a simple tutorial that talks about how to make a ball 00:08:01.324 --> 00:08:05.070 bounce in love 2D using Box2D. 00:08:05.070 --> 00:08:07.950 The third is a great resource that I used actually 00:08:07.950 --> 00:08:11.250 to learn most of what I know about Box2D, especially 00:08:11.250 --> 00:08:13.984 in the context of this lecture. 00:08:13.984 --> 00:08:15.900 So it talks about a lot of different concepts. 00:08:15.900 --> 00:08:17.290 It talks about all the things that we'll be talking about. 00:08:17.290 --> 00:08:19.710 And then it goes into a lot more detail about how 00:08:19.710 --> 00:08:24.540 you can go about constructing a lot of really cool, crazy things like tanks 00:08:24.540 --> 00:08:27.150 and pulleys and a whole bunch of different things 00:08:27.150 --> 00:08:30.030 that are worth looking into if you're looking into potentially making 00:08:30.030 --> 00:08:31.230 a physics based game. 00:08:31.230 --> 00:08:35.429 Obviously we won't be going into things of that complexity here. 00:08:35.429 --> 00:08:37.169 But you could easily do it with Box2D. 00:08:37.169 --> 00:08:40.350 It makes it very, very possible. 00:08:40.350 --> 00:08:43.620 So the very first thing that we should talk 00:08:43.620 --> 00:08:47.100 about when we want to construct a game, or simulation, 00:08:47.100 --> 00:08:50.490 or whatever we want to do, with Box2D is we 00:08:50.490 --> 00:08:55.320 need some sort of system that will actually perform the simulation for us. 00:08:55.320 --> 00:09:02.670 And the fundamental core of what a Box2D app or game is, the core is the world 00:09:02.670 --> 00:09:03.280 object. 00:09:03.280 --> 00:09:06.780 So there is a world that you can think of as sort of being your world, 00:09:06.780 --> 00:09:12.810 but what it effectively is is a machine that simulates all of the pieces 00:09:12.810 --> 00:09:16.200 that you've told it interact with each other in Box2D. 00:09:16.200 --> 00:09:20.310 So Box2D has a set of objects called fixtures and bodies. 00:09:20.310 --> 00:09:22.820 Those perform the physical interactions. 00:09:22.820 --> 00:09:25.650 And it's up to the world to update all of those 00:09:25.650 --> 00:09:28.680 and apply the relevant forces and physics calculations 00:09:28.680 --> 00:09:32.450 that resolve collisions and do all sorts of things. 00:09:32.450 --> 00:09:35.487 All of the things that Box2D does for us, the world 00:09:35.487 --> 00:09:36.570 takes care of this for us. 00:09:36.570 --> 00:09:40.050 So we don't have to manually go through and update every single object 00:09:40.050 --> 00:09:43.020 with its velocity that we've done before and check for collisions. 00:09:43.020 --> 00:09:45.240 The world does this for us, and resolves them 00:09:45.240 --> 00:09:48.120 based on how we tell it to resolve them. 00:09:48.120 --> 00:09:51.120 And the world also possesses, like an actual world 00:09:51.120 --> 00:09:53.730 would, gravity on the x and y-axis. 00:09:53.730 --> 00:09:57.630 In this case, we have gravity applied on the y-axis going down, 00:09:57.630 --> 00:09:59.820 so it's a positive value. 00:09:59.820 --> 00:10:03.420 We set it to 300 in this distro, but you can set it to whatever you want. 00:10:03.420 --> 00:10:05.610 Setting a lower gravity would have the effect 00:10:05.610 --> 00:10:08.110 of making it feel like we're on the moon or something. 00:10:08.110 --> 00:10:10.110 Making it feel like we're on a different planet. 00:10:10.110 --> 00:10:11.276 So that's what the world is. 00:10:11.276 --> 00:10:12.650 The world simulates everything. 00:10:12.650 --> 00:10:14.400 And we'll go through just a few terms here 00:10:14.400 --> 00:10:15.990 before we look at some source code. 00:10:15.990 --> 00:10:20.250 But there's a few terms that we need to understand before we can really 00:10:20.250 --> 00:10:22.930 understand what Box2D is doing. 00:10:22.930 --> 00:10:26.490 And this is the function that we use to create a new world in love2D. 00:10:26.490 --> 00:10:29.730 Very simple, love dot physics dot new world. 00:10:29.730 --> 00:10:33.510 And this love dot physics is just a name space that 00:10:33.510 --> 00:10:41.410 encapsulates all of the Box2D functions and objects that love2D has access to. 00:10:41.410 --> 00:10:44.220 So anything that you see in love dot physics is effectively 00:10:44.220 --> 00:10:47.100 a wrapper for Box2D. 00:10:47.100 --> 00:10:51.330 And to clarify about Box2D, Box2D is just a library that's written in C++ 00:10:51.330 --> 00:10:54.240 that you can plug-in pretty much anywhere you want to. 00:10:54.240 --> 00:10:58.080 Unity uses it and, actually, most 2D game engines 00:10:58.080 --> 00:11:03.420 that I've ever seen including Live GDX, for example, which is a very large Java 00:11:03.420 --> 00:11:05.880 2D game framework uses Box2D. 00:11:05.880 --> 00:11:07.920 You can use it anywhere. 00:11:07.920 --> 00:11:11.640 In this case we're using love2D's own wrapper for it. 00:11:11.640 --> 00:11:15.270 So the people that created love 2D, they took Box2D 00:11:15.270 --> 00:11:17.490 and then they just put a bunch of Lua functions 00:11:17.490 --> 00:11:19.650 around them, around all the objects and functions 00:11:19.650 --> 00:11:22.620 to make it possible to use it in the same style 00:11:22.620 --> 00:11:24.592 that we use the rest of the framework. 00:11:24.592 --> 00:11:26.050 This is how you create a new world. 00:11:26.050 --> 00:11:29.310 This is the first step in getting your Box2D simulation working. 00:11:29.310 --> 00:11:32.460 So any questions so far as to how we can get that going? 00:11:32.460 --> 00:11:34.050 OK. 00:11:34.050 --> 00:11:39.240 So beyond the world object, which is the foundation, sort of sets up our stage, 00:11:39.240 --> 00:11:42.540 you can think of it as our stage, we need bodies 00:11:42.540 --> 00:11:44.770 to actually interact with each other. 00:11:44.770 --> 00:11:47.880 So a body is just an abstract container. 00:11:47.880 --> 00:11:52.650 It basically holds a position and a velocity. 00:11:52.650 --> 00:11:56.190 And you attach things to it via what are called fixtures 00:11:56.190 --> 00:12:00.612 that allow you to give the body a shape, and therefore a collision box, 00:12:00.612 --> 00:12:02.820 and therefore allow it to interact with other things. 00:12:02.820 --> 00:12:07.590 But a body is essentially all the disparate things in your scene interact 00:12:07.590 --> 00:12:09.510 with each other and move around. 00:12:09.510 --> 00:12:14.160 And so to create a new body we just do love dot physics dot new body. 00:12:14.160 --> 00:12:17.610 We pass in the world, so therefore when we do this, 00:12:17.610 --> 00:12:19.950 the world has a reference to this body now. 00:12:19.950 --> 00:12:22.440 And every time we call update on our world, which 00:12:22.440 --> 00:12:25.230 we'll see in the source code, it will know, OK, 00:12:25.230 --> 00:12:29.280 I have a reference to this body, perform all of the relevant checks 00:12:29.280 --> 00:12:33.660 on the collision for that body and all the fixtures that it contains. 00:12:33.660 --> 00:12:38.770 Update its position, updates velocity, and so forth. 00:12:38.770 --> 00:12:41.700 And not only a world, but it also gets an x and a y, 00:12:41.700 --> 00:12:45.900 which will place it in the world on instantiation. 00:12:45.900 --> 00:12:48.970 The last parameter here, type. 00:12:48.970 --> 00:12:51.330 There are three fundamental types of bodies 00:12:51.330 --> 00:12:56.130 which we'll see in love 2D, static, dynamic, and kinematic. 00:12:56.130 --> 00:12:59.580 And that basically influences how it'll interact with the other objects, 00:12:59.580 --> 00:13:01.810 the other bodies, in our scene. 00:13:01.810 --> 00:13:04.860 So we have the world, which encapsulates everything, 00:13:04.860 --> 00:13:06.900 all the bodies, all the fixtures. 00:13:06.900 --> 00:13:10.380 And then we have the bodies, which are the entities in our game world 00:13:10.380 --> 00:13:14.310 that have position and velocity, effectively. 00:13:14.310 --> 00:13:18.180 The last key ingredient here that will allow 00:13:18.180 --> 00:13:23.820 us to create interactions between the bodies that we have are fixtures. 00:13:23.820 --> 00:13:28.680 And fixtures, all a fixture is, is this abstract object 00:13:28.680 --> 00:13:31.650 that will allow you to attach a shape to a body. 00:13:31.650 --> 00:13:34.740 So bodies are shapeless by default. They don't have a shape. 00:13:34.740 --> 00:13:39.930 They are just a container that has position velocity, effectively. 00:13:39.930 --> 00:13:42.010 But they don't interact with anything else. 00:13:42.010 --> 00:13:44.260 And they don't know how to interact with anything else 00:13:44.260 --> 00:13:46.290 until you give them a fixture. 00:13:46.290 --> 00:13:50.170 And the fixture you will give the body and a shape. 00:13:50.170 --> 00:13:52.860 So for example, if you want the bird that we 00:13:52.860 --> 00:13:56.715 were looking at earlier, the alien, the round alien, we create a body for it 00:13:56.715 --> 00:13:59.880 in our world, which doesn't mean anything yet. 00:13:59.880 --> 00:14:03.810 But we say, I'm going to attach a fixture to that alien. 00:14:03.810 --> 00:14:05.760 I'm going to give it a circle shape. 00:14:05.760 --> 00:14:08.970 And it'll then know whenever it performs any calculations, 00:14:08.970 --> 00:14:13.170 that that alien should interact with things as if it were round. 00:14:13.170 --> 00:14:16.410 And therefore trigger collisions based on a circular hitbox, 00:14:16.410 --> 00:14:21.180 as opposed to a rectangular or polygonal hitbox, as we'll see. 00:14:21.180 --> 00:14:24.390 Fixtures, in addition to attaching shapes 00:14:24.390 --> 00:14:27.300 to bodies, which will, as said here, influence 00:14:27.300 --> 00:14:32.010 how they collide with other bodies, they have density, which we'll see. 00:14:32.010 --> 00:14:34.110 So that things with higher density obviously 00:14:34.110 --> 00:14:38.704 will fall faster, or not fall faster, but they will influence things 00:14:38.704 --> 00:14:39.870 as if they have more weight. 00:14:39.870 --> 00:14:43.660 They will push things farther when they collide with them. 00:14:43.660 --> 00:14:46.110 They also have friction and they have restitution. 00:14:46.110 --> 00:14:48.120 Restitution is bounciness. 00:14:48.120 --> 00:14:51.810 So if something, if we had our alien, no restitution when it hits the ground 00:14:51.810 --> 00:14:53.590 it'll just fall flat. 00:14:53.590 --> 00:14:55.410 But if we give it a higher restitution it 00:14:55.410 --> 00:14:58.080 will actually bounce when it hits the ground. 00:14:58.080 --> 00:15:02.380 And therefore interact with the world a little bit differently. 00:15:02.380 --> 00:15:08.000 So when we want to take a fixture and apply a shape to a body, 00:15:08.000 --> 00:15:09.750 we have a few different shapes that we can 00:15:09.750 --> 00:15:12.930 apply to it that are given to us by default in love 2D. 00:15:12.930 --> 00:15:15.340 So circle shape, rectangle shape, edge shape. 00:15:15.340 --> 00:15:18.520 These are just, effectively, how we define how 00:15:18.520 --> 00:15:20.680 our bodies interact with other bodies. 00:15:20.680 --> 00:15:24.010 How, for example, if it's something that's circular 00:15:24.010 --> 00:15:26.680 it should roll when it's moving along the ground. 00:15:26.680 --> 00:15:29.680 Or when it hits something the corner obviously of it 00:15:29.680 --> 00:15:32.990 won't hit something because it's rounded, as opposed to something 00:15:32.990 --> 00:15:36.670 that has a square hit box, it'll affect things in a slightly different way. 00:15:36.670 --> 00:15:40.840 And we can define arbitrarily shaped hit boxes, thanks to the polygon shape. 00:15:40.840 --> 00:15:45.560 If we want something to be shaped like a pentagon, for example, 00:15:45.560 --> 00:15:47.870 and have it roll around and behave like such, 00:15:47.870 --> 00:15:51.730 we can just define a polygon via a set of vertices. 00:15:51.730 --> 00:15:54.820 And then affix that to a body and it will 00:15:54.820 --> 00:15:57.900 behave as if it were pentagon shaped. 00:15:57.900 --> 00:16:00.280 And this is how you would instantiate just as we've 00:16:00.280 --> 00:16:03.940 seen with love dot physics dot new world and love dot physics dot new body, 00:16:03.940 --> 00:16:07.180 love dot physics dot new fixture takes in a body and a shape, 00:16:07.180 --> 00:16:10.180 and will apply that shape to the body. 00:16:10.180 --> 00:16:14.779 And the world after that will know exactly how to collide with things. 00:16:14.779 --> 00:16:16.570 And so the last thing, the last slide we'll 00:16:16.570 --> 00:16:19.229 look at here before we start looking at source code 00:16:19.229 --> 00:16:20.770 is what the different body types are. 00:16:20.770 --> 00:16:25.600 So I alluded to having three different body types before, static, dynamic, 00:16:25.600 --> 00:16:26.710 and kinematic. 00:16:26.710 --> 00:16:32.080 So a static body will exist in our world but not actually be affected by gravity 00:16:32.080 --> 00:16:34.090 or the collision of anything else. 00:16:34.090 --> 00:16:36.730 Things can hit it and bounce off of it and do their own thing, 00:16:36.730 --> 00:16:39.790 but the static body will never be influenced by something else. 00:16:39.790 --> 00:16:43.817 It exists as some sort of permanent structure, almost like the ground. 00:16:43.817 --> 00:16:46.900 You don't really affect the ground by moving into it and bouncing into it, 00:16:46.900 --> 00:16:49.360 unless you do it with enough force. 00:16:49.360 --> 00:16:55.090 But in our Box2D world, a static body cannot be influenced by anything else. 00:16:55.090 --> 00:16:57.770 A dynamic body is the opposite. 00:16:57.770 --> 00:17:03.310 It has the full simulation of Box2D. 00:17:03.310 --> 00:17:06.790 Gravity affects it, things collide into it, it will bounce off of them. 00:17:06.790 --> 00:17:09.010 It'll do what you would expect a normal body to do. 00:17:09.010 --> 00:17:13.150 If I throw a ball in this room and it hits the wall, it's a dynamic body. 00:17:13.150 --> 00:17:15.940 The walls are the static bodies in this case. 00:17:15.940 --> 00:17:19.720 And then a kinematic body is a hybrid between the two. 00:17:19.720 --> 00:17:24.109 It's something that can move and can rotate and do things, 00:17:24.109 --> 00:17:28.400 but it's not influenced by other objects colliding with it. 00:17:28.400 --> 00:17:32.860 So, for example, if I have a platform that's just spinning indefinitely, 00:17:32.860 --> 00:17:36.940 but it's not being affected by gravity and it doesn't move when I hit it, 00:17:36.940 --> 00:17:38.170 that's a kinematic body. 00:17:38.170 --> 00:17:42.400 It's still moving and it's semi-static and it influences other things, 00:17:42.400 --> 00:17:43.660 but it's not purely static. 00:17:43.660 --> 00:17:47.197 It does have a little bit of behavior that it can grant it. 00:17:47.197 --> 00:17:49.030 So let's go ahead and look at a few examples 00:17:49.030 --> 00:17:53.030 now and see how this actually looks in code. 00:17:53.030 --> 00:17:56.380 So I'm going to go into an example, if you're looking in the distro, 00:17:56.380 --> 00:17:58.600 there is an example called static. 00:17:58.600 --> 00:18:02.227 So we'll take a look here and see what a static body looks like in our scene. 00:18:02.227 --> 00:18:04.560 And for all of these examples leading up to Angry Birds, 00:18:04.560 --> 00:18:08.320 we're just going to render everything with shapes for simplicity. 00:18:08.320 --> 00:18:14.350 But this, as anti-climactic as it is, is a full Box2D world 00:18:14.350 --> 00:18:17.020 with just a single static body. 00:18:17.020 --> 00:18:19.410 And it's just this square here, colored white. 00:18:19.410 --> 00:18:21.620 The static body doesn't move, it doesn't do anything. 00:18:21.620 --> 00:18:25.000 Nothing can influence how it moves or behaves. 00:18:25.000 --> 00:18:27.190 But it exists in our world as a permanent fixture. 00:18:27.190 --> 00:18:30.370 And if we had dynamic bodies and we threw a dynamic body at it, 00:18:30.370 --> 00:18:32.770 for example, the dynamic body would bounce off, 00:18:32.770 --> 00:18:34.872 the static body would stay there permanently. 00:18:34.872 --> 00:18:36.580 So let's go ahead and take a look at what 00:18:36.580 --> 00:18:38.200 the source code looks like for that. 00:18:38.200 --> 00:18:42.820 So I'm here in main dot Lua of our static file. 00:18:42.820 --> 00:18:46.630 And just as we've seen before, we needed to find a world. 00:18:46.630 --> 00:18:49.270 So I have a world here on line 45. 00:18:49.270 --> 00:18:52.960 Love dot physics dot new world, no x-able gravity, 00:18:52.960 --> 00:18:57.910 but we are going to have 300 units of positive gravity on the y-axis, which 00:18:57.910 --> 00:19:01.720 is going from top to bottom. 00:19:01.720 --> 00:19:06.460 We need a body for our square that's in our game world, our static square. 00:19:06.460 --> 00:19:08.800 So we're going to go ahead and define a new body here. 00:19:08.800 --> 00:19:11.251 Love dot physics dot new body takes in the world, 00:19:11.251 --> 00:19:14.500 recall, because that's how our world's going to have a reference to that body, 00:19:14.500 --> 00:19:18.117 doesn't know about it unless we pass it into here, our new body constructor. 00:19:18.117 --> 00:19:20.950 And then I'm just going to put it right in the middle of the screen. 00:19:20.950 --> 00:19:25.030 So virtual width divided by 2 and virtual height divided by 2. 00:19:25.030 --> 00:19:29.020 The difference between Box2D bodies and things 00:19:29.020 --> 00:19:31.270 that we've drawn before or seen before is 00:19:31.270 --> 00:19:34.690 that everything is defined by its center point, as opposed to its top left. 00:19:34.690 --> 00:19:37.150 So I'm able to say virtual width divided by 2 00:19:37.150 --> 00:19:39.270 and virtual height divided by 2 here. 00:19:39.270 --> 00:19:42.790 But I don't actually need to say virtual width divided by 2 minus whatever 00:19:42.790 --> 00:19:44.800 the half of that square is. 00:19:44.800 --> 00:19:50.740 By default, the center point is the XY of that object. 00:19:50.740 --> 00:19:55.600 And this last string here in the constructor for our new body, static, 00:19:55.600 --> 00:19:58.810 tells the constructor that this is going to be a static body specifically, 00:19:58.810 --> 00:20:02.960 not a dynamic body and not a kinematic body. 00:20:02.960 --> 00:20:05.962 So we have a body and it's static, but it doesn't have a shape, 00:20:05.962 --> 00:20:08.920 it doesn't really know how to interact with anything else in our world. 00:20:08.920 --> 00:20:10.270 So we're going to give it a-- 00:20:10.270 --> 00:20:12.340 we're going to create a new shape first. 00:20:12.340 --> 00:20:18.347 So love gives us a few functions in the form of new X shape. 00:20:18.347 --> 00:20:20.930 We have new rectangle shape, new circle shape, new edge shape, 00:20:20.930 --> 00:20:22.620 a few other ones. 00:20:22.620 --> 00:20:26.380 We're just going to create a new rectangle of width and height of 10. 00:20:26.380 --> 00:20:28.420 So that's what the 10 and 10 are here. 00:20:28.420 --> 00:20:31.070 Then we're going to create a new fixture. 00:20:31.070 --> 00:20:37.370 We're going to affix the box shape to our body with this function. 00:20:37.370 --> 00:20:44.420 And then once we do that, all we have to do is then render a polygon with fill 00:20:44.420 --> 00:20:48.950 and then we get the coordinates for our-- or the vertices for our polygon 00:20:48.950 --> 00:20:52.190 by saying, body get world points. 00:20:52.190 --> 00:20:55.940 So that's a function off of any Box2D body 00:20:55.940 --> 00:21:01.400 that will basically get where it is in the world and all of its vertices. 00:21:01.400 --> 00:21:04.730 And then you just pass in the shape that you want to get the points for. 00:21:04.730 --> 00:21:08.300 And that will end up just exploding here into a set of vertices 00:21:08.300 --> 00:21:10.790 that fill up this love dot graphics dot polygon. 00:21:10.790 --> 00:21:17.090 And the end result of that is we get a square. 00:21:17.090 --> 00:21:21.275 And we specifically use polygon instead of love 00:21:21.275 --> 00:21:24.566 dot graphics dot new rectangle because that's what the get 00:21:24.566 --> 00:21:26.690 world points function explodes out to. 00:21:26.690 --> 00:21:32.150 It doesn't explode out to the number of arguments that would satisfy 00:21:32.150 --> 00:21:35.040 love dot graphics dot rectangle. 00:21:35.040 --> 00:21:37.460 So not a very exciting example. 00:21:37.460 --> 00:21:43.110 But this is basically the foundation of a full Box2D application. 00:21:43.110 --> 00:21:46.411 So any questions as to how this works at all? 00:21:46.411 --> 00:21:47.036 AUDIENCE: Yeah. 00:21:47.036 --> 00:21:48.032 I'm wondering. 00:21:48.032 --> 00:21:52.514 How does it determine the center of a abnormal shape? 00:21:52.514 --> 00:21:54.804 Not like a polygon, square, rectangle, or circle. 00:21:54.804 --> 00:21:56.720 COLTON OGDEN: The center of an abnormal shape. 00:21:56.720 --> 00:21:57.710 I'm not entirely sure. 00:21:57.710 --> 00:22:00.774 The circle is just-- 00:22:00.774 --> 00:22:01.680 AUDIENCE: [INAUDIBLE] 00:22:01.680 --> 00:22:02.471 COLTON OGDEN: Yeah. 00:22:02.471 --> 00:22:04.790 I'm not entirely sure about a polygon though. 00:22:04.790 --> 00:22:06.790 I haven't looked into that into too much detail. 00:22:06.790 --> 00:22:08.040 I can explore that and see. 00:22:08.040 --> 00:22:11.320 That's something that I think Box2D is-- 00:22:11.320 --> 00:22:14.300 the actual library implements that and calculates that. 00:22:14.300 --> 00:22:18.029 Probably based upon calculating the area of-- 00:22:18.029 --> 00:22:20.570 and to repeat for the camera if I didn't repeat already, it's 00:22:20.570 --> 00:22:25.340 how does Box2D calculate the center point of something non-symmetrical, 00:22:25.340 --> 00:22:27.860 like a polygon? 00:22:27.860 --> 00:22:33.230 And best I can understand is that it would do an area calculation off of it 00:22:33.230 --> 00:22:38.567 and figure out where all the vertices tend towards, I guess. 00:22:38.567 --> 00:22:41.150 But, yeah, that's something that's implemented in the library. 00:22:41.150 --> 00:22:42.170 I'm not entirely sure. 00:22:42.170 --> 00:22:46.469 I can look into it and see and then I'll post in the Slack. 00:22:46.469 --> 00:22:48.718 AUDIENCE: It seems like [INAUDIBLE] you did have that, 00:22:48.718 --> 00:22:52.940 it would be difficult to place in a very precise spot. 00:22:52.940 --> 00:22:55.010 COLTON OGDEN: Yeah. 00:22:55.010 --> 00:22:56.810 If it were-- yeah. 00:22:56.810 --> 00:23:00.220 If we did have an odd shape to get it placed in a exact spot. 00:23:00.220 --> 00:23:01.440 Yeah, I'm not entirely sure. 00:23:01.440 --> 00:23:04.450 I'd have to explore that a little bit. 00:23:04.450 --> 00:23:05.450 Interesting idea though. 00:23:07.980 --> 00:23:13.444 But, yeah, that's essentially how we get a Box2D world up and running. 00:23:13.444 --> 00:23:14.360 We have a static body. 00:23:14.360 --> 00:23:16.580 It's not terribly interesting. 00:23:16.580 --> 00:23:19.130 But with one change-- 00:23:19.130 --> 00:23:23.150 so I have a separate example called dynamic in the source code distro. 00:23:23.150 --> 00:23:26.760 But all we need to do to really see the difference 00:23:26.760 --> 00:23:32.360 between a static and dynamic body is on line 48, just change static to dynamic, 00:23:32.360 --> 00:23:35.660 save it, and then rerun it. 00:23:35.660 --> 00:23:38.300 And then we'll immediately see that it's affected by gravity 00:23:38.300 --> 00:23:41.930 and it moves downwards as we've told the world that our gravity is 00:23:41.930 --> 00:23:43.880 set to positive 300. 00:23:43.880 --> 00:23:47.000 And so that behaves how we would expect it to. 00:23:47.000 --> 00:23:50.730 Now, there's nothing else in the scene so it's not particularly interesting. 00:23:50.730 --> 00:23:55.220 So I've created a another example called ground. 00:23:55.220 --> 00:23:58.110 So let's go ahead and look at that. 00:24:02.970 --> 00:24:09.408 So if we want more interesting behavior, what do we need to do in a nutshell? 00:24:09.408 --> 00:24:11.719 AUDIENCE: Have more shapes and make a ground. 00:24:11.719 --> 00:24:13.760 COLTON OGDEN: Some more shapes and make a ground. 00:24:13.760 --> 00:24:14.600 Exactly. 00:24:14.600 --> 00:24:17.330 That's a simple way we can start to get instantly 00:24:17.330 --> 00:24:19.490 a sense of how powerful Box2D is. 00:24:19.490 --> 00:24:22.940 Just introduce more shapes that interact with each other in different ways. 00:24:22.940 --> 00:24:28.540 So ground is an example that just introduces a ground into our scene, 00:24:28.540 --> 00:24:33.590 so that we can see the box fall down and actually collide with something else. 00:24:33.590 --> 00:24:36.480 And Love2D makes this nice and easy. 00:24:36.480 --> 00:24:37.190 Excuse me. 00:24:37.190 --> 00:24:40.640 They have a actual edge shape that will allow us 00:24:40.640 --> 00:24:44.150 to basically form where the ground is. 00:24:44.150 --> 00:24:48.710 Anything that collides with this-- it's effectively a line. 00:24:48.710 --> 00:24:52.430 But no matter how fast anything moves in are scene, 00:24:52.430 --> 00:24:56.690 the body will not move past that line. 00:24:56.690 --> 00:25:00.100 So it's a nice, easy way of getting a ground in our scene 00:25:00.100 --> 00:25:03.560 without having to implement a polygon that maybe has two vertices going 00:25:03.560 --> 00:25:05.387 left to right on the screen. 00:25:05.387 --> 00:25:06.470 So that's what we do here. 00:25:06.470 --> 00:25:11.720 We have a ground body, which is a static body, recall. 00:25:11.720 --> 00:25:14.150 Because the ground shouldn't move. 00:25:14.150 --> 00:25:18.101 We're going to change the box into a dynamic body, 00:25:18.101 --> 00:25:19.350 but the ground shouldn't move. 00:25:19.350 --> 00:25:21.183 The ground should be unaffected by anything. 00:25:21.183 --> 00:25:23.210 It's going to be static in our scene. 00:25:23.210 --> 00:25:25.400 And it's going to have an edge shape. 00:25:25.400 --> 00:25:28.850 So notice here, we take 0, 0 as the XY. 00:25:28.850 --> 00:25:31.220 And then a virtual width is zero. 00:25:31.220 --> 00:25:35.510 So with shapes, when we define them here, 00:25:35.510 --> 00:25:39.690 it's not going to draw the shape at 0, 0, at virtual width in 0. 00:25:39.690 --> 00:25:42.680 This is relative to wherever the body is located. 00:25:42.680 --> 00:25:45.350 So wherever our body is, this shape will be 00:25:45.350 --> 00:25:49.460 drawn with these coordinates, this X and Y and this width and height, 00:25:49.460 --> 00:25:50.930 relative to that. 00:25:50.930 --> 00:25:56.130 And specifically, relative to the center point of wherever we place a body. 00:25:56.130 --> 00:26:01.440 So if this ground is set to 0, 0 at virtual width and zero, 00:26:01.440 --> 00:26:03.440 where do we need to place the actual body for it 00:26:03.440 --> 00:26:08.125 to render the ground appropriately? 00:26:08.125 --> 00:26:09.829 AUDIENCE: The middle bottom. 00:26:09.829 --> 00:26:12.370 COLTON OGDEN: Yeah, so we place it towards the middle bottom. 00:26:12.370 --> 00:26:18.670 So we actually end up placing the body itself here at virtual height minus 30. 00:26:18.670 --> 00:26:21.850 And when we affix this edge shape to the body, we'll end up, 00:26:21.850 --> 00:26:24.280 even though it says 0, 0 virtual width zero, 00:26:24.280 --> 00:26:27.070 it's relative to wherever the body's XY are. 00:26:27.070 --> 00:26:31.210 So it's actually going to be 0 virtual height minus 30, 00:26:31.210 --> 00:26:35.800 virtual width zero will be where that edge exists. 00:26:35.800 --> 00:26:37.990 And then lastly, just as we did with our box, 00:26:37.990 --> 00:26:41.980 we need a ground fixture so that the ground body knows how 00:26:41.980 --> 00:26:43.820 it should interact with other things. 00:26:43.820 --> 00:26:47.350 So we're going to affix the edge shape, which is just a line, 00:26:47.350 --> 00:26:49.870 to our ground body. 00:26:49.870 --> 00:26:53.410 And then here we do love dot graphics-- just 00:26:53.410 --> 00:26:58.030 as we did with the love dot graphics dot polygon for our box, 00:26:58.030 --> 00:27:00.931 we're going to do love dot graphics dot line for our ground body. 00:27:00.931 --> 00:27:03.430 And we're going to do the exact same thing, get world points 00:27:03.430 --> 00:27:06.510 and get points passing the edge shape here. 00:27:06.510 --> 00:27:09.850 And I'm also setting a line width of 2 just 00:27:09.850 --> 00:27:11.920 so we can see it a little bit better. 00:27:11.920 --> 00:27:13.580 And I'm going to color it red. 00:27:13.580 --> 00:27:17.770 Again, I colored the box up here green. 00:27:17.770 --> 00:27:20.570 So go ahead take a look at what this looks like. 00:27:20.570 --> 00:27:24.280 So I'm going to go into ground. 00:27:27.120 --> 00:27:30.460 And so notice-- and I also added a little bit of restitution 00:27:30.460 --> 00:27:33.910 to the-- as I said before, restitution is a quality that a fixture can 00:27:33.910 --> 00:27:35.890 have which gives it bounciness. 00:27:35.890 --> 00:27:38.350 So rather than just falling flat down onto the ground, 00:27:38.350 --> 00:27:39.740 it bounces a little bit as well. 00:27:39.740 --> 00:27:42.323 And we can see the interaction, so I'll play it one more time. 00:27:42.323 --> 00:27:43.630 It starts in the middle. 00:27:43.630 --> 00:27:46.600 And then as soon as it hits the ground body 00:27:46.600 --> 00:27:49.840 that we created before, the edge shape, it bounces a couple of times. 00:27:49.840 --> 00:27:54.580 But it shows that the box is dynamic, but the ground is static. 00:27:54.580 --> 00:27:57.040 Nothing influences the position of the ground. 00:27:57.040 --> 00:28:01.900 It gets hard set and will stay there permanently. 00:28:01.900 --> 00:28:05.260 So that shows a nice, easy simple demonstration 00:28:05.260 --> 00:28:09.820 of an interaction between a static and a dynamic body. 00:28:09.820 --> 00:28:13.250 I'm going to go ahead and pull up another example here. 00:28:13.250 --> 00:28:18.460 So kinematic, recall, what was the difference between a kinematic 00:28:18.460 --> 00:28:21.298 and a static or dynamic body? 00:28:21.298 --> 00:28:23.798 AUDIENCE: Kinematic can move but not influence other shapes. 00:28:23.798 --> 00:28:24.714 COLTON OGDEN: Correct. 00:28:24.714 --> 00:28:26.030 So a kinematic body can move. 00:28:26.030 --> 00:28:31.000 You can ascribe it positional velocity or angular velocity, it's rotation. 00:28:31.000 --> 00:28:35.290 But when something collides with it, it's not going to be influenced by it. 00:28:35.290 --> 00:28:38.530 It's going to influence the body that it collides with. 00:28:38.530 --> 00:28:40.780 It's going to affect it in some way, but nothing 00:28:40.780 --> 00:28:42.700 colliding with the kinematic body is going 00:28:42.700 --> 00:28:45.790 to have an effect on its position or its velocity. 00:28:45.790 --> 00:28:48.970 It's something that exists and does something programmed 00:28:48.970 --> 00:28:50.920 and will just do that indefinitely, but it 00:28:50.920 --> 00:28:55.260 will interact with other dynamic bodies as we have programmed. 00:28:55.260 --> 00:28:57.760 And it will not interact with other kinematic bodies either. 00:28:57.760 --> 00:29:00.280 They will almost pretend that each other doesn't exist. 00:29:00.280 --> 00:29:03.785 If you overlap a static and a kinematic body or kinematic and a kinematic body, 00:29:03.785 --> 00:29:06.160 they render on top of each other, but they don't actually 00:29:06.160 --> 00:29:09.470 influence each other's position or anything like that. 00:29:09.470 --> 00:29:13.695 So I'm going to go ahead and run the kinematic example. 00:29:19.550 --> 00:29:23.780 So here we have a few things going on. 00:29:23.780 --> 00:29:27.410 We have the box body that we had before, the dynamic box that 00:29:27.410 --> 00:29:29.520 falls from the middle of the screen. 00:29:29.520 --> 00:29:31.700 We have the ground on the very bottom to catch it. 00:29:31.700 --> 00:29:35.240 But we have three kinematic boxes in the very center that 00:29:35.240 --> 00:29:39.440 are spinning that influence the green box 00:29:39.440 --> 00:29:41.700 when the green box collides with them. 00:29:41.700 --> 00:29:44.510 So as you can see, it tosses it around and then 00:29:44.510 --> 00:29:46.610 the green body falls back to the bottom. 00:29:46.610 --> 00:29:49.070 And in this example I've taken away its restitution. 00:29:49.070 --> 00:29:53.300 So as soon as it hits the ground, it just falls flat. 00:29:53.300 --> 00:29:54.870 Just like that. 00:29:54.870 --> 00:29:57.330 And so, as you can see, these blue bodies, they're moving. 00:29:57.330 --> 00:30:00.830 They have angular velocity indefinitely. 00:30:00.830 --> 00:30:04.940 Specifically 360 degrees per second. 00:30:04.940 --> 00:30:09.080 And they will stay in that exact position and rotate in that exact way 00:30:09.080 --> 00:30:10.080 forever. 00:30:10.080 --> 00:30:13.370 But as soon as they interact with a dynamic body, 00:30:13.370 --> 00:30:16.670 they actually cause a collision with that dynamic body. 00:30:16.670 --> 00:30:19.550 And the collision resolves and this green body 00:30:19.550 --> 00:30:21.710 gets tossed around because it's dynamic. 00:30:21.710 --> 00:30:27.350 It will basically do whatever it can to interact with the game world 00:30:27.350 --> 00:30:30.590 as long as it's interacting with other bodies 00:30:30.590 --> 00:30:32.270 and resolving its collision that way. 00:30:34.800 --> 00:30:39.860 And so that's the key example between what the three different bodies are 00:30:39.860 --> 00:30:40.580 fundamentally. 00:30:40.580 --> 00:30:45.182 And with these three body types you can construct pretty much any scene 00:30:45.182 --> 00:30:45.890 that you want to. 00:30:45.890 --> 00:30:50.180 And obviously the bodies and the fixtures can get insanely complex. 00:30:50.180 --> 00:30:55.010 I mean, we can look back here at this first example. 00:30:55.010 --> 00:31:05.780 These structures are a composition of many different types of dynamic bodies 00:31:05.780 --> 00:31:11.330 that have been given anchors and joints and all sorts of other things 00:31:11.330 --> 00:31:15.170 to make them look as if they're big constructions. 00:31:15.170 --> 00:31:18.370 But at the end, they're all just a bunch of little bodies 00:31:18.370 --> 00:31:20.870 that are welded together, fixtures that are welded together. 00:31:23.480 --> 00:31:27.710 And these fundamental building blocks are how you construct scenes like this. 00:31:27.710 --> 00:31:32.210 Put a bunch of these blocks together, weld them together with joints, 00:31:32.210 --> 00:31:33.050 in this case. 00:31:33.050 --> 00:31:35.840 We won't cover joints in the context of this lecture. 00:31:35.840 --> 00:31:39.290 But if you're wondering how all of these individual things 00:31:39.290 --> 00:31:44.729 can be collideable while still constructing these massive scenes 00:31:44.729 --> 00:31:46.520 and having physics applied to them, they're 00:31:46.520 --> 00:31:51.140 just jointed together using weld joints or other types of joints, pulley joints 00:31:51.140 --> 00:31:52.640 depending on what they are. 00:31:52.640 --> 00:31:58.760 In this case, there is two circle shapes here, circle fixtures, 00:31:58.760 --> 00:32:01.190 that are the wheels on this cart and then 00:32:01.190 --> 00:32:06.740 they're welded to the flat constructions here. 00:32:06.740 --> 00:32:09.980 Allowing those to be dynamic allows the wheels to roll, and therefore 00:32:09.980 --> 00:32:12.650 carry the other load with it. 00:32:12.650 --> 00:32:14.390 Same with this bridge. 00:32:14.390 --> 00:32:18.710 I forget the exact name of the joint, but it's a chain of fixtures together 00:32:18.710 --> 00:32:20.720 that are welded by a specific kind of joint. 00:32:20.720 --> 00:32:23.090 And by putting them together in this way, 00:32:23.090 --> 00:32:27.740 you get a bridge and all sorts of things that you could think of, 00:32:27.740 --> 00:32:33.830 including tanks, which is in the notes here. 00:32:33.830 --> 00:32:36.080 This third link, one of them talks about how 00:32:36.080 --> 00:32:37.970 to implement a tank by having treads going 00:32:37.970 --> 00:32:40.580 around circles and then a massive body. 00:32:40.580 --> 00:32:45.156 You could do anything with Box2D, it's an awesome library. 00:32:45.156 --> 00:32:47.030 In the context of Angry Birds, really we just 00:32:47.030 --> 00:32:49.400 scratched the surface for what is possible here. 00:32:52.470 --> 00:32:54.590 So I'm going to demo now. 00:32:54.590 --> 00:32:59.480 Actually, I enjoyed, I think, this demo, this bit of code, 00:32:59.480 --> 00:33:03.410 more than I enjoyed the Angry Birds implementation. 00:33:03.410 --> 00:33:06.400 And it's a program that I wrote called Ball Pit. 00:33:06.400 --> 00:33:08.160 Oh, by the way, before I get into that. 00:33:08.160 --> 00:33:11.840 So I'll leave that as a little teaser, I guess. 00:33:11.840 --> 00:33:15.440 Looking at kinematic, really quickly. 00:33:15.440 --> 00:33:18.590 We're going to look and see that I've created 00:33:18.590 --> 00:33:23.450 a table for the kinematic bodies, a table for the fixtures, 00:33:23.450 --> 00:33:24.802 and then one shape. 00:33:24.802 --> 00:33:26.510 Because you only need one shape actually, 00:33:26.510 --> 00:33:28.400 and you can apply one shape to as many bodies 00:33:28.400 --> 00:33:32.960 as you want to as long as they all have the same shape. 00:33:32.960 --> 00:33:35.690 I just create three kinematic bodies here. 00:33:35.690 --> 00:33:39.590 So spacing them out relative to the center with this math here. 00:33:39.590 --> 00:33:41.019 They get the string kinematic. 00:33:41.019 --> 00:33:42.560 And that's really the key difference. 00:33:42.560 --> 00:33:45.830 And then before finishing, I make sure that I 00:33:45.830 --> 00:33:47.920 set them to have an angular velocity. 00:33:47.920 --> 00:33:49.400 So this is how you spin something. 00:33:49.400 --> 00:33:51.483 If you want to set something to spin indefinitely, 00:33:51.483 --> 00:33:52.730 just set an angular velocity. 00:33:52.730 --> 00:33:56.540 In this case, 360 times degrees to radians. 00:33:56.540 --> 00:34:01.880 And that's just a formula written out as a constant, which is just the number-- 00:34:01.880 --> 00:34:05.942 I forget offhand what exactly the formula is. 00:34:05.942 --> 00:34:06.650 But it's up here. 00:34:06.650 --> 00:34:13.070 It's degrees to radians 0.01745329, et cetera. 00:34:13.070 --> 00:34:15.949 But just like pi, it's a number that you can 00:34:15.949 --> 00:34:19.540 use to multiply a number in degrees, and you'll get a number in radians. 00:34:19.540 --> 00:34:22.120 And there's the reverse up there as well. 00:34:22.120 --> 00:34:26.949 We have to do this because Box2D expects, for any types of rotation, 00:34:26.949 --> 00:34:28.239 it expects it in radians. 00:34:28.239 --> 00:34:30.050 I prefer thinking in degrees. 00:34:30.050 --> 00:34:33.370 So I passed in 360 times degrees to radians. 00:34:33.370 --> 00:34:37.340 And so we render down here, just as we did with the box body. 00:34:37.340 --> 00:34:42.790 We render the kinematic bodies, polygon fill, kinematic bodies at i 00:34:42.790 --> 00:34:45.639 get world points kinematic shape get points. 00:34:45.639 --> 00:34:47.179 Nothing terribly different. 00:34:47.179 --> 00:34:50.949 The only real key difference is that we've added kinematic as a string 00:34:50.949 --> 00:34:53.659 to the constructor for the body. 00:34:53.659 --> 00:34:55.810 And we've added some angular velocity. 00:34:55.810 --> 00:34:58.082 And recall, this will make it spin indefinitely, 00:34:58.082 --> 00:35:00.790 but it will never be influenced-- its angular velocity will never 00:35:00.790 --> 00:35:03.850 be influenced, its position will never be influenced 00:35:03.850 --> 00:35:06.310 by anything else in our scene. 00:35:06.310 --> 00:35:10.060 So now with that out of the way, I'm going to pull up Ball Pit. 00:35:13.170 --> 00:35:15.590 And maybe I'm just a little bit too excited about this. 00:35:15.590 --> 00:35:18.160 But I enjoyed this a lot. 00:35:18.160 --> 00:35:22.300 So what it is, is this is like a bigger demonstration 00:35:22.300 --> 00:35:24.680 of putting all these pieces together. 00:35:24.680 --> 00:35:26.994 We have a bunch of circle shapes. 00:35:26.994 --> 00:35:28.660 They're all interacting with each other. 00:35:28.660 --> 00:35:29.770 They all have physics. 00:35:29.770 --> 00:35:33.190 And then I have a larger shape here, this square, 00:35:33.190 --> 00:35:35.510 which has a higher density than everything else. 00:35:35.510 --> 00:35:38.660 And by pressing Spacebar I can just dive into-- 00:35:38.660 --> 00:35:41.440 throw it into the ball pit, and it'll cause an interaction 00:35:41.440 --> 00:35:42.670 with everything else. 00:35:42.670 --> 00:35:46.780 And a bug slash feature that I discovered 00:35:46.780 --> 00:35:51.070 about this is that if you press Spacebar over and over again, 00:35:51.070 --> 00:35:53.510 it never resets its velocity. 00:35:53.510 --> 00:35:55.854 So it just slams down into the ball pit. 00:35:55.854 --> 00:35:58.270 So it's just kind of fun, and I think there might actually 00:35:58.270 --> 00:36:00.580 be possibly a game idea in here. 00:36:00.580 --> 00:36:02.710 But, I mean, well, what are the pieces here? 00:36:02.710 --> 00:36:04.000 What's different about this? 00:36:07.388 --> 00:36:10.949 AUDIENCE: They're all dynamic shapes. 00:36:10.949 --> 00:36:11.740 COLTON OGDEN: Yeah. 00:36:11.740 --> 00:36:13.490 So they're all dynamic shapes. 00:36:13.490 --> 00:36:15.410 Except for the ground at the very bottom. 00:36:15.410 --> 00:36:21.994 And also, hidden from view are actually two more static shapes 00:36:21.994 --> 00:36:22.910 on the left and right. 00:36:22.910 --> 00:36:25.160 Because if we didn't have those, all of the balls 00:36:25.160 --> 00:36:28.520 would fall to the side out of view. 00:36:28.520 --> 00:36:33.020 But yeah, we have the static delimiters for our scene. 00:36:33.020 --> 00:36:38.420 But we have a bunch of dynamic bodies, the balls are all dynamic. 00:36:38.420 --> 00:36:42.470 And then the square is also dynamic. 00:36:42.470 --> 00:36:45.387 And then, like I said before, the only real difference between them 00:36:45.387 --> 00:36:47.220 is that obviously the square is a rectangle. 00:36:47.220 --> 00:36:49.200 But it also just has a higher density. 00:36:49.200 --> 00:36:53.027 And so by giving it a higher density it pushes everything else-- oh, 00:36:53.027 --> 00:36:53.860 what happened there? 00:36:53.860 --> 00:36:54.485 That was weird. 00:36:54.485 --> 00:36:57.410 It pushes-- I think it went to sleep because we didn't do anything 00:36:57.410 --> 00:36:57.980 for a while. 00:36:57.980 --> 00:37:01.550 But it's able to fall through everything else 00:37:01.550 --> 00:37:05.960 because it knows that it's heavier, and that it should push and apply 00:37:05.960 --> 00:37:09.800 a larger force to everything else that's around it. 00:37:09.800 --> 00:37:14.030 And so by using these fundamental building blocks of what Box2D is, 00:37:14.030 --> 00:37:18.320 you can construct a lot of really cool simulations and other fun programs 00:37:18.320 --> 00:37:20.840 and actually get interesting game ideas. 00:37:20.840 --> 00:37:25.010 I'm inclined to believe that Angry Birds started out as somebody messing around 00:37:25.010 --> 00:37:27.780 with the Box2D, or physics engine like this. 00:37:27.780 --> 00:37:31.430 And it was inspired by some other game that I should look into a little bit. 00:37:31.430 --> 00:37:34.837 But the creators of that game, presumably, found this physics engine 00:37:34.837 --> 00:37:36.170 and were like, oh, this is cool. 00:37:36.170 --> 00:37:39.650 I'm going to put a tower of blocks here and just throw something at it. 00:37:39.650 --> 00:37:42.130 And then they realized, oh, we can make a game out of this. 00:37:42.130 --> 00:37:46.890 And so I encourage you, if you're ever curious to just experiment with things 00:37:46.890 --> 00:37:47.390 like that. 00:37:47.390 --> 00:37:49.040 We could probably turn this into a game. 00:37:49.040 --> 00:37:49.581 I don't know. 00:37:49.581 --> 00:37:50.480 I like this a lot. 00:37:50.480 --> 00:38:00.050 It's a good segue from the abstract, for lack of a better word, examples 00:38:00.050 --> 00:38:05.030 that we used earlier, and merges it more into the realm 00:38:05.030 --> 00:38:09.230 of how can we make something fun with this? 00:38:09.230 --> 00:38:14.570 And so that's how we're going to start moving into the distro today. 00:38:14.570 --> 00:38:21.320 So the main topic of today's lecture is Box2D and how we use it to make a game. 00:38:21.320 --> 00:38:23.780 Another thing that we should consider is mouse input. 00:38:23.780 --> 00:38:25.480 We haven't really used it yet. 00:38:25.480 --> 00:38:29.450 And I believe I've mentioned it before, slightly offhand. 00:38:29.450 --> 00:38:31.060 But Love2D makes it super easy. 00:38:31.060 --> 00:38:33.761 It's just like we do with keyboard input. 00:38:33.761 --> 00:38:36.260 We just have a couple of callbacks that are in main dot Lua, 00:38:36.260 --> 00:38:38.390 mouse pressed and mouse released. 00:38:38.390 --> 00:38:41.705 The difference between these and key pressed and key 00:38:41.705 --> 00:38:45.500 released is that they also get an X and a Y. Because usually, 00:38:45.500 --> 00:38:47.420 when you click the mouse or release the mouse, 00:38:47.420 --> 00:38:49.461 you want to know where it happened because that's 00:38:49.461 --> 00:38:53.250 obviously pertinent to what you're doing when you're using a mouse. 00:38:53.250 --> 00:38:58.940 So these are fired by Love2D every time you click or release a mouse button. 00:38:58.940 --> 00:39:01.670 And they get the X the Y and the key, and you 00:39:01.670 --> 00:39:03.350 can do whatever you want with those. 00:39:03.350 --> 00:39:05.900 And just as we've done in prior lectures so 00:39:05.900 --> 00:39:10.220 that we can use mouse input in other modules besides main dot Lua, 00:39:10.220 --> 00:39:13.505 there's a function called love dot mouse dot key pressed and key 00:39:13.505 --> 00:39:15.341 released that I implemented in main dot Lua. 00:39:15.341 --> 00:39:16.340 You can check those out. 00:39:16.340 --> 00:39:20.540 They're very similar to how we did the input tables for the keyboard before. 00:39:20.540 --> 00:39:24.020 But they allow us to use this functionality inside 00:39:24.020 --> 00:39:30.350 of other functions, other modules, besides main dot Lua. 00:39:30.350 --> 00:39:35.180 So let's go ahead and start looking at-- 00:39:35.180 --> 00:39:42.140 this is where we're going to start looking at the distro for Angry Birds 00:39:42.140 --> 00:39:46.489 and how we can take all these pieces and form them into an actual game. 00:39:46.489 --> 00:39:49.530 So the first thing we'll do, we'll take a look at just a couple of things 00:39:49.530 --> 00:39:51.530 and then we'll take a short break and then we'll 00:39:51.530 --> 00:39:53.150 get more into the meat of it. 00:39:53.150 --> 00:39:55.820 But let me go ahead and clear out all of these. 00:39:58.800 --> 00:40:02.460 And then we're going to pull up-- so the distro is in Angry 50. 00:40:02.460 --> 00:40:06.270 And so main dot Lua is here. 00:40:06.270 --> 00:40:08.280 So not a whole lot is different in here. 00:40:08.280 --> 00:40:11.700 So we have two states in our game. 00:40:11.700 --> 00:40:14.490 So we had a start and a play state, as we saw before. 00:40:14.490 --> 00:40:16.810 The start state is like we've done before. 00:40:16.810 --> 00:40:20.070 The only difference is in this start state, well, for one, 00:40:20.070 --> 00:40:22.020 it's running a Box2D simulation. 00:40:22.020 --> 00:40:25.800 And two, we're actually using mouse input. 00:40:25.800 --> 00:40:27.780 So actually, let's look at main so you can 00:40:27.780 --> 00:40:31.540 see where I've added this, which is different than before. 00:40:31.540 --> 00:40:35.310 So we have love dot key pressed, as we've seen before. 00:40:35.310 --> 00:40:38.520 But we also have mouse pressed and mouse released. 00:40:38.520 --> 00:40:40.660 And then mouse was pressed and mouse was released. 00:40:40.660 --> 00:40:44.340 So those are the main differences in main dot Lua this time, as opposed 00:40:44.340 --> 00:40:49.020 to last prior lectures, which we only had keyboard input. 00:40:49.020 --> 00:40:53.490 And as you can see here, we have input tables for keys pressed and released 00:40:53.490 --> 00:40:54.570 on the mouse. 00:40:54.570 --> 00:40:57.870 And so we initialized those to empty on every update frame 00:40:57.870 --> 00:41:00.840 just like we've done with the keyboard. 00:41:00.840 --> 00:41:05.820 And then the input tables get updated in the callback functions 00:41:05.820 --> 00:41:07.517 as we've done before. 00:41:07.517 --> 00:41:10.600 And so that's basically all that's different about main dot Lua this time. 00:41:10.600 --> 00:41:15.540 And that's how we've tied together the new mouse functions that we've just 00:41:15.540 --> 00:41:17.040 looked at into our game. 00:41:19.830 --> 00:41:24.270 The states that exist in our game are play state and start state. 00:41:24.270 --> 00:41:25.110 So very simple. 00:41:25.110 --> 00:41:27.480 Very similar to last week where we looked at Zelda, 00:41:27.480 --> 00:41:31.470 we only basically had a start state and a play state. 00:41:31.470 --> 00:41:37.860 The start state, we can see here, just to tie together 00:41:37.860 --> 00:41:41.160 the last bit of our usage of the mouse. 00:41:41.160 --> 00:41:43.920 Love dot mouse dot was pressed 1. 00:41:43.920 --> 00:41:46.695 Does anybody know what this 1 is? 00:41:46.695 --> 00:41:48.120 AUDIENCE: Is that left click? 00:41:48.120 --> 00:41:49.411 COLTON OGDEN: It is left click. 00:41:49.411 --> 00:41:53.850 So Love2D assigns integer values to all of your mouse buttons. 00:41:53.850 --> 00:41:58.230 And 1 is traditionally the default value for left click. 00:41:58.230 --> 00:42:00.420 Some frameworks will use 0. 00:42:00.420 --> 00:42:06.300 But Lua, 1 index so start with 1 instead of 0. 00:42:06.300 --> 00:42:10.810 The thing about the start state here that's kind of cool and interesting. 00:42:10.810 --> 00:42:18.030 So I'm going to go ahead and play it again, the game. 00:42:18.030 --> 00:42:21.440 So we start off and right off the gate, just to make things interesting 00:42:21.440 --> 00:42:23.940 rather than just have a static screen that says 00:42:23.940 --> 00:42:28.050 Anger 50 click to start, we're actually running a Love2D, 00:42:28.050 --> 00:42:30.790 a Box2D simulation here. 00:42:30.790 --> 00:42:33.720 It's a world with a bunch of squares. 00:42:33.720 --> 00:42:37.812 And so what kind of bodies are all of these? 00:42:37.812 --> 00:42:38.810 AUDIENCE: [INAUDIBLE]. 00:42:38.810 --> 00:42:40.518 COLTON OGDEN: They're all dynamic bodies. 00:42:40.518 --> 00:42:44.210 And we've encapsulated them all, just as we did before in the ball pit example, 00:42:44.210 --> 00:42:47.895 with some invisible static bodies on the left, right, and bottom of the screen. 00:42:47.895 --> 00:42:49.770 Because if we didn't have those static bodies 00:42:49.770 --> 00:42:52.980 they would just fall all the way down. 00:42:52.980 --> 00:42:56.100 And the nice thing is we don't actually have to render anything. 00:42:56.100 --> 00:43:01.850 So if you want maybe an invisible barrier for something in your game, 00:43:01.850 --> 00:43:04.364 or you want to encapsulate something, something physical, 00:43:04.364 --> 00:43:05.780 you don't have to render anything. 00:43:05.780 --> 00:43:10.160 You can just have arbitrarily shaped and positioned static bodies. 00:43:10.160 --> 00:43:11.977 And that will act as a container. 00:43:11.977 --> 00:43:13.310 So that's all we're doing there. 00:43:13.310 --> 00:43:17.960 We have a container set for all of our little square alien guys. 00:43:17.960 --> 00:43:22.580 And by creating, I think, a hundred of them and just letting them drop, 00:43:22.580 --> 00:43:27.140 we have this interesting visual start to our game 00:43:27.140 --> 00:43:29.310 with very, very minimal effort. 00:43:29.310 --> 00:43:31.340 So we can take a look at this. 00:43:31.340 --> 00:43:36.260 So in our start state init, as I said before, we have a world. 00:43:36.260 --> 00:43:38.570 We obviously need a member of new world. 00:43:38.570 --> 00:43:40.670 Anytime we do any Box2D stuff you have to start 00:43:40.670 --> 00:43:43.185 by having a love dot physics dot new world, 00:43:43.185 --> 00:43:46.730 else you won't be able to run any simulations. 00:43:46.730 --> 00:43:51.740 Going to create a ground, walls, and then a bunch of aliens. 00:43:51.740 --> 00:43:57.630 So this here, we can see that we have a table that we're inserting aliens into. 00:43:57.630 --> 00:44:00.980 But we have a class called alien. 00:44:00.980 --> 00:44:04.520 So anybody want to ballpark what an alien class ultimately 00:44:04.520 --> 00:44:05.930 encapsulates or ultimately is? 00:44:10.421 --> 00:44:15.694 AUDIENCE: Probably the way it looks, like the skin. 00:44:15.694 --> 00:44:18.110 COLTON OGDEN: It is, yeah, that's definitely a part of it. 00:44:18.110 --> 00:44:19.880 So the way it looks, or it's skin. 00:44:19.880 --> 00:44:23.210 So it does have a reference to that. 00:44:23.210 --> 00:44:31.970 And then more functionally, it also possesses a body and a fixture. 00:44:31.970 --> 00:44:35.000 So rather than having a bunch of bodies and fixtures 00:44:35.000 --> 00:44:38.780 that are separated out and maybe just in tables 00:44:38.780 --> 00:44:44.240 at the surface level of whatever, our level, just wrap them in a class. 00:44:44.240 --> 00:44:46.370 And then we just can maintain a reference 00:44:46.370 --> 00:44:50.630 to each individual alien's body and fixture that way. 00:44:50.630 --> 00:44:53.240 So it's a little bit more encapsulated. 00:44:53.240 --> 00:44:57.500 It's a little bit more object oriented, little bit cleaner in my opinion. 00:44:57.500 --> 00:45:03.230 The alien class can take square or round as its-- 00:45:03.230 --> 00:45:05.900 well, it can take anything you want to as its type. 00:45:05.900 --> 00:45:09.290 So this will ultimately decide how it's rendered and what shape it gets. 00:45:09.290 --> 00:45:13.670 But if it's square, which is the default, so if you just 00:45:13.670 --> 00:45:18.020 create an alien with no type, it will get 00:45:18.020 --> 00:45:21.350 a love dot physics dot rectangle shape. 00:45:21.350 --> 00:45:23.720 So as we saw before, that's just a box. 00:45:23.720 --> 00:45:26.510 And then if not, we just default to circle shape. 00:45:26.510 --> 00:45:29.450 But you could program it to take in whatever shape you want, 00:45:29.450 --> 00:45:30.980 and then just give it that shape. 00:45:30.980 --> 00:45:33.230 And you don't really have to do much in terms 00:45:33.230 --> 00:45:36.890 of coding how it interacts with anything else in terms of collision, at least. 00:45:36.890 --> 00:45:40.220 Because, thankfully, Box2D will know, OK, it's a circle. 00:45:40.220 --> 00:45:43.790 It should spin around and interact with things like a circle. 00:45:43.790 --> 00:45:47.090 Or it's a rectangle so it should interact with things like it's a box. 00:45:47.090 --> 00:45:48.680 Just nice and convenient. 00:45:48.680 --> 00:45:52.070 And then we'll just create a fixture here. 00:45:52.070 --> 00:45:55.860 This set user data function here is important 00:45:55.860 --> 00:46:01.850 because we'll see in the context of how we actually resolve collisions 00:46:01.850 --> 00:46:05.300 in a customized way, we'll need user data 00:46:05.300 --> 00:46:08.840 to be able to differentiate what gets collided in our world. 00:46:08.840 --> 00:46:14.900 But at the moment you can just know that this basically allows us to pass in-- 00:46:14.900 --> 00:46:17.720 to set arbitrary data onto a fixture. 00:46:17.720 --> 00:46:22.850 So we can say, fixture set user data alien, the string alien. 00:46:22.850 --> 00:46:28.520 And what that means is that fixture has some customized metadata about it that 00:46:28.520 --> 00:46:30.290 says, this is an alien. 00:46:30.290 --> 00:46:31.892 It's whatever we want to do with it. 00:46:31.892 --> 00:46:33.350 We could give this a table as well. 00:46:33.350 --> 00:46:35.570 We could just say, the user data is a table 00:46:35.570 --> 00:46:40.190 and then has a bunch of information that we can then use at collision time 00:46:40.190 --> 00:46:42.050 to perform different work on it. 00:46:42.050 --> 00:46:44.210 But this set user data function is how we 00:46:44.210 --> 00:46:48.900 are able to resolve collisions between obstacles and aliens differently than, 00:46:48.900 --> 00:46:53.460 say players and aliens, or even the alien and the ground. 00:46:53.460 --> 00:46:57.110 Because when we do any Box2D collision, right, the world's 00:46:57.110 --> 00:46:59.150 taking care of the collisions for us. 00:46:59.150 --> 00:47:04.460 How do we tell the world, OK, when I hit the ground I want to play a sound, 00:47:04.460 --> 00:47:05.810 but not do anything. 00:47:05.810 --> 00:47:10.130 If I hit this box at this velocity, I want it to destroy it. 00:47:10.130 --> 00:47:12.860 If I hit the alien, I want the alien to disappear 00:47:12.860 --> 00:47:16.280 and I want to show a victory label. 00:47:16.280 --> 00:47:18.890 How do we do all these different things? 00:47:18.890 --> 00:47:21.770 We do that with what are called collision callbacks 00:47:21.770 --> 00:47:23.400 in the context of Box2D. 00:47:23.400 --> 00:47:24.720 And we'll see how that works. 00:47:24.720 --> 00:47:30.870 But suffice to say, user data will be very important coming forward. 00:47:30.870 --> 00:47:33.350 And then this launched false, actually we don't end up 00:47:33.350 --> 00:47:34.910 using this so this is irrelevant. 00:47:34.910 --> 00:47:43.190 But it has a render function here, which just takes in the bodies X and Y 00:47:43.190 --> 00:47:46.242 and will draw it at the angle that it's at. 00:47:46.242 --> 00:47:47.450 So that's an important thing. 00:47:47.450 --> 00:47:52.400 When we before, what we were doing is drawing things via shapes. 00:47:52.400 --> 00:47:55.790 So love dot graphics dot polygon, love dot graphics dot circle, 00:47:55.790 --> 00:47:57.710 love dot graphics dot line. 00:47:57.710 --> 00:48:03.440 But if we want to draw a sprite instead, we 00:48:03.440 --> 00:48:06.440 need to draw it at the right position, first of all, right? 00:48:06.440 --> 00:48:09.890 And then things also rotate in Box2D. 00:48:09.890 --> 00:48:13.500 So we need to draw it at the right angle. 00:48:13.500 --> 00:48:17.270 So what we do is we can actually query the body for its X. 00:48:17.270 --> 00:48:21.770 We can query the body for its Y. And we can also query the body for its angle. 00:48:21.770 --> 00:48:24.560 And then we can draw the texture and the quad 00:48:24.560 --> 00:48:28.470 that we want to using those XY and the angle, 00:48:28.470 --> 00:48:33.560 and that will have the effect of drawing a sprite in the world that 00:48:33.560 --> 00:48:37.190 mirrors what's going on in Box2D, rather than just a simple shape. 00:48:37.190 --> 00:48:42.260 So that's as simple as it is for drawing a sprite instead of a shape. 00:48:42.260 --> 00:48:46.230 You can see here, the 17.5 17.5. 00:48:46.230 --> 00:48:48.404 Does anybody know what that's for? 00:48:48.404 --> 00:48:49.240 AUDIENCE: Not sure. 00:48:49.240 --> 00:48:52.940 COLTON OGDEN: So 17.5 17.5 at the end is half of the width 00:48:52.940 --> 00:48:56.030 and half of the height of the aliens. 00:48:56.030 --> 00:48:58.670 So aliens are 35 by 35 in this game. 00:48:58.670 --> 00:49:00.050 We pass those in. 00:49:00.050 --> 00:49:02.450 This is the center of origin. 00:49:02.450 --> 00:49:05.600 So when we rotate something by center of origin, 00:49:05.600 --> 00:49:11.620 it basically describes where the rotation is going to take place. 00:49:11.620 --> 00:49:15.237 So if it's rotated about the top left and we rotate something, 00:49:15.237 --> 00:49:17.570 it's going to have the effect of the sprite going around 00:49:17.570 --> 00:49:20.150 in a circle in sort of an odd way. 00:49:20.150 --> 00:49:23.960 If we rotate the sprite based on the center of origin of the actual sprite 00:49:23.960 --> 00:49:28.760 itself, that will have the effect of rotating the sprite on its center. 00:49:28.760 --> 00:49:31.520 So you can set that origin wherever you want to 00:49:31.520 --> 00:49:35.180 and it'll perform a 360 degree rotation about that point. 00:49:35.180 --> 00:49:37.590 And we're setting that point to half-- 00:49:37.590 --> 00:49:40.040 to basically the middle of where we're drawing the sprite. 00:49:40.040 --> 00:49:42.720 So that will have the effect of when we give it this angle here, 00:49:42.720 --> 00:49:46.880 self dot body to get angle, the rotation will take place in place. 00:49:46.880 --> 00:49:50.570 It won't take place-- it won't be some sort of weird about the top left corner 00:49:50.570 --> 00:49:52.770 rotation, which is not what we want. 00:49:52.770 --> 00:49:55.840 So when you see center of origin being modified like that, 00:49:55.840 --> 00:49:58.610 you can assume that it's because we have an offset 00:49:58.610 --> 00:50:01.550 and we're trying to find the center of where we're drawing 00:50:01.550 --> 00:50:04.980 and rotate about that to do an in place rotation. 00:50:04.980 --> 00:50:08.720 But not necessarily, you could also draw something. 00:50:08.720 --> 00:50:12.800 You could also, maybe you want something some sort of magical ball of energy 00:50:12.800 --> 00:50:15.230 to rotate about a rod or something. 00:50:15.230 --> 00:50:17.780 And so you want it to rotate around a different center, 00:50:17.780 --> 00:50:20.660 or whatever you want arbitrarily. 00:50:20.660 --> 00:50:23.840 But typically, at least mostly that I've seen, 00:50:23.840 --> 00:50:27.950 this is useful for making sure that your rotations, your in place rotations, 00:50:27.950 --> 00:50:29.360 are accurately rendered. 00:50:29.360 --> 00:50:33.320 So any questions about how the alien class works? 00:50:36.860 --> 00:50:38.340 All right. 00:50:38.340 --> 00:50:40.650 So that's the alien class. 00:50:40.650 --> 00:50:44.160 That's the basically the fundamental building block of our game. 00:50:44.160 --> 00:50:48.120 The other part is the obstacle. 00:50:48.120 --> 00:50:50.280 We have obstacles and we have aliens. 00:50:50.280 --> 00:50:53.610 The obstacles and aliens are actually very similar. 00:50:53.610 --> 00:50:55.560 So what's the difference between-- 00:50:55.560 --> 00:50:58.080 I mean, ultimately, how are they similar? 00:51:03.470 --> 00:51:05.430 AUDIENCE: They're both dynamic [INAUDIBLE].. 00:51:05.430 --> 00:51:07.580 COLTON OGDEN: They're both dynamic bodies, yeah. 00:51:07.580 --> 00:51:11.720 Really, the only thing that's different about a obstacle and an alien 00:51:11.720 --> 00:51:14.570 is what we do with them in our scene and how they're rendered. 00:51:14.570 --> 00:51:16.760 But they function very similarly. 00:51:16.760 --> 00:51:18.950 They're just dynamic bodies that we give a shape to 00:51:18.950 --> 00:51:21.200 and we render them with that shape. 00:51:24.680 --> 00:51:28.670 In this case, the obstacle constructor, we've 00:51:28.670 --> 00:51:33.540 decided to design it such that it could take a shape horizontal or vertical, 00:51:33.540 --> 00:51:36.620 which is similar to the type that we saw before with the alien, 00:51:36.620 --> 00:51:38.840 where it could be square or circular. 00:51:38.840 --> 00:51:45.860 In this case, if we look back at our sprite sheet back here, 00:51:45.860 --> 00:51:48.124 we can see there's a ton of different shapes. 00:51:48.124 --> 00:51:51.290 But the only two shapes that we're going to use in the context of this game, 00:51:51.290 --> 00:51:55.970 just for this demonstration, are the horizontal, clean wooden shape here 00:51:55.970 --> 00:51:59.150 and the vertical one that's right here. 00:51:59.150 --> 00:52:02.120 And so in order to find those out I had to open up 00:52:02.120 --> 00:52:05.567 basically this sprite in my sprite editor, 00:52:05.567 --> 00:52:08.150 figure out where the XY width and height were, and then create 00:52:08.150 --> 00:52:10.340 a quad manually off of that. 00:52:10.340 --> 00:52:14.120 And then I edited the util dot Lua-- or not util dot Lua, 00:52:14.120 --> 00:52:17.480 the dependencies dot Lua here. 00:52:17.480 --> 00:52:21.050 Normally we just create gframes and then we use generate quads. 00:52:21.050 --> 00:52:25.460 And you can do that like with the aliens and with the tiles, the tiles 00:52:25.460 --> 00:52:28.190 being this sprite sheet that-- 00:52:28.190 --> 00:52:29.510 this one right here. 00:52:29.510 --> 00:52:31.310 These are 35 by 35. 00:52:31.310 --> 00:52:32.720 These are 35 by 35. 00:52:32.720 --> 00:52:34.130 These are not 35 by 35. 00:52:34.130 --> 00:52:38.280 These are a bunch of different shapes and sizes. 00:52:38.280 --> 00:52:47.840 So I went through and gframes wood is for manually created quads here. 00:52:47.840 --> 00:52:53.540 And then there's four because I also added the semi broken shapes as well. 00:52:53.540 --> 00:52:55.820 But we don't actually use those. 00:52:55.820 --> 00:53:03.100 But you could decide to turn these into these on collision, 00:53:03.100 --> 00:53:06.350 perhaps maybe if the velocity isn't strong enough to break it necessarily, 00:53:06.350 --> 00:53:09.740 but you want to have some sort of feedback that you collided with it. 00:53:09.740 --> 00:53:15.140 You can just set maybe the frame to 1 or 2 on collision for that object, 00:53:15.140 --> 00:53:18.950 instead of 2 and render it appropriately. 00:53:18.950 --> 00:53:21.380 But if you're dealing with a sprite sheet 00:53:21.380 --> 00:53:26.450 and that sprite sheet has odd distribution of its sprites, 00:53:26.450 --> 00:53:29.480 sometimes you have to figure out where the offsets are manually 00:53:29.480 --> 00:53:31.190 and do it that way. 00:53:31.190 --> 00:53:34.910 The ideal is that you don't have to and that you can do it programmatically. 00:53:34.910 --> 00:53:38.270 But it really depends on the game, what your domain is 00:53:38.270 --> 00:53:42.090 and what objects you're interacting with in the scene. 00:53:42.090 --> 00:53:44.950 Any questions on the why or how as to that? 00:53:47.700 --> 00:53:48.320 Cool. 00:53:48.320 --> 00:53:51.780 So back to the obstacle. 00:53:51.780 --> 00:53:54.020 So they're horizontal or vertical, and what that does 00:53:54.020 --> 00:53:55.730 is it sets the frame to 2 or 4. 00:53:55.730 --> 00:54:02.180 And the 2 or 4 being in gframes that would, the 4 quads that I had a hand, 00:54:02.180 --> 00:54:03.620 figure out the coordinates for. 00:54:06.350 --> 00:54:09.800 And really, it's not a whole lot different at that point. 00:54:09.800 --> 00:54:15.260 If it's a horizontal or a vertical shape, 00:54:15.260 --> 00:54:17.690 then we need to set its width and height appropriately. 00:54:17.690 --> 00:54:19.820 Because it's going to have a different width and a different height. 00:54:19.820 --> 00:54:22.770 If it's vertical, obviously the height is higher than the width. 00:54:22.770 --> 00:54:25.910 And if it's horizontal, the opposite is true. 00:54:25.910 --> 00:54:27.929 But they're both a rectangle shape. 00:54:27.929 --> 00:54:29.720 So you can pass in the width and the height 00:54:29.720 --> 00:54:32.520 after you calculate that, and give it the right shape, 00:54:32.520 --> 00:54:33.770 and then ascribe it a fixture. 00:54:33.770 --> 00:54:37.310 And then set user data in this case, we set user data to obstacle. 00:54:37.310 --> 00:54:40.760 So now that obstacle, the fixture specifically, 00:54:40.760 --> 00:54:45.080 knows that it's an obstacle, as opposed to being an alien, as opposed 00:54:45.080 --> 00:54:47.510 to being anything else, as opposed to being the ground. 00:54:47.510 --> 00:54:54.500 And so when we explore in a few minutes what the custom collision, world 00:54:54.500 --> 00:54:56.420 collision callbacks, that we can actually 00:54:56.420 --> 00:54:58.940 define all this interesting collision behavior for, 00:54:58.940 --> 00:55:01.370 this user data is going to be relevant. 00:55:01.370 --> 00:55:08.310 And then we render it just like we render the alien as before. 00:55:08.310 --> 00:55:10.875 So any questions on obstacles and aliens, how they differ, 00:55:10.875 --> 00:55:11.750 how they're the same? 00:55:14.588 --> 00:55:15.750 Cool. 00:55:15.750 --> 00:55:16.250 All right. 00:55:16.250 --> 00:55:18.500 Let's take a five minute now. 00:55:18.500 --> 00:55:21.710 When we get back, we're going to actually look at the play state. 00:55:21.710 --> 00:55:23.870 We're going to look at what makes a level. 00:55:23.870 --> 00:55:27.650 And we're going to actually look at how we can customize the world 00:55:27.650 --> 00:55:32.480 to resolve collisions in ways that are relevant to our game behavior. 00:55:32.480 --> 00:55:36.080 As in, how to make things break when we collide with them, 00:55:36.080 --> 00:55:40.310 how to make the victory screen pop up when we've destroyed the bird, 00:55:40.310 --> 00:55:41.240 so on and so forth. 00:55:43.971 --> 00:55:44.470 All right. 00:55:44.470 --> 00:55:45.250 Welcome back. 00:55:45.250 --> 00:55:47.110 So before we took a break, we were talking 00:55:47.110 --> 00:55:51.120 about the aliens and obstacles that are in our game 00:55:51.120 --> 00:55:52.880 world that interact with each other. 00:55:52.880 --> 00:55:58.900 They are the backbone of what makes our games slash Angry Birds work. 00:55:58.900 --> 00:56:02.170 You throw aliens into the obstacles, obstacles break, 00:56:02.170 --> 00:56:07.660 the bad pigs slash aliens die and then you score points. 00:56:07.660 --> 00:56:10.120 But we actually have to model these interactions 00:56:10.120 --> 00:56:13.030 and we have to tell our game, our world, what 00:56:13.030 --> 00:56:16.900 to do when these collisions happen in order for things more interesting 00:56:16.900 --> 00:56:19.354 than just things bouncing off each other to work. 00:56:19.354 --> 00:56:20.520 That's the default behavior. 00:56:20.520 --> 00:56:26.230 Box2D's goal, by default, is when two things overlap, 00:56:26.230 --> 00:56:29.170 assuming that they're dynamic or at least one of them is dynamic, 00:56:29.170 --> 00:56:34.840 is to push the dynamic bodies away until they no longer overlap 00:56:34.840 --> 00:56:38.950 via either position or rotation. 00:56:38.950 --> 00:56:42.640 But that's not the gist or the goal of our game. 00:56:42.640 --> 00:56:45.490 Because what we want to have happen is different things happen 00:56:45.490 --> 00:56:49.330 and certain things to disappear and to break and all sorts of other things 00:56:49.330 --> 00:56:52.210 to happen when different kinds of objects 00:56:52.210 --> 00:56:56.290 interact with different kinds of objects at differing speeds. 00:56:56.290 --> 00:57:00.790 So in order to do this, we need to define collision callbacks 00:57:00.790 --> 00:57:01.630 for our world. 00:57:01.630 --> 00:57:04.810 So a callback, recall, is a function that gets 00:57:04.810 --> 00:57:06.850 called back when something happens. 00:57:06.850 --> 00:57:12.950 It's just something that will get called at a specific time or later on. 00:57:12.950 --> 00:57:16.090 And we can define these callbacks for our world 00:57:16.090 --> 00:57:19.210 such that when two things collide with each other, 00:57:19.210 --> 00:57:23.350 it will execute this call back and then perform the corresponding logic 00:57:23.350 --> 00:57:25.750 that we've defined therein. 00:57:25.750 --> 00:57:30.850 And with every collision in Box2D, there are four callbacks that take place. 00:57:30.850 --> 00:57:35.770 There's begin contact, so when two things begin to overlap 00:57:35.770 --> 00:57:37.630 or begin to contact one another. 00:57:37.630 --> 00:57:40.480 End contact, so once that ends, once two objects 00:57:40.480 --> 00:57:42.990 are pushed away from each other. 00:57:42.990 --> 00:57:46.270 Presolved, which happens right before the collision actually gets 00:57:46.270 --> 00:57:50.200 solved in Box2D, meaning that the things get pushed away from each other. 00:57:50.200 --> 00:57:54.130 And then postsolved, meaning right after they get pushed away from each other. 00:57:54.130 --> 00:57:58.040 And the postsolved in particular is interesting 00:57:58.040 --> 00:58:02.540 because it gets the information about how the collision needed to resolve. 00:58:02.540 --> 00:58:08.650 So how much velocity or rotation needed to happen within that interaction. 00:58:08.650 --> 00:58:12.340 And we will not be using end contact, presolve, or postsolve. 00:58:12.340 --> 00:58:15.370 We will only be using begin contact because, really, that's 00:58:15.370 --> 00:58:18.612 all we need in order to model the behavior that we're looking for. 00:58:18.612 --> 00:58:20.320 Because anything that happens in our game 00:58:20.320 --> 00:58:23.170 we can just figure it out as soon as two objects touch each other. 00:58:25.730 --> 00:58:28.600 And these are things, if you're interested in a tutorial that 00:58:28.600 --> 00:58:31.420 goes over these in perhaps a little bit more detail, 00:58:31.420 --> 00:58:33.520 there's a link here in the slides. 00:58:33.520 --> 00:58:38.470 But I'll show you how to actually implement these callbacks yourself. 00:58:38.470 --> 00:58:42.040 You do this via a function called world set callbacks, 00:58:42.040 --> 00:58:45.110 in this case, F1, F2, F3, F4. 00:58:45.110 --> 00:58:47.770 And recall, because Lua is a dynamic language where functions 00:58:47.770 --> 00:58:52.210 are first class objects, you can pass in functions as arguments 00:58:52.210 --> 00:58:53.300 to other functions. 00:58:53.300 --> 00:58:54.260 And that's what we're doing here. 00:58:54.260 --> 00:58:56.218 So this is assuming that we have four functions 00:58:56.218 --> 00:59:00.820 we've defined called begin contact, end contact. presolve, or postsolve. 00:59:00.820 --> 00:59:03.250 Their actual names don't matter at all. 00:59:03.250 --> 00:59:05.881 These are just the de facto names for them. 00:59:05.881 --> 00:59:09.130 What matters is that you have the logic there and you pass in function objects 00:59:09.130 --> 00:59:11.170 that perform something. 00:59:11.170 --> 00:59:15.130 And you can pass in all empty functions and Box2D will still behave as normal. 00:59:15.130 --> 00:59:20.680 These are only for when you want more complicated behavior out of your game 00:59:20.680 --> 00:59:23.320 than just things bouncing off of each other 00:59:23.320 --> 00:59:26.200 and moving relative to one another. 00:59:26.200 --> 00:59:29.620 So does that make sense? 00:59:29.620 --> 00:59:32.020 So we'll see how this actually works. 00:59:32.020 --> 00:59:34.390 We're going to go ahead and open up level dot Lua. 00:59:34.390 --> 00:59:37.090 So level dot Lua is a container class that 00:59:37.090 --> 00:59:40.120 basically has our game level in it, including 00:59:40.120 --> 00:59:42.430 the world and all the entities. 00:59:42.430 --> 00:59:47.391 And we update it and are able to model, effectively, 00:59:47.391 --> 00:59:48.640 like a level from Angry Birds. 00:59:48.640 --> 00:59:50.080 That's really what it is. 00:59:50.080 --> 00:59:51.220 It has a world. 00:59:51.220 --> 00:59:55.720 So the level has its own world with 300 positive Y gravity, as we saw before. 00:59:55.720 --> 00:59:58.630 It has a table called destroyed bodies. 00:59:58.630 --> 01:00:01.160 And we'll see that in a second. 01:00:01.160 --> 01:00:02.710 And then here we have four functions. 01:00:02.710 --> 01:00:06.730 Starting on line 22, we have begin contact, which is a long function. 01:00:06.730 --> 01:00:09.510 And then we have end contact, presolve, and postsolve. 01:00:09.510 --> 01:00:11.590 Those are the four callback functions that I 01:00:11.590 --> 01:00:14.659 alluded to just a few seconds ago. 01:00:14.659 --> 01:00:16.450 They take in slightly different signatures. 01:00:16.450 --> 01:00:19.150 The first three take A, B, and collision. 01:00:19.150 --> 01:00:23.260 And then the last one takes in A, B, collision, and then a normal impulse 01:00:23.260 --> 01:00:26.680 and a tangent impulse, which are the forces that it needed to apply in order 01:00:26.680 --> 01:00:29.620 to push apart the two objects. 01:00:29.620 --> 01:00:31.840 Like I said, we won't be using these three functions. 01:00:31.840 --> 01:00:36.550 But there might be a situation where you need to use those functions. 01:00:36.550 --> 01:00:40.330 Maybe you want end contact because, in your game, two objects attached 01:00:40.330 --> 01:00:43.640 to one another, when they collide maybe they're magnetic or something, 01:00:43.640 --> 01:00:46.550 and then once they pull apart maybe you want a particle effect 01:00:46.550 --> 01:00:50.690 or something to show that they've separated or something. 01:00:50.690 --> 01:00:52.310 And then presolve and postsolve. 01:00:52.310 --> 01:00:54.980 Presolve, offhand I can't think of a use case, 01:00:54.980 --> 01:00:59.360 but postsolve could be useful for, depending on your game, 01:00:59.360 --> 01:01:03.552 whether you need to just figure out maybe the amount of force 01:01:03.552 --> 01:01:04.760 that they needed to separate. 01:01:04.760 --> 01:01:11.540 Maybe you multiply that by some amount and cause some sort of dramatic effect. 01:01:11.540 --> 01:01:14.120 Those are ultimately dependent on the domain of your game. 01:01:14.120 --> 01:01:16.120 The important function that we'll be using today 01:01:16.120 --> 01:01:18.830 is the first one, begin contact. 01:01:18.830 --> 01:01:21.050 And notice, that we've defined these four functions, 01:01:21.050 --> 01:01:23.460 even if these three are just empty. 01:01:23.460 --> 01:01:27.080 But we pass in, as I said before, the set callbacks 01:01:27.080 --> 01:01:29.510 function takes in those four functions. 01:01:29.510 --> 01:01:33.410 And notice another interesting thing, because of Lua's dynamic nature, line 01:01:33.410 --> 01:01:35.330 11 you can see that we have level init, which 01:01:35.330 --> 01:01:37.820 is the constructor for our level class. 01:01:37.820 --> 01:01:41.060 Within the constructor we are defining more functions. 01:01:41.060 --> 01:01:45.020 You can define functions as many layers deep as you want to. 01:01:45.020 --> 01:01:47.690 And you can even return functions from functions, which 01:01:47.690 --> 01:01:50.959 are called higher order functions. 01:01:50.959 --> 01:01:52.250 Really do whatever you want to. 01:01:52.250 --> 01:01:55.730 In this case we're just defining the collision callbacks here inside 01:01:55.730 --> 01:01:56.321 of our init. 01:01:56.321 --> 01:01:58.320 But you could put the most anywhere you want to. 01:01:58.320 --> 01:02:01.370 You can have them outside of the class, you can have them wherever you want. 01:02:01.370 --> 01:02:03.828 You can have them be global functions in your main dot Lua, 01:02:03.828 --> 01:02:05.660 which I don't know how I feel about that. 01:02:05.660 --> 01:02:08.930 But you can do whatever you want to as long as the functions exist 01:02:08.930 --> 01:02:11.180 and you can reference their symbols, you can pass them 01:02:11.180 --> 01:02:14.540 into self dot world set callbacks. 01:02:14.540 --> 01:02:19.490 And now, whenever a collision happens in the world period, 01:02:19.490 --> 01:02:22.640 it's going to call all four of those functions 01:02:22.640 --> 01:02:26.040 at each stage of each collision. 01:02:26.040 --> 01:02:29.960 So you could see that potentially getting a little bit 01:02:29.960 --> 01:02:33.810 hairy if you were to scale high enough with all of your logic. 01:02:33.810 --> 01:02:36.100 If you had a million lines of code in each of these 01:02:36.100 --> 01:02:38.796 and its executing million lines of code per collision, 01:02:38.796 --> 01:02:39.920 you could run into trouble. 01:02:39.920 --> 01:02:43.910 But, fortunately, we're not going anywhere near that. 01:02:43.910 --> 01:02:49.100 The gist of begin contact, so it takes in an A and a B and a collision. 01:02:49.100 --> 01:02:53.100 We don't end up using the collision itself, we just use the A and the B 01:02:53.100 --> 01:02:56.060 because that's all we need for our game world. 01:02:56.060 --> 01:02:58.868 The A and the B are what? 01:02:58.868 --> 01:03:00.368 Do we know what the A and the B are? 01:03:00.368 --> 01:03:02.000 AUDIENCE: Probably the two objects [INAUDIBLE].. 01:03:02.000 --> 01:03:02.810 COLTON OGDEN: The two objects. 01:03:02.810 --> 01:03:04.685 Do you know whether it's a body or a fixture? 01:03:08.749 --> 01:03:10.040 AUDIENCE: It would the fixture. 01:03:10.040 --> 01:03:11.623 COLTON OGDEN: It would be the fixture. 01:03:11.623 --> 01:03:14.640 The fixtures collide with each other, not the bodies. 01:03:14.640 --> 01:03:18.420 So when you have a body, recall that the fixture attaches the shape to a body. 01:03:18.420 --> 01:03:22.830 The body is just a position and velocity container for a bunch of fixtures, 01:03:22.830 --> 01:03:24.150 the body is. 01:03:24.150 --> 01:03:27.810 Each individual fixture collides with other things, 01:03:27.810 --> 01:03:30.150 other fixtures in your game world. 01:03:30.150 --> 01:03:33.700 And so, recall that before we had fixture 01:03:33.700 --> 01:03:36.480 set user data because that's what we ended up 01:03:36.480 --> 01:03:39.720 needing to have data on when we do the collisions. 01:03:39.720 --> 01:03:43.650 We check to see via get user data what something is 01:03:43.650 --> 01:03:46.230 or what metadata we've given to that fixture. 01:03:46.230 --> 01:03:51.690 And then we can then separate different classes of objects this way. 01:03:51.690 --> 01:03:55.630 We can say, oh, this object was an alien, or this object was an obstacle, 01:03:55.630 --> 01:03:56.880 or this object was the ground. 01:03:56.880 --> 01:03:59.129 And then we can say, oh, did we collide with an alien? 01:03:59.129 --> 01:04:01.830 Was the collision between an alien and the ground? 01:04:01.830 --> 01:04:04.620 If it was, OK, let's play a bounce sound effect. 01:04:04.620 --> 01:04:07.230 And if it was between an alien and the other alien, the player 01:04:07.230 --> 01:04:10.170 and the other alien, and the velocity was fast enough, 01:04:10.170 --> 01:04:11.820 OK, the alien should die. 01:04:11.820 --> 01:04:12.420 Right? 01:04:12.420 --> 01:04:15.810 We can do arbitrary things. 01:04:15.810 --> 01:04:19.320 And so the way that I've programmed it here such that we 01:04:19.320 --> 01:04:21.870 can see what two things interacted with each other, 01:04:21.870 --> 01:04:26.280 and this is a very simple use of user data. 01:04:26.280 --> 01:04:31.020 All we we're doing in this code base is just assigning strings to fixtures, 01:04:31.020 --> 01:04:34.770 but you could assign tables to fixtures with arbitrary amounts of data 01:04:34.770 --> 01:04:36.780 and do all sorts of things. 01:04:36.780 --> 01:04:39.120 In this case, we're only using strings. 01:04:39.120 --> 01:04:42.960 So I create a table, an empty table, and then I just 01:04:42.960 --> 01:04:47.490 assign at table, at that string, true. 01:04:47.490 --> 01:04:49.360 And then I can just query that table. 01:04:49.360 --> 01:04:52.200 Do I have a key player and a key alien? 01:04:52.200 --> 01:04:56.324 Do I have a key obstacle and a key obstacle? 01:04:56.324 --> 01:04:58.740 This is how you can figure out what your two objects were. 01:04:58.740 --> 01:05:02.242 Because A could be a player and B can be an obstacle. 01:05:02.242 --> 01:05:04.200 A can be an obstacle and B could be the player. 01:05:04.200 --> 01:05:08.050 So you have to take both of that into consideration. 01:05:08.050 --> 01:05:12.990 So it allows us to do if types obstacle and types player, so 01:05:12.990 --> 01:05:20.370 a collision between the player and an obstacle, if it's fast enough, then we 01:05:20.370 --> 01:05:22.750 can destroy the obstacle. 01:05:22.750 --> 01:05:23.880 This is what we do here. 01:05:23.880 --> 01:05:29.760 So I take the absolute value of the velocity on the X and Y. 01:05:29.760 --> 01:05:33.790 So I do vel X vel Y gets the body's linear velocity. 01:05:33.790 --> 01:05:37.220 So linear velocity is just where it's moving in the world. 01:05:37.220 --> 01:05:42.360 And it returns two values because velocity has an X and Y component. 01:05:42.360 --> 01:05:48.810 And then we sum it here by taking its absolute value of both parts 01:05:48.810 --> 01:05:50.230 and adding it together. 01:05:50.230 --> 01:05:54.450 So if it's moving fast on the x-axis, but not fast on the y-axis, 01:05:54.450 --> 01:05:57.420 or if it's not moving fast on either, or if it's moving fast on both, 01:05:57.420 --> 01:06:02.220 we have a sense, in general, what's the average velocity of our object. 01:06:02.220 --> 01:06:04.620 If it's moving fast on any of the axes, we 01:06:04.620 --> 01:06:08.580 can assume that that's sufficient force to cause an object 01:06:08.580 --> 01:06:10.500 to get destroyed, right? 01:06:10.500 --> 01:06:14.250 So we do if the velocity is greater than 20, just an arbitrary value 01:06:14.250 --> 01:06:16.680 that I came up with that seemed appropriate, 01:06:16.680 --> 01:06:19.370 then we're going to do this. 01:06:19.370 --> 01:06:24.280 Table dot insert self dot destroyed bodies, which we saw earlier. 01:06:24.280 --> 01:06:25.860 And then the obstacles body. 01:06:25.860 --> 01:06:30.030 Now, why are we inserting that value here as 01:06:30.030 --> 01:06:33.968 opposed to, maybe just destroying it inside this function? 01:06:38.155 --> 01:06:39.530 AUDIENCE: Destroying the fixture. 01:06:39.530 --> 01:06:41.080 COLTON OGDEN: Destroying the body. 01:06:41.080 --> 01:06:43.490 The fixture, yeah, in this case. 01:06:43.490 --> 01:06:45.110 AUDIENCE: I mean the fixture, sorry. 01:06:45.110 --> 01:06:47.360 Because you're still referencing it later in the code. 01:06:47.360 --> 01:06:49.735 COLTON OGDEN: You're still referencing later in the code. 01:06:49.735 --> 01:06:52.070 Box2D maintains a reference to all of the bodies, all 01:06:52.070 --> 01:06:58.820 of the fixtures in your world, regardless of 01:06:58.820 --> 01:07:00.440 whether you've deleted them or not. 01:07:00.440 --> 01:07:03.470 But if you delete them while it's in the middle of a, 01:07:03.470 --> 01:07:06.950 like checking for collision, it'll try to do another collision 01:07:06.950 --> 01:07:12.100 with that destroyed body and you'll get a crash or a stack overflow error. 01:07:12.100 --> 01:07:14.300 I found I experienced both of those. 01:07:14.300 --> 01:07:19.940 You don't want to ever delete or destroy anything while inside a collision 01:07:19.940 --> 01:07:21.260 callback for your world. 01:07:21.260 --> 01:07:24.192 It will cause horrible things to happen. 01:07:24.192 --> 01:07:26.900 So what we do is we maintain a reference to everything that we're 01:07:26.900 --> 01:07:29.480 going to destroy by just inserting it. 01:07:29.480 --> 01:07:37.220 So if we do table dot insert the body of whatever we want into destroyed bodies, 01:07:37.220 --> 01:07:40.250 we can then loop over that after the world updates. 01:07:40.250 --> 01:07:45.750 And then just destroy them one by one outside of the update function. 01:07:45.750 --> 01:07:49.760 And the reason that we are passing in the body and not the fixture 01:07:49.760 --> 01:07:55.430 is when we destroy a body, it destroys all the fixtures 01:07:55.430 --> 01:07:57.451 associated with that body as well. 01:07:57.451 --> 01:07:59.700 So we're just destroying the top level container here. 01:07:59.700 --> 01:08:04.970 In this case, it doesn't matter too much whether we destroy a fixture or a body 01:08:04.970 --> 01:08:09.090 because it's a one to one relationship. 01:08:09.090 --> 01:08:14.012 But if you had, let's say, a body that has five fixtures on it. 01:08:14.012 --> 01:08:16.220 And if that entire thing collides with something else 01:08:16.220 --> 01:08:18.080 and you want to destroy that entire thing, 01:08:18.080 --> 01:08:20.479 you want to destroy the body, not an individual fixture. 01:08:20.479 --> 01:08:24.410 Because when you destroy the body, it destroys all the fixtures, not just 01:08:24.410 --> 01:08:25.760 the one fixture. 01:08:25.760 --> 01:08:29.990 So that's we're deleting the body, adding the body to destroyed bodies, 01:08:29.990 --> 01:08:34.189 and then later performing a delete off of that. 01:08:34.189 --> 01:08:39.740 The function is destroy here. 01:08:39.740 --> 01:08:42.350 So on line 157-- 01:08:42.350 --> 01:08:45.859 well, 155 to 159, this is where we actually 01:08:45.859 --> 01:08:48.310 iterate over everything that we wanted to flag, 01:08:48.310 --> 01:08:51.560 or that we've flagged as destroyed, and we destroy it. 01:08:51.560 --> 01:08:55.910 So if not body is destroyed, destroy it. 01:08:55.910 --> 01:09:01.790 And then once we destroy it, we're going to go down here and end up 01:09:01.790 --> 01:09:05.420 actually removing the obstacle and the alien class 01:09:05.420 --> 01:09:09.410 from our list of aliens and obstacles. 01:09:09.410 --> 01:09:12.479 Because that maintains a reference to what we're drawing 01:09:12.479 --> 01:09:13.979 and we want to also delete that. 01:09:13.979 --> 01:09:17.450 So not only do we want to delete the object from the world, 01:09:17.450 --> 01:09:19.970 we want to delete the objects that we've created 01:09:19.970 --> 01:09:23.090 that are a wrapper for the bodies and fixtures 01:09:23.090 --> 01:09:26.540 and also the drawing of our aliens so it no longer gets drawn to the scene, 01:09:26.540 --> 01:09:27.388 basically. 01:09:30.020 --> 01:09:36.410 So yeah, don't ever delete a body or a fixture inside your callbacks. 01:09:36.410 --> 01:09:39.109 Always flag them and delete them afterwards. 01:09:39.109 --> 01:09:43.700 Basically, don't delete in the middle of a world update function 01:09:43.700 --> 01:09:45.410 call, which we see here. 01:09:45.410 --> 01:09:49.550 Notice that this takes place, 152, were doing self world update. 01:09:49.550 --> 01:09:55.850 And then on 155 to 159, we've populated destroyed bodies via the collision 01:09:55.850 --> 01:09:57.780 callback that we defined up above. 01:09:57.780 --> 01:10:00.650 So in here, this is where we can actually destroy everything. 01:10:00.650 --> 01:10:04.920 This is outside of the update function, here, the world update function. 01:10:04.920 --> 01:10:08.210 We don't need to worry about stack overflow or a segfault, which 01:10:08.210 --> 01:10:13.070 we get by deleting something while it's in the middle 01:10:13.070 --> 01:10:16.280 of processing its collisions. 01:10:16.280 --> 01:10:17.390 So unfortunate bug. 01:10:17.390 --> 01:10:21.620 If you ever find yourself running into stack overflows or segfaults 01:10:21.620 --> 01:10:25.680 in your collision callbacks, make sure you're not deleting anything. 01:10:25.680 --> 01:10:28.430 But we can see here, it's very similar, the behavior 01:10:28.430 --> 01:10:32.960 we defined between obstacles and the player, between obstacles and aliens, 01:10:32.960 --> 01:10:34.940 and between the player and alien. 01:10:34.940 --> 01:10:38.480 Ultimately, it's check to see whether the average of its velocity 01:10:38.480 --> 01:10:41.000 is greater than a certain number, in this case, 20. 01:10:41.000 --> 01:10:44.627 And if it is, flag it as destroyed. 01:10:44.627 --> 01:10:46.460 So if the player hits the alien, destroy it. 01:10:46.460 --> 01:10:48.560 If a obstacle hits the alien, destroy it. 01:10:48.560 --> 01:10:51.230 And it's similar to how it works in Angry Birds. 01:10:51.230 --> 01:10:57.020 When you throw something at a structure in Angry Birds and a piece of debris 01:10:57.020 --> 01:11:00.740 falls off of it and hits the pig, usually kills the pig too. 01:11:00.740 --> 01:11:04.331 And if your bird hits the pig, that usually kills the pig. 01:11:04.331 --> 01:11:06.830 But if you're not moving fast enough or if a piece of debris 01:11:06.830 --> 01:11:09.530 isn't moving fast enough, it'll just nudge the pig, 01:11:09.530 --> 01:11:11.000 it won't actually kill the pig. 01:11:11.000 --> 01:11:13.820 So that's why we're taking all of this into consideration. 01:11:13.820 --> 01:11:18.780 We're not just doing a blind delete off of the body's in our code, 01:11:18.780 --> 01:11:22.540 we're actually making sure, is it also moving fast enough, i.e. 01:11:22.540 --> 01:11:24.170 does it have enough force? 01:11:24.170 --> 01:11:28.890 And if it does, then perform the code, then perform the deletion or flag it 01:11:28.890 --> 01:11:30.210 as being deleted. 01:11:30.210 --> 01:11:33.110 And so once again, that's why user data is important. 01:11:33.110 --> 01:11:37.920 Because that's how we're able to-- because notice in the callback 01:11:37.920 --> 01:11:41.820 we just get an A and a B. And those are always going to be fixtures. 01:11:41.820 --> 01:11:44.520 Fixtures, in order for it to know what kind of a fixture 01:11:44.520 --> 01:11:48.000 it is, whether it belongs to a player or an alien, 01:11:48.000 --> 01:11:50.010 we need to give it some information. 01:11:50.010 --> 01:11:55.090 So the set user data flags the fixtures as being of a specific type. 01:11:55.090 --> 01:11:58.170 And then we can fetch it here with get user data 01:11:58.170 --> 01:12:02.490 and then actually perform the relevant game logic. 01:12:02.490 --> 01:12:05.424 Any questions as to how this works? 01:12:05.424 --> 01:12:11.412 AUDIENCE: Are you checking for if two obstacles knock into each other? 01:12:11.412 --> 01:12:14.370 COLTON OGDEN: Am I checking with two obstacles collide with each other? 01:12:14.370 --> 01:12:15.570 I might not be. 01:12:15.570 --> 01:12:18.720 In that case-- you should. 01:12:18.720 --> 01:12:21.930 In that case, since we're not, they'll just bump into each other. 01:12:21.930 --> 01:12:24.780 But, yeah, if we wanted two wooden obstacles 01:12:24.780 --> 01:12:27.240 to destroy each other if they hit fast enough, 01:12:27.240 --> 01:12:29.340 you would just do the same thing here. 01:12:29.340 --> 01:12:32.850 If types obstacle, I guess. 01:12:32.850 --> 01:12:35.490 But in this case, because they're both the same key, 01:12:35.490 --> 01:12:39.342 you would have to do if types-- 01:12:39.342 --> 01:12:40.800 let's see how we're doing it again. 01:12:40.800 --> 01:12:45.310 So types obstacles is true, types obstacles is true. 01:12:45.310 --> 01:12:50.740 You would say if types obstacle and not types alien, not types player, not-- 01:12:50.740 --> 01:12:52.300 there's a cleaner way to do it. 01:12:52.300 --> 01:12:54.390 AUDIENCE: Like a series of [INAUDIBLE] statements. 01:12:54.390 --> 01:12:54.630 COLTON OGDEN: Yeah. 01:12:54.630 --> 01:12:55.800 AUDIENCE: [INAUDIBLE] statements. 01:12:55.800 --> 01:12:56.591 COLTON OGDEN: Yeah. 01:12:56.591 --> 01:12:57.330 That's true. 01:12:57.330 --> 01:12:59.680 Yeah, there's a lot of ways. 01:12:59.680 --> 01:13:02.702 And if I were to re-engineer this, I would also abstract out this code 01:13:02.702 --> 01:13:03.660 and make it a function. 01:13:03.660 --> 01:13:07.620 Because it's pretty much the same code between all three of these. 01:13:07.620 --> 01:13:09.630 But just to illustrate and just for simplicity 01:13:09.630 --> 01:13:12.080 because it's pretty similar interactions, 01:13:12.080 --> 01:13:15.420 didn't really put too much engineering forethought into it. 01:13:15.420 --> 01:13:20.580 Definitely if you expand upon it, I would recommend doing that. 01:13:20.580 --> 01:13:26.070 But that's the gist of making our world behave beyond just resolving 01:13:26.070 --> 01:13:28.620 collisions and pushing obstacles away from each other, which 01:13:28.620 --> 01:13:31.690 is the default behavior. 01:13:31.690 --> 01:13:33.090 So we set the callbacks. 01:13:33.090 --> 01:13:33.630 We're good. 01:13:33.630 --> 01:13:36.671 Now things, when we interact with each other, they'll behave differently, 01:13:36.671 --> 01:13:39.210 they'll trigger different behavior. 01:13:39.210 --> 01:13:42.270 We have this thing called a launch marker, an alien launch marker. 01:13:42.270 --> 01:13:43.711 Anybody know what that might be? 01:13:47.559 --> 01:13:50.697 AUDIENCE: Is that the little dots that show the trajectory? 01:13:50.697 --> 01:13:53.280 COLTON OGDEN: Yeah, so it's the dots that show the trajectory. 01:13:53.280 --> 01:13:56.220 It's one, the alien being rendered on the left side of the screen 01:13:56.220 --> 01:14:00.180 without any physics applied to it, that's click and dragable. 01:14:00.180 --> 01:14:02.040 And it also renders a trajectory. 01:14:02.040 --> 01:14:07.050 And when you release the mouse, it launches an actual Box2D alien 01:14:07.050 --> 01:14:12.630 traveling in the direction that that trajectory foretells. 01:14:12.630 --> 01:14:19.024 If we look at alien launch marker here, it basically maintains a reference to 01:14:19.024 --> 01:14:20.190 whether we're aiming or not. 01:14:20.190 --> 01:14:21.600 So it's got a couple of states. 01:14:21.600 --> 01:14:25.190 It's got a launch state and an aiming state. 01:14:25.190 --> 01:14:27.960 An alien that we'll have a reference to eventually, which 01:14:27.960 --> 01:14:30.400 will spawn and will give it an impulse. 01:14:30.400 --> 01:14:36.420 So an impulse is effectively setting its velocity immediately to some value, 01:14:36.420 --> 01:14:38.160 as opposed to something over time. 01:14:38.160 --> 01:14:40.170 We can apply force to an object, which would 01:14:40.170 --> 01:14:43.230 be like you driving your car up against something 01:14:43.230 --> 01:14:46.110 and then gradually accelerating, that's applying force. 01:14:46.110 --> 01:14:49.920 And we can also apply impulse by going full speed with our car 01:14:49.920 --> 01:14:52.230 and hitting an object, and that will have 01:14:52.230 --> 01:14:56.220 the effect of applying an impulse at a certain velocity. 01:14:56.220 --> 01:15:00.450 When we drag our alien and then we release it, 01:15:00.450 --> 01:15:03.480 we want to apply an impulse in the opposite direction of where we're 01:15:03.480 --> 01:15:06.060 dragging based on a certain amount. 01:15:06.060 --> 01:15:10.500 I scaled it by 10, but you can have it be arbitrary. 01:15:10.500 --> 01:15:14.550 And then the trajectory models where it's going. 01:15:14.550 --> 01:15:20.110 And the trajectory is calculated via these lines here. 01:15:20.110 --> 01:15:22.250 So from line 90 to 104. 01:15:22.250 --> 01:15:25.620 There is a formula for, in that Box2D set 01:15:25.620 --> 01:15:27.390 of tutorials, that actually shows you how 01:15:27.390 --> 01:15:31.890 to calculate an estimated trajectory given a starting impulse and a starting 01:15:31.890 --> 01:15:33.900 position. 01:15:33.900 --> 01:15:36.060 Which is this formula here. 01:15:36.060 --> 01:15:38.190 It's semi-complicated. 01:15:38.190 --> 01:15:40.500 The article goes into detail as to how it works, 01:15:40.500 --> 01:15:45.420 but it effectively calculates 1/60 of a second, 01:15:45.420 --> 01:15:48.580 assuming that we're running our simulation at 1/60 of a second, 01:15:48.580 --> 01:15:52.810 it will, over 90 iterations here, 1 to 90, 01:15:52.810 --> 01:15:56.310 calculate each individual step of that simulation. 01:15:56.310 --> 01:15:58.900 And then I only render every 5 here. 01:15:58.900 --> 01:16:03.180 So if i is mod 5 s 0, then I'll actually end up 01:16:03.180 --> 01:16:05.640 drawing a circle at trajectory X, trajectory 01:16:05.640 --> 01:16:07.830 Y. Trajectory X and Y being here. 01:16:07.830 --> 01:16:10.950 Shifted X, shifted Y being the starting location. 01:16:10.950 --> 01:16:15.180 And then we multiply i by 1/60 of a second, which will give us 01:16:15.180 --> 01:16:19.860 the scalar for this impulse here. 01:16:19.860 --> 01:16:23.600 And then with gravity we have to do this i squared plus 01:16:23.600 --> 01:16:31.530 i times 1/2 times the gravity on the y-axis times 1/60 squared. 01:16:31.530 --> 01:16:34.530 The article goes into a little bit more detail as to how it works. 01:16:34.530 --> 01:16:38.910 But that's it converted into source code. 01:16:38.910 --> 01:16:41.010 But it's effectively a gravity simulation 01:16:41.010 --> 01:16:44.490 and a velocity simulation over time. 01:16:44.490 --> 01:16:47.670 And by rendering it based on 90 iterations, which 01:16:47.670 --> 01:16:51.210 is one and a half seconds, at 1/60 of a second 01:16:51.210 --> 01:16:54.750 we can forecast where exactly we're going. 01:16:54.750 --> 01:17:00.620 And then when we apply this impulse, X and Y, the ball will actually travel, 01:17:00.620 --> 01:17:04.690 the alien will actually travel in that direction at that exact trajectory. 01:17:09.050 --> 01:17:12.050 That's the complicated part of the launch marker. 01:17:12.050 --> 01:17:16.550 The other part is that it has a couple of states, like I said before. 01:17:16.550 --> 01:17:20.180 So when we click and we're not launched, it should go into aiming mode. 01:17:20.180 --> 01:17:25.790 And so if we're aiming then we're going to set a rotation to-- 01:17:25.790 --> 01:17:31.610 actually, rotation is not relevant because this was before I ended up 01:17:31.610 --> 01:17:34.760 using the predictive trajectory method. 01:17:34.760 --> 01:17:39.470 The shift at X and Y though, those are relevant because that's the starting 01:17:39.470 --> 01:17:41.240 location for your trajectory. 01:17:41.240 --> 01:17:43.084 That's wherever your mouse is. 01:17:43.084 --> 01:17:45.500 And we clamp it so that it doesn't go past a certain limit 01:17:45.500 --> 01:17:49.730 on the left or the right, so that it stays within a box area. 01:17:49.730 --> 01:17:52.160 But this will be whenever you let go of the mouse, that 01:17:52.160 --> 01:17:55.670 will be where we spawn the Box2D alien and apply 01:17:55.670 --> 01:17:59.460 an impulse in a negative direction relative to where we move the mouse. 01:17:59.460 --> 01:18:01.820 So if we move the mouse to the left and down, 01:18:01.820 --> 01:18:05.620 it's going to negate that with an impulse going up 01:18:05.620 --> 01:18:08.330 and to the right, if that makes sense. 01:18:08.330 --> 01:18:10.378 And that's what's shown by the trajectory. 01:18:13.130 --> 01:18:15.560 And then, aside from that, it renders different things 01:18:15.560 --> 01:18:16.827 depending on whether or not-- 01:18:16.827 --> 01:18:17.660 what state we're in. 01:18:17.660 --> 01:18:20.600 So if we haven't launched, it will render just the alien. 01:18:20.600 --> 01:18:23.660 If we're in aiming mode then it should actually render and calculate 01:18:23.660 --> 01:18:24.710 the trajectory. 01:18:24.710 --> 01:18:27.080 Otherwise, it would just render the alien. 01:18:27.080 --> 01:18:34.130 And so once we release the mouse, so was released 1 and were aiming, 01:18:34.130 --> 01:18:35.960 launched is true, spawn an alien. 01:18:35.960 --> 01:18:40.610 So we create a new alien with self world, it's round. 01:18:40.610 --> 01:18:43.400 We started at shifted X and shifted Y. We 01:18:43.400 --> 01:18:48.720 set its linear velocity to the same values that we calculated before. 01:18:48.720 --> 01:18:51.960 So it's base X minus shifted X times 10. 01:18:51.960 --> 01:18:53.450 So the times 10 is a scalar amount. 01:18:56.450 --> 01:19:03.421 And then the base X is where we've moved it, effectively. 01:19:03.421 --> 01:19:03.920 Or, no. 01:19:03.920 --> 01:19:07.970 Base X is where it starts and shifted X is where we've moved it. 01:19:07.970 --> 01:19:11.390 And so by subtracting shifted from the base, 01:19:11.390 --> 01:19:16.280 we get the negative direction that we want to effect the impulse. 01:19:16.280 --> 01:19:21.560 And then the impulse is set here with linear velocity. 01:19:21.560 --> 01:19:26.660 And then we also set it to have a restitution of 0.4. 01:19:26.660 --> 01:19:29.420 Recall, restitution is bounciness. 01:19:29.420 --> 01:19:32.450 So our alien bounces a little bit when it hits the ground. 01:19:32.450 --> 01:19:37.170 And then anybody know what angular damping might be? 01:19:37.170 --> 01:19:39.680 Any guesses? 01:19:39.680 --> 01:19:45.860 Angular damping is when it rotates, basically, friction on its rotation. 01:19:45.860 --> 01:19:49.520 So that when it rotates on the ground, it doesn't roll indefinitely. 01:19:49.520 --> 01:19:52.997 If we don't set that, it'll just roll forever and ever and ever and ever. 01:19:52.997 --> 01:19:54.080 Which is not what we want. 01:19:54.080 --> 01:19:56.990 We want it to stop at a certain point because once it stops, 01:19:56.990 --> 01:20:00.170 we know, OK, now we can get the next alien ready to launch. 01:20:03.170 --> 01:20:05.420 And that's the gist behind the launch marker. 01:20:05.420 --> 01:20:07.294 How we render trajectory. 01:20:07.294 --> 01:20:10.460 For the math on that, a little bit more in detail, I would explore that URL. 01:20:10.460 --> 01:20:12.740 It goes into it into pretty good detail. 01:20:12.740 --> 01:20:18.156 I use that as a reference for creating this bit of code here. 01:20:18.156 --> 01:20:20.030 But yeah, effectively, is it's just rendering 01:20:20.030 --> 01:20:24.470 a bunch of circles with that trajectory and calculating it 01:20:24.470 --> 01:20:30.770 over 90 ticks, 90 frame iterations. 01:20:30.770 --> 01:20:32.860 Back to the level. 01:20:32.860 --> 01:20:37.402 Sorry, any questions overall as to how the launch marker works? 01:20:37.402 --> 01:20:38.334 AUDIENCE: No. 01:20:38.334 --> 01:20:40.000 COLTON OGDEN: Cool. 01:20:40.000 --> 01:20:40.500 All right. 01:20:40.500 --> 01:20:44.190 So then we have an alien's table, an obstacles table, 01:20:44.190 --> 01:20:47.580 edge shape for the ground. 01:20:47.580 --> 01:20:50.660 And then we just create an alien to destroy. 01:20:50.660 --> 01:20:52.140 Spawn a few obstacles here. 01:20:52.140 --> 01:20:56.280 So in this case, two vertical obstacles and a horizontal one. 01:20:56.280 --> 01:20:59.580 Positioned such that the horizontal one is over the vertical ones 01:20:59.580 --> 01:21:04.730 and they're spaced apart such that the aliens are in the middle of them. 01:21:04.730 --> 01:21:08.980 Then the ground here, we give the ground some friction, 0.5. 01:21:08.980 --> 01:21:12.280 And that's pretty much it for setting up our level. 01:21:12.280 --> 01:21:18.330 So if we wanted to, after this point, we have the foundation 01:21:18.330 --> 01:21:24.030 necessary to really spawn arbitrary levels with admittedly simple obstacles 01:21:24.030 --> 01:21:24.900 at this point. 01:21:24.900 --> 01:21:26.970 But we could set-- 01:21:26.970 --> 01:21:30.270 because all we're doing here is just simple insertions to our aliens 01:21:30.270 --> 01:21:36.030 and obstacles table, we could create pretty much any level just by, maybe 01:21:36.030 --> 01:21:40.710 in data, specifying level could be like a table 01:21:40.710 --> 01:21:44.220 and then aliens could be another table. 01:21:44.220 --> 01:21:53.100 And then maybe all it is just a like X equals some value, 01:21:53.100 --> 01:21:55.170 and then Y equals some value. 01:21:55.170 --> 01:21:59.340 And then obstacles is the same thing. 01:21:59.340 --> 01:22:02.640 And then all we do is just we iterate over this level definition 01:22:02.640 --> 01:22:07.440 and we just say, new alien for every table here. 01:22:07.440 --> 01:22:09.390 And then new obstacle for every table in here. 01:22:09.390 --> 01:22:11.640 And then now your levels are data driven. 01:22:11.640 --> 01:22:13.260 It's easy just to make levels. 01:22:13.260 --> 01:22:15.134 You don't have to code, really, much. 01:22:15.134 --> 01:22:16.800 And you can put this in a separate file. 01:22:16.800 --> 01:22:21.240 Be like, levels dot Lua, and then just load individual levels at a time. 01:22:21.240 --> 01:22:28.020 Level 1 equals-- levels would be the top level container. 01:22:28.020 --> 01:22:33.720 And then you would have 1 equals all of this, and then 2 01:22:33.720 --> 01:22:36.004 equals another one, 3 equals another one. 01:22:36.004 --> 01:22:37.920 And then you're not really programming as much 01:22:37.920 --> 01:22:40.170 as you are just laying things out in data. 01:22:40.170 --> 01:22:41.640 Super nice and concise. 01:22:41.640 --> 01:22:44.980 That's a nice thing about a language like Lua, is that you can, 01:22:44.980 --> 01:22:47.130 and it's the same thing in JavaScript with JSON, 01:22:47.130 --> 01:22:50.970 you can just define things as data and then write 01:22:50.970 --> 01:22:54.630 a script to go over it and construct your actual relevant data structures 01:22:54.630 --> 01:22:55.760 that way-- 01:22:55.760 --> 01:22:57.240 in your code that way. 01:22:57.240 --> 01:22:59.580 When you have the foundation like we have now 01:22:59.580 --> 01:23:02.340 where you can think in terms of obstacles and aliens, 01:23:02.340 --> 01:23:04.650 you can construct levels like so. 01:23:04.650 --> 01:23:07.170 And obviously you could go a lot more complicated with this. 01:23:07.170 --> 01:23:14.280 All we're doing is having very simple almost boring static obstacles. 01:23:14.280 --> 01:23:17.280 They're not static in a technical sense because they're dynamic objects, 01:23:17.280 --> 01:23:21.520 but all they really do is just stand there and then fall over. 01:23:21.520 --> 01:23:25.890 But if you wanted a pulley system or maybe 01:23:25.890 --> 01:23:29.520 something that's shaped in a giant head or something, 01:23:29.520 --> 01:23:36.880 you can create arbitrarily complex objects that way using joints. 01:23:36.880 --> 01:23:40.050 And if you're curious, I recommend to look into the documentation for Love2D 01:23:40.050 --> 01:23:40.980 a little bit more. 01:23:40.980 --> 01:23:44.340 Especially their weld joints are what you would use 01:23:44.340 --> 01:23:47.970 to combine pieces in arbitrary shapes. 01:23:47.970 --> 01:23:50.820 But you could easily take this to the next level 01:23:50.820 --> 01:23:56.520 and start to create in that same level definition, arbitrarily shaped, 01:23:56.520 --> 01:24:01.495 welded together obstacles. 01:24:01.495 --> 01:24:03.870 But that would be, I think, a next step if you're looking 01:24:03.870 --> 01:24:06.990 to take this beyond just one level. 01:24:06.990 --> 01:24:12.510 I would say, think in terms of, how can I get my game world represented 01:24:12.510 --> 01:24:14.850 in a very simple data like way? 01:24:14.850 --> 01:24:17.670 Because not only does it make it easier for you to create content, 01:24:17.670 --> 01:24:20.430 it allows you to shift that burden to somebody else 01:24:20.430 --> 01:24:23.002 and allow you to give the task of creating levels 01:24:23.002 --> 01:24:24.960 less to a programmer and maybe more to somebody 01:24:24.960 --> 01:24:28.290 who has just a design background who isn't as comfortable writing code. 01:24:28.290 --> 01:24:31.920 And allow you to create the engine that constructs the game world based off 01:24:31.920 --> 01:24:34.440 of this data. 01:24:34.440 --> 01:24:40.560 Any questions as to how we've set things up here? 01:24:40.560 --> 01:24:41.877 OK. 01:24:41.877 --> 01:24:43.710 So we have the ground, we have a background. 01:24:43.710 --> 01:24:47.550 A background is just a simple class that renders a static image 01:24:47.550 --> 01:24:49.860 that you can scroll the image with left or right, 01:24:49.860 --> 01:24:51.930 but we don't end up using it much. 01:24:51.930 --> 01:24:55.590 It's relevant in Angry Birds because in Angry Birds they have a camera, 01:24:55.590 --> 01:25:00.540 and the camera pans left to right depending on how far away 01:25:00.540 --> 01:25:02.790 the fortress is from your sling shot. 01:25:02.790 --> 01:25:06.660 So that's in there if you want to experiment with it at all, 01:25:06.660 --> 01:25:08.160 and experiment with a moving camera. 01:25:08.160 --> 01:25:11.280 Maybe use timer dot tween to tween the camera 01:25:11.280 --> 01:25:15.690 or just to have it track the alien if you want larger worlds. 01:25:15.690 --> 01:25:19.320 But we don't end up using it in the distro as much. 01:25:19.320 --> 01:25:20.890 Our update function is simple. 01:25:20.890 --> 01:25:23.070 We update the launch marker, update the world, 01:25:23.070 --> 01:25:26.280 and then we process all the bodies that we flagged as being destroyed, 01:25:26.280 --> 01:25:27.680 which we've already seen. 01:25:27.680 --> 01:25:29.640 We reset destroyed bodies to an empty table 01:25:29.640 --> 01:25:31.740 because we've processed all of them. 01:25:31.740 --> 01:25:38.504 We actually remove from our level the obstacle objects 01:25:38.504 --> 01:25:40.670 so that they're no longer rendered, and we no longer 01:25:40.670 --> 01:25:44.650 try to reference the bodies that are destroyed. 01:25:44.650 --> 01:25:49.160 And then notice here too, when we destroy the obstacle, 01:25:49.160 --> 01:25:52.050 we're playing a sound effect inside this bit of code. 01:25:52.050 --> 01:25:54.650 So we can just do g sounds. 01:25:54.650 --> 01:25:57.260 I put five wooden sound effects in there just for variability. 01:25:57.260 --> 01:25:58.280 It'll pick a random one. 01:25:58.280 --> 01:26:00.650 And then using to string at the number, just 01:26:00.650 --> 01:26:03.020 create break one, two, three, four, five here. 01:26:03.020 --> 01:26:06.420 And then stop and play it. 01:26:06.420 --> 01:26:07.197 Same thing here. 01:26:07.197 --> 01:26:09.530 I have a sound called kill for when we destroy an alien. 01:26:09.530 --> 01:26:14.240 So when we flag an alien as destroyed and we remove it from the scene, 01:26:14.240 --> 01:26:16.910 we should also call that sound effect. 01:26:16.910 --> 01:26:27.050 And then if the alien stops moving in our scene, the player, 01:26:27.050 --> 01:26:31.430 we can get a reference to it here, self dot launch marker dot alien, 01:26:31.430 --> 01:26:33.667 as opposed to any aliens in our scene. 01:26:33.667 --> 01:26:36.125 When it stops moving, so we get the average of its velocity 01:26:36.125 --> 01:26:38.510 and if it's less than 1.5, so not perfectly 01:26:38.510 --> 01:26:43.610 still, because it's tedious to wait that long, but almost still, 01:26:43.610 --> 01:26:48.950 we destroy the alien and then we create a new launch marker. 01:26:48.950 --> 01:26:52.439 We destroy the alien so that the world doesn't keep a reference to it 01:26:52.439 --> 01:26:54.230 and then we just create a brand new marker, 01:26:54.230 --> 01:27:00.530 which has the effect of instantiating a new alien there when we relaunch. 01:27:00.530 --> 01:27:04.369 And then here, if there are no more aliens in our scene, 01:27:04.369 --> 01:27:07.410 if we've destroyed all of the aliens, in this case there's only ever one, 01:27:07.410 --> 01:27:09.800 but there could easily, with a little more work, 01:27:09.800 --> 01:27:13.040 be a few more aliens in the scene, if it's set to zero, 01:27:13.040 --> 01:27:14.630 then go back to the start. 01:27:14.630 --> 01:27:18.160 Which we saw before when we finally killed the alien. 01:27:18.160 --> 01:27:19.910 And then all we're doing here is deferring 01:27:19.910 --> 01:27:26.090 rendering to the individual objects we want to render, the launch marker, 01:27:26.090 --> 01:27:27.650 the alien, the obstacle. 01:27:27.650 --> 01:27:29.420 We render ground tiles. 01:27:29.420 --> 01:27:34.070 So recall, from our ground example before we were just using a line, 01:27:34.070 --> 01:27:36.200 an edge shape to represent the ground. 01:27:36.200 --> 01:27:44.630 But if we look at our game, it's a little hard to see because I'm in 720, 01:27:44.630 --> 01:27:49.250 but there's actually a ground tile here at the very bottom, a bunch of them. 01:27:49.250 --> 01:27:52.760 And even though we have all of those tiles, 01:27:52.760 --> 01:27:56.090 all we're doing to detect collision is just an edge shape. 01:27:56.090 --> 01:28:02.720 So what we're doing is just beyond having the edge shape in our scene, 01:28:02.720 --> 01:28:09.530 we draw that tile, which is frame 12 in our sprite sheet 01:28:09.530 --> 01:28:11.930 from negative virtual width to virtual times 2. 01:28:11.930 --> 01:28:13.850 So three screen widths total. 01:28:13.850 --> 01:28:16.130 And then we just do it in increments of 35 pixels 01:28:16.130 --> 01:28:17.630 because that's how wide the tile is. 01:28:17.630 --> 01:28:19.856 And that'll just create a bunch of the same tile 01:28:19.856 --> 01:28:21.230 at the very bottom of our screen. 01:28:24.660 --> 01:28:28.130 So just a graphical thing, not really necessarily functional. 01:28:28.130 --> 01:28:31.190 We have the edge shape already in our scene, but just to make the ground 01:28:31.190 --> 01:28:35.540 look a little larger than one pixel tall. 01:28:35.540 --> 01:28:38.300 And then if we haven't launched anything, 01:28:38.300 --> 01:28:40.610 we should display some instructions here. 01:28:40.610 --> 01:28:45.050 And then if we're at no aliens left, then we 01:28:45.050 --> 01:28:47.570 should display the victory screen. 01:28:47.570 --> 01:28:51.650 And the victory thing will last for just a little bit of time, 01:28:51.650 --> 01:28:55.370 because even though self dot aliens is zero, this bit of code 01:28:55.370 --> 01:28:59.840 doesn't register until after the velocity of our moving alien 01:28:59.840 --> 01:29:01.520 slows down sufficiently. 01:29:01.520 --> 01:29:05.420 So this will get called when we're just about to finally stop moving, 01:29:05.420 --> 01:29:09.500 and then we check to see, oh, OK, do we indeed have no aliens left? 01:29:09.500 --> 01:29:12.380 If not, time to go back to the start. 01:29:12.380 --> 01:29:13.475 We've completed a level. 01:29:13.475 --> 01:29:15.350 And then you obviously would just change this 01:29:15.350 --> 01:29:19.179 to go to be next level if you ended up implementing more 01:29:19.179 --> 01:29:20.720 levels in your game besides just one. 01:29:23.600 --> 01:29:27.550 Beyond that, that's pretty much all of the code that's in this example. 01:29:27.550 --> 01:29:32.300 It's fairly, I would say, unsophisticated relative 01:29:32.300 --> 01:29:33.260 to prior examples. 01:29:33.260 --> 01:29:35.630 But mainly, the burden is learning how to use 01:29:35.630 --> 01:29:38.960 the physics engine, the Box2D physics engine, which 01:29:38.960 --> 01:29:42.240 itself is quite a few functions. 01:29:42.240 --> 01:29:47.060 It's some of the longest documentation on Love2D's wiki, I think. 01:29:47.060 --> 01:29:50.270 But the principles are pretty simple, in my opinion. 01:29:50.270 --> 01:29:54.905 I think it's actually quite easy to get rolling with a lot of cool features. 01:29:57.617 --> 01:30:00.200 The vast majority of which I don't think we even really cover, 01:30:00.200 --> 01:30:03.920 at least in terms of what you can do with compound objects and joints 01:30:03.920 --> 01:30:06.260 and things like that, which really start to go 01:30:06.260 --> 01:30:12.260 into the world of more sophisticated and interesting physical simulations. 01:30:12.260 --> 01:30:16.130 Things like I alluded to before, pulleys and tanks and other things like that. 01:30:16.130 --> 01:30:19.580 Some features that we could look at potentially expanding upon 01:30:19.580 --> 01:30:21.920 if we wanted to make our game more interesting, 01:30:21.920 --> 01:30:24.430 is more shapes for our objects. 01:30:24.430 --> 01:30:28.280 So if we look at our sprite sheet here, we 01:30:28.280 --> 01:30:33.290 can see there are things like roofs and circles and things like that. 01:30:33.290 --> 01:30:36.710 So more interesting obstacles beyond just square rectangular 01:30:36.710 --> 01:30:37.590 shaped obstacles. 01:30:40.790 --> 01:30:44.540 Go back to-- like I said before, compound obstacles. 01:30:44.540 --> 01:30:47.240 So a bunch of things put together via joints. 01:30:47.240 --> 01:30:51.210 So pulleys, there's motors, weld joints, which you can use to-- you 01:30:51.210 --> 01:30:56.840 can affix a roof to a square and then have two pieces that are tied together. 01:30:56.840 --> 01:30:59.330 And you can make arbitrarily complex and shaped things 01:30:59.330 --> 01:31:01.010 and just be really interesting. 01:31:01.010 --> 01:31:03.890 And that big thing, that body with all these fixtures, 01:31:03.890 --> 01:31:09.740 will collide just as any other thing would, thanks to Box2D. 01:31:09.740 --> 01:31:13.670 As I alluded to before, instead of having levels to be hard coded 01:31:13.670 --> 01:31:19.100 into our level class, maybe define them in a Lua file called levels dot Lua. 01:31:19.100 --> 01:31:22.070 And then just have aliens be a table, obstacles 01:31:22.070 --> 01:31:23.870 be a table, and then whatever else, however 01:31:23.870 --> 01:31:25.869 more complicated you want to get with your game. 01:31:25.869 --> 01:31:27.260 You can add more things. 01:31:27.260 --> 01:31:32.409 But just have it be represented as simple data structures. 01:31:32.409 --> 01:31:34.700 So aliens that maybe have different shooting mechanics. 01:31:34.700 --> 01:31:37.280 So if you've played Angry Birds you're familiar with the fact 01:31:37.280 --> 01:31:40.070 that some birds will split off into multiple birds. 01:31:40.070 --> 01:31:44.150 Some birds will dive and go super fast and break through all the obstacles 01:31:44.150 --> 01:31:45.290 in their path. 01:31:45.290 --> 01:31:48.020 Some birds will explode, and then their explosion 01:31:48.020 --> 01:31:50.610 affects all of the obstacles around them. 01:31:50.610 --> 01:31:52.970 So there's a lot of different game play mechanics 01:31:52.970 --> 01:31:57.240 you can implement using different types of birds or aliens. 01:31:57.240 --> 01:32:01.670 And then different obstacle materials is another direction we could go. 01:32:01.670 --> 01:32:04.280 And it's supported out of the box with the sprite sheet 01:32:04.280 --> 01:32:08.300 that I provided because it has sheets for metal 01:32:08.300 --> 01:32:10.080 and glass and explosive material. 01:32:10.080 --> 01:32:12.080 So there's a lot of different interesting things 01:32:12.080 --> 01:32:15.800 you could do just by changing up what materials you're using in the game. 01:32:15.800 --> 01:32:19.250 And obviously those will have different densities and behave in different ways. 01:32:19.250 --> 01:32:21.450 So assignment five is a fairly simple assignment. 01:32:21.450 --> 01:32:24.320 So this is just as I alluded to before. 01:32:24.320 --> 01:32:27.620 The task here is to split the bird that you 01:32:27.620 --> 01:32:31.850 shoot by pressing Spacebar when it's in the bird-- the alien, when 01:32:31.850 --> 01:32:35.360 it's in the air, press Spacebar and have it split into three. 01:32:35.360 --> 01:32:37.680 So you have your one that you're shooting already. 01:32:37.680 --> 01:32:39.470 So it should just shoot off two more. 01:32:39.470 --> 01:32:41.600 One that's angled higher, one that's angled lower. 01:32:41.600 --> 01:32:45.945 And all of those should be interactable with your game world. 01:32:45.945 --> 01:32:46.820 And that's really it. 01:32:46.820 --> 01:32:48.944 So if you can do that then it'll show that you know 01:32:48.944 --> 01:32:52.580 how to effect the Box2D game world. 01:32:52.580 --> 01:32:55.574 Next time, next lecture, we'll be talking about-- 01:32:55.574 --> 01:32:57.365 the theme is going to be Pokemon, but we'll 01:32:57.365 --> 01:33:03.057 be talking about more generally RPGs and turn-based games of that nature. 01:33:03.057 --> 01:33:05.390 It won't maybe necessarily look quite as pretty as this. 01:33:05.390 --> 01:33:08.390 But we'll be striving for a similar over world 01:33:08.390 --> 01:33:11.937 that we can walk around and then engage in fairly simple turn-based battles 01:33:11.937 --> 01:33:12.770 and stuff like that. 01:33:12.770 --> 01:33:15.530 And also, we'll be talking about user interfaces and things 01:33:15.530 --> 01:33:18.080 like dialogue and stuff like that. 01:33:18.080 --> 01:33:20.332 But that was it for lecture six, Angry Birds. 01:33:20.332 --> 01:33:21.290 I'll see you next time. 01:33:21.290 --> 01:33:23.140 Thank you.