1 00:00:00,000 --> 00:00:00,068 2 00:00:00,068 --> 00:00:02,610 COLTON OGDEN: So Pong 6 was a little bit on the simpler side. 3 00:00:02,610 --> 00:00:04,920 All we did was add a string to the top left. 4 00:00:04,920 --> 00:00:06,540 That measured our FPS. 5 00:00:06,540 --> 00:00:09,600 So nice to have if you want to measure how well your game is 6 00:00:09,600 --> 00:00:11,040 running on a particular system. 7 00:00:11,040 --> 00:00:14,530 It's not particular sophisticated, but it was a nice little reprieve. 8 00:00:14,530 --> 00:00:16,530 Pong 7 is a little bit meatier in that now we're 9 00:00:16,530 --> 00:00:19,528 going to get a little bit of more interesting functionality in our game 10 00:00:19,528 --> 00:00:20,570 with collision detection. 11 00:00:20,570 --> 00:00:23,370 Now, again, you can't really see it in this slide. 12 00:00:23,370 --> 00:00:27,090 But what we're going to do is have it so that the ball can move and collide, 13 00:00:27,090 --> 00:00:30,854 not only with the paddles but also with the up and down edges of the screen. 14 00:00:30,854 --> 00:00:32,729 And now what I realized, in the last section, 15 00:00:32,729 --> 00:00:34,562 we didn't actually implement love dot window 16 00:00:34,562 --> 00:00:37,930 dot set title, so we're going to do that in this section as well. 17 00:00:37,930 --> 00:00:41,340 So in order to get to that, we need to talk about how to actually collide 18 00:00:41,340 --> 00:00:42,480 two rectangles together. 19 00:00:42,480 --> 00:00:45,450 And fortunately, it's pretty easy in the context of what 20 00:00:45,450 --> 00:00:47,880 are called axis-aligned bounding boxes. 21 00:00:47,880 --> 00:00:51,000 And that just means that we have rectangles on our screen 22 00:00:51,000 --> 00:00:55,185 that are aligned, not rotated at all to our x, 23 00:00:55,185 --> 00:00:58,960 or our y and our x-axes in our coordinate system. 24 00:00:58,960 --> 00:01:02,280 And in order to test whether two rectangles are colliding, 25 00:01:02,280 --> 00:01:07,470 we really just need to really test to see whether or not one edge of another 26 00:01:07,470 --> 00:01:11,910 is not touching or beyond the opposite edge of the other rectangle. 27 00:01:11,910 --> 00:01:14,190 And to illustrate this, I have a slide here 28 00:01:14,190 --> 00:01:17,610 that sort of shows two rectangles that are colliding. 29 00:01:17,610 --> 00:01:24,450 And you can see that for example, this side here is within this side. 30 00:01:24,450 --> 00:01:27,120 It's to the left of that side. 31 00:01:27,120 --> 00:01:28,320 But it suffices. 32 00:01:28,320 --> 00:01:32,050 If we do a check on each edge of the rectangle, so for example, 33 00:01:32,050 --> 00:01:35,500 this edge here, this left edge of this right rectangle, 34 00:01:35,500 --> 00:01:37,692 if we know that it's to the right of this edge, 35 00:01:37,692 --> 00:01:39,900 well, then there can't be a collision no matter what. 36 00:01:39,900 --> 00:01:41,640 It's just impossible for that to happen. 37 00:01:41,640 --> 00:01:45,090 The same thing if this edge is above this edge. 38 00:01:45,090 --> 00:01:49,470 In other words, if the opposite edges are disjointed, 39 00:01:49,470 --> 00:01:51,000 then there's no collision. 40 00:01:51,000 --> 00:01:51,750 It's not possible. 41 00:01:51,750 --> 00:01:53,750 So if you do a check for each of the four edges, 42 00:01:53,750 --> 00:01:55,740 by virtue of that, the simplicity of that, 43 00:01:55,740 --> 00:01:57,698 then you're guaranteed to not have a collision. 44 00:01:57,698 --> 00:02:02,220 And that's how you do a simple axis-aligned bounding box collision. 45 00:02:02,220 --> 00:02:04,387 And that's really all of the mental framework 46 00:02:04,387 --> 00:02:05,970 we'll establish before we get into it. 47 00:02:05,970 --> 00:02:08,650 Now, let's just actually implement that code. 48 00:02:08,650 --> 00:02:10,680 So I'm going to go here into my distro. 49 00:02:10,680 --> 00:02:15,240 And what I want to do is I want to have a function in the ball class 50 00:02:15,240 --> 00:02:17,520 that will actually check to see whether it's colliding 51 00:02:17,520 --> 00:02:20,240 with some other entity which we assume is going 52 00:02:20,240 --> 00:02:22,248 to have an xy, a width and a height. 53 00:02:22,248 --> 00:02:23,790 In this case, it will be our paddles. 54 00:02:23,790 --> 00:02:25,890 And we'll check to see whether the ball collides 55 00:02:25,890 --> 00:02:27,620 with paddle one and paddle two. 56 00:02:27,620 --> 00:02:28,735 We'll do that from main. 57 00:02:28,735 --> 00:02:31,110 But we need to actually have the function that does that. 58 00:02:31,110 --> 00:02:34,065 So I'm going to say it's going to be a function called collides. 59 00:02:34,065 --> 00:02:35,820 It's going to return a Boolean. 60 00:02:35,820 --> 00:02:37,680 And it's going to take-- 61 00:02:37,680 --> 00:02:41,470 let's just say box as our argument here. 62 00:02:41,470 --> 00:02:44,670 And what we can do is as I just described, 63 00:02:44,670 --> 00:02:47,910 check to see whether or not the edge of our ball 64 00:02:47,910 --> 00:02:50,520 is disjointed from the opposite edge. 65 00:02:50,520 --> 00:02:55,330 In other words, if it's the left edge, check 66 00:02:55,330 --> 00:02:58,620 to see whether it's to the right of the right edge of the other box. 67 00:02:58,620 --> 00:03:02,620 If it is, well, then it's an impossible collision. 68 00:03:02,620 --> 00:03:10,950 So we'll just say, if self.x is greater than box.x plus box.width-- 69 00:03:10,950 --> 00:03:14,530 because remember, everything is relative to its top left corner. 70 00:03:14,530 --> 00:03:17,100 The x is relative to the top left. 71 00:03:17,100 --> 00:03:19,230 So we want to add the width to check to see 72 00:03:19,230 --> 00:03:25,350 whether our x, our left side basically, is to the right of the other box. 73 00:03:25,350 --> 00:03:27,930 If it's greater than the other box's right edge. 74 00:03:27,930 --> 00:03:34,380 So if it's greater than the box.x plus the box.width or our self.x 75 00:03:34,380 --> 00:03:44,500 plus self.width is less than the box.x, then return false. 76 00:03:44,500 --> 00:03:45,840 So it doesn't collide. 77 00:03:45,840 --> 00:03:47,400 It's an impossibility. 78 00:03:47,400 --> 00:03:50,790 And likewise for y, so if self.y is greater 79 00:03:50,790 --> 00:03:59,520 than box.y plus box.height or self.y plus self.height is less than box.y, 80 00:03:59,520 --> 00:04:00,990 then return false. 81 00:04:00,990 --> 00:04:03,270 Otherwise, we can return true. 82 00:04:03,270 --> 00:04:05,700 And we can put that all into one if statement as well. 83 00:04:05,700 --> 00:04:08,408 It's just a little bit more readable in this particular instance. 84 00:04:08,408 --> 00:04:11,220 But this collides function should get us as far as we need to go. 85 00:04:11,220 --> 00:04:13,590 Now, we'll return to main. 86 00:04:13,590 --> 00:04:17,589 And here, sort of in the update function is where we really want to test this. 87 00:04:17,589 --> 00:04:23,730 So I can just add some code here that says, if ball collides with paddle 1, 88 00:04:23,730 --> 00:04:27,420 let's say, then I want to do something here. 89 00:04:27,420 --> 00:04:31,678 I want to deflect the ball to the-- 90 00:04:31,678 --> 00:04:32,470 that's on the left. 91 00:04:32,470 --> 00:04:35,303 So we're going to say we are going to deflect the ball to the right. 92 00:04:35,303 --> 00:04:43,780 And if ball collides with paddle 2, then I want to deflect the ball to the left. 93 00:04:43,780 --> 00:04:47,100 So in order to do that-- so we know that things move with an x 94 00:04:47,100 --> 00:04:51,780 and a y velocity, the ball if it's going towards paddle 1 which is there 95 00:04:51,780 --> 00:04:57,120 for you, if it's going towards paddle 1, it has an x velocity of negative 100 96 00:04:57,120 --> 00:04:57,840 in this case. 97 00:04:57,840 --> 00:05:00,670 So we want to change that to positive 100. 98 00:05:00,670 --> 00:05:03,880 So to do that, all we have to do is just say, 99 00:05:03,880 --> 00:05:08,950 ball.dx is equal to negative ball.dx. 100 00:05:08,950 --> 00:05:11,140 And actually, this works either way. 101 00:05:11,140 --> 00:05:13,390 So we can say like that. 102 00:05:13,390 --> 00:05:15,970 So it's just going to reflect the ball either way. 103 00:05:15,970 --> 00:05:24,320 And really, this exact line of code actually applies in both ways. 104 00:05:24,320 --> 00:05:27,940 Now, what we can do as well, if the ball collides, what we want to do is 105 00:05:27,940 --> 00:05:30,400 not only deflect it back towards the right, 106 00:05:30,400 --> 00:05:33,430 but also keep the y velocity going the same way, which 107 00:05:33,430 --> 00:05:37,720 is really already going to happen by virtue of it already having. 108 00:05:37,720 --> 00:05:41,260 So let's say if it's going up, it's going to have a negative y velocity. 109 00:05:41,260 --> 00:05:43,360 So by shifting it back towards the direction, 110 00:05:43,360 --> 00:05:44,870 that y velocity will be maintained. 111 00:05:44,870 --> 00:05:47,328 So actually, we don't need to change the y velocity at all. 112 00:05:47,328 --> 00:05:51,250 Though the dx is all that needs to be flipped, essentially. 113 00:05:51,250 --> 00:05:53,773 So not only do we need to worry about the falls. 114 00:05:53,773 --> 00:05:56,440 But we should also worry about the top and bottom of the screen. 115 00:05:56,440 --> 00:05:58,993 So that's a little bit of a different case. 116 00:05:58,993 --> 00:06:00,910 Since there is nothing really moving, we don't 117 00:06:00,910 --> 00:06:04,540 have to worry about anything like that, we can just literally take the y value 118 00:06:04,540 --> 00:06:06,260 and be concerned about that. 119 00:06:06,260 --> 00:06:11,260 So let's just say, if ball.y is less than or equal to 0, 120 00:06:11,260 --> 00:06:17,748 which will be at the top of the screen, then I want to deflect the ball down. 121 00:06:17,748 --> 00:06:19,540 Well, to do that, all we have to do is just 122 00:06:19,540 --> 00:06:22,240 say ball.dy is equal to negative ball.dy. 123 00:06:22,240 --> 00:06:23,840 It's as simple as that. 124 00:06:23,840 --> 00:06:33,160 And if the ball.y is greater than or equal to virtual height minus 4-- 125 00:06:33,160 --> 00:06:35,720 because remember, the ball is 4 pixels tall. 126 00:06:35,720 --> 00:06:39,100 So we want to account for that by offsetting where it's checking 127 00:06:39,100 --> 00:06:41,380 for the collision by 4 pixels up-- 128 00:06:41,380 --> 00:06:47,140 then ball.dy is equal to negative ball.dy. 129 00:06:47,140 --> 00:06:50,170 And in addition, it's possible that the ball might 130 00:06:50,170 --> 00:06:53,020 move actually a little bit up above 0. 131 00:06:53,020 --> 00:06:55,300 And so by setting the velocity, we don't really 132 00:06:55,300 --> 00:06:57,740 account for putting it back into play. 133 00:06:57,740 --> 00:06:59,680 For example, between one frame and another, 134 00:06:59,680 --> 00:07:01,480 we might move a few pixels above the edge, 135 00:07:01,480 --> 00:07:05,575 and so therefore see the ball sort of go above the top edge of the screen. 136 00:07:05,575 --> 00:07:09,373 What we want to do is reset the ball back down into the playfield 137 00:07:09,373 --> 00:07:10,790 as soon as it hits that collision. 138 00:07:10,790 --> 00:07:14,080 So what we can do is we can say ball.y is equal to 0 139 00:07:14,080 --> 00:07:16,460 in the case of it hitting the top of the screen. 140 00:07:16,460 --> 00:07:22,780 We can then say, here ball.y is equal to virtual height minus 4 in the case 141 00:07:22,780 --> 00:07:25,530 that it hits the bottom edge of the screen. 142 00:07:25,530 --> 00:07:27,670 So let's go ahead and test this out really quickly. 143 00:07:27,670 --> 00:07:29,290 Local box is a null value. 144 00:07:29,290 --> 00:07:33,610 Ball 31, let me go ahead and see where I have that. 145 00:07:33,610 --> 00:07:37,750 So box.y function ball collides. 146 00:07:37,750 --> 00:07:43,330 Box.y, box.width, so we are taking in a box. 147 00:07:43,330 --> 00:07:45,310 So let's go over back to main. 148 00:07:45,310 --> 00:07:48,670 Ball collides, paddle 1, paddle 2. 149 00:07:48,670 --> 00:07:53,440 And we do indeed have the collides function here. 150 00:07:53,440 --> 00:07:58,170 Unless I am just missing something completely wrong, 151 00:07:58,170 --> 00:08:00,610 let me just run this one more time. 152 00:08:00,610 --> 00:08:03,120 Oh, it's getting past a null value, OK. 153 00:08:03,120 --> 00:08:07,540 So that means that here in our code, we're actually giving it a null value. 154 00:08:07,540 --> 00:08:12,000 So ball collides with paddle 1 and paddle 2. 155 00:08:12,000 --> 00:08:14,970 Let me just make sure, oh, because it's player 1 and player 2. 156 00:08:14,970 --> 00:08:15,480 My bad. 157 00:08:15,480 --> 00:08:17,260 OK, I apologize for that. 158 00:08:17,260 --> 00:08:20,430 Let's go ahead and set that to player 1 and player 2, not paddle 1 159 00:08:20,430 --> 00:08:21,360 and paddle 2. 160 00:08:21,360 --> 00:08:22,350 That is my mistake. 161 00:08:22,350 --> 00:08:23,520 Let's re-run that. 162 00:08:23,520 --> 00:08:25,680 And we see white here. 163 00:08:25,680 --> 00:08:29,070 So again, I have a love.graphics.clear call. 164 00:08:29,070 --> 00:08:33,989 That needs to be corrected just down here. 165 00:08:33,989 --> 00:08:36,900 So let's divide that 255. 166 00:08:36,900 --> 00:08:38,325 Divide by 255. 167 00:08:38,325 --> 00:08:39,275 Divide by 255. 168 00:08:39,275 --> 00:08:40,635 And divide by 255. 169 00:08:40,635 --> 00:08:41,970 We'll fix that. 170 00:08:41,970 --> 00:08:43,409 Save it, run it. 171 00:08:43,409 --> 00:08:44,680 And let's test it. 172 00:08:44,680 --> 00:08:46,225 So let's see if it bounces. 173 00:08:46,225 --> 00:08:47,350 Oh, it bounced off the top. 174 00:08:47,350 --> 00:08:48,420 Let's see if it bounces off the bottom. 175 00:08:48,420 --> 00:08:49,530 It bounced off the bottom. 176 00:08:49,530 --> 00:08:51,250 And lastly, it bounced off the paddle. 177 00:08:51,250 --> 00:08:52,230 OK, perfect. 178 00:08:52,230 --> 00:08:55,620 So everything works really well minus the little graphical issue there. 179 00:08:55,620 --> 00:08:57,180 So that is collision detection. 180 00:08:57,180 --> 00:08:57,930 It's that simple. 181 00:08:57,930 --> 00:09:00,630 We'll just check to see whether one edge is 182 00:09:00,630 --> 00:09:03,600 sort of to the opposite side of the opposite edge. 183 00:09:03,600 --> 00:09:07,382 So in other words, make sure the left edge is to the right of the right edge, 184 00:09:07,382 --> 00:09:08,340 and so on and so forth. 185 00:09:08,340 --> 00:09:13,320 And just because of geometric space, it ends up being that ensures-- 186 00:09:13,320 --> 00:09:17,010 assuming there's no rotation on our rectangles 187 00:09:17,010 --> 00:09:18,860 that things have or have not collided. 188 00:09:18,860 --> 00:09:21,448 And it's a very simple, easy calculation to add. 189 00:09:21,448 --> 00:09:22,740 So that was it for this update. 190 00:09:22,740 --> 00:09:25,110 In the next update, we're going to take a look at actually detecting 191 00:09:25,110 --> 00:09:27,568 whether the ball goes past the left or the right edge which 192 00:09:27,568 --> 00:09:28,860 we haven't actually done yet. 193 00:09:28,860 --> 00:09:32,523 And if we kept playing, we would see the ball keep going forever into that edge. 194 00:09:32,523 --> 00:09:34,440 And so in the next update, we're going to look 195 00:09:34,440 --> 00:09:39,420 at adding a score when it gets past the left side or the right side. 196 00:09:39,420 --> 00:09:44,620 And then move towards the end of actually creating a win condition. 197 00:09:44,620 --> 00:09:47,500 So we'll see you then in Pong 8. 198 00:09:47,500 --> 00:09:48,000