COLTON OGDEN: So Pong 6 was a little bit on the simpler side.
All we did was add a string to the top left.
That measured our FPS.
So nice to have if you want to measure how well your game is
running on a particular system.
It's not particular sophisticated, but it was a nice little reprieve.
Pong 7 is a little bit meatier in that now we're
going to get a little bit of more interesting functionality in our game
with collision detection.
Now, again, you can't really see it in this slide.
But what we're going to do is have it so that the ball can move and collide,
not only with the paddles but also with the up and down edges of the screen.
And now what I realized, in the last section,
we didn't actually implement love dot window
dot set title, so we're going to do that in this section as well.
So in order to get to that, we need to talk about how to actually collide
two rectangles together.
And fortunately, it's pretty easy in the context of what
are called axis-aligned bounding boxes.
And that just means that we have rectangles on our screen
that are aligned, not rotated at all to our x,
or our y and our x-axes in our coordinate system.
And in order to test whether two rectangles are colliding,
we really just need to really test to see whether or not one edge of another
is not touching or beyond the opposite edge of the other rectangle.
And to illustrate this, I have a slide here
that sort of shows two rectangles that are colliding.
And you can see that for example, this side here is within this side.
It's to the left of that side.
But it suffices.
If we do a check on each edge of the rectangle, so for example,
this edge here, this left edge of this right rectangle,
if we know that it's to the right of this edge,
well, then there can't be a collision no matter what.
It's just impossible for that to happen.
The same thing if this edge is above this edge.
In other words, if the opposite edges are disjointed,
then there's no collision.
It's not possible.
So if you do a check for each of the four edges,
by virtue of that, the simplicity of that,
then you're guaranteed to not have a collision.
And that's how you do a simple axis-aligned bounding box collision.
And that's really all of the mental framework
we'll establish before we get into it.
Now, let's just actually implement that code.
So I'm going to go here into my distro.
And what I want to do is I want to have a function in the ball class
that will actually check to see whether it's colliding
with some other entity which we assume is going
to have an xy, a width and a height.
In this case, it will be our paddles.
And we'll check to see whether the ball collides
with paddle one and paddle two.
We'll do that from main.
But we need to actually have the function that does that.
So I'm going to say it's going to be a function called collides.
It's going to return a Boolean.
And it's going to take--
let's just say box as our argument here.
And what we can do is as I just described,
check to see whether or not the edge of our ball
is disjointed from the opposite edge.
In other words, if it's the left edge, check
to see whether it's to the right of the right edge of the other box.
If it is, well, then it's an impossible collision.
So we'll just say, if self.x is greater than box.x plus box.width--
because remember, everything is relative to its top left corner.
The x is relative to the top left.
So we want to add the width to check to see
whether our x, our left side basically, is to the right of the other box.
If it's greater than the other box's right edge.
So if it's greater than the box.x plus the box.width or our self.x
plus self.width is less than the box.x, then return false.
So it doesn't collide.
It's an impossibility.
And likewise for y, so if self.y is greater
than box.y plus box.height or self.y plus self.height is less than box.y,
then return false.
Otherwise, we can return true.
And we can put that all into one if statement as well.
It's just a little bit more readable in this particular instance.
But this collides function should get us as far as we need to go.
Now, we'll return to main.
And here, sort of in the update function is where we really want to test this.
So I can just add some code here that says, if ball collides with paddle 1,
let's say, then I want to do something here.
I want to deflect the ball to the--
that's on the left.
So we're going to say we are going to deflect the ball to the right.
And if ball collides with paddle 2, then I want to deflect the ball to the left.
So in order to do that-- so we know that things move with an x
and a y velocity, the ball if it's going towards paddle 1 which is there
for you, if it's going towards paddle 1, it has an x velocity of negative 100
in this case.
So we want to change that to positive 100.
So to do that, all we have to do is just say,
ball.dx is equal to negative ball.dx.
And actually, this works either way.
So we can say like that.
So it's just going to reflect the ball either way.
And really, this exact line of code actually applies in both ways.
Now, what we can do as well, if the ball collides, what we want to do is
not only deflect it back towards the right,
but also keep the y velocity going the same way, which
is really already going to happen by virtue of it already having.
So let's say if it's going up, it's going to have a negative y velocity.
So by shifting it back towards the direction,
that y velocity will be maintained.
So actually, we don't need to change the y velocity at all.
Though the dx is all that needs to be flipped, essentially.
So not only do we need to worry about the falls.
But we should also worry about the top and bottom of the screen.
So that's a little bit of a different case.
Since there is nothing really moving, we don't
have to worry about anything like that, we can just literally take the y value
and be concerned about that.
So let's just say, if ball.y is less than or equal to 0,
which will be at the top of the screen, then I want to deflect the ball down.
Well, to do that, all we have to do is just
say ball.dy is equal to negative ball.dy.
It's as simple as that.
And if the ball.y is greater than or equal to virtual height minus 4--
because remember, the ball is 4 pixels tall.
So we want to account for that by offsetting where it's checking
for the collision by 4 pixels up--
then ball.dy is equal to negative ball.dy.
And in addition, it's possible that the ball might
move actually a little bit up above 0.
And so by setting the velocity, we don't really
account for putting it back into play.
For example, between one frame and another,
we might move a few pixels above the edge,
and so therefore see the ball sort of go above the top edge of the screen.
What we want to do is reset the ball back down into the playfield
as soon as it hits that collision.
So what we can do is we can say ball.y is equal to 0
in the case of it hitting the top of the screen.
We can then say, here ball.y is equal to virtual height minus 4 in the case
that it hits the bottom edge of the screen.
So let's go ahead and test this out really quickly.
Local box is a null value.
Ball 31, let me go ahead and see where I have that.
So box.y function ball collides.
Box.y, box.width, so we are taking in a box.
So let's go over back to main.
Ball collides, paddle 1, paddle 2.
And we do indeed have the collides function here.
Unless I am just missing something completely wrong,
let me just run this one more time.
Oh, it's getting past a null value, OK.
So that means that here in our code, we're actually giving it a null value.
So ball collides with paddle 1 and paddle 2.
Let me just make sure, oh, because it's player 1 and player 2.
My bad.
OK, I apologize for that.
Let's go ahead and set that to player 1 and player 2, not paddle 1
and paddle 2.
That is my mistake.
Let's re-run that.
And we see white here.
So again, I have a love.graphics.clear call.
That needs to be corrected just down here.
So let's divide that 255.
Divide by 255.
And divide by 255.
We'll fix that.
Save it, run it.
And let's test it.
So let's see if it bounces.
Oh, it bounced off the top.
Let's see if it bounces off the bottom.
It bounced off the bottom.
And lastly, it bounced off the paddle.
OK, perfect.
So everything works really well minus the little graphical issue there.
So that is collision detection.
It's that simple.
We'll just check to see whether one edge is
sort of to the opposite side of the opposite edge.
So in other words, make sure the left edge is to the right of the right edge,
and so on and so forth.
And just because of geometric space, it ends up being that ensures--
assuming there's no rotation on our rectangles
that things have or have not collided.
And it's a very simple, easy calculation to add.
So that was it for this update.
In the next update, we're going to take a look at actually detecting
whether the ball goes past the left or the right edge which
we haven't actually done yet.
And if we kept playing, we would see the ball keep going forever into that edge.
And so in the next update, we're going to look
at adding a score when it gets past the left side or the right side.
And then move towards the end of actually creating a win condition.
So we'll see you then in Pong 8.