Hello again!
In this video, we are going to look at how to make the ball interact with the bricks, in our game.
The idea is this when the ball hits a brick, that brick
will be destroyed. And the ball will bounce off the brick, at a physically credible-looking angle.
So to do that, we are going to delete the brick object from the vector.
You remember that the program has this vector of brick objects.
And every time it displays the window, it goes through this vector and displays each brick.
So if we delete a brick from the vector, then that brick can never be displayed again.
To implement this, we need to make some changes to the entity hierarchy.
We need to make the ball move down, as well as up and sideways.
So we add a move_down() member function to the moving_entity class.
We also need to know whether the brick has been destroyed.
So we are going to add a member, to store that status. And also member functions, for accessing the
status.
And for reasons which I will explain in a moment, we need to be able to find the edges of the sprite.
We have looked at handling collisions before, between the ball and the paddle, and that was fairly straightforward.
We could assume that the board was only come from above the paddle, and we only cared if the ball hit
the left side of the paddle, or the right side. With a brick,
it is more complicated.
The brick has four edges, and also the ball can come from any one of four different directions.
The solution I am going to use is to look at the overlaps between the edges of the ball, and the edges
of the brick.
So, for example, we have an overlap between the left edge of the brick and the right edge of the ball.
There is also the overlap between the left edge of the ball and the right edge of the brick.
And this left overlap is much smaller than the right overlap.
So this tells us that the ball hits the left edge of the brick, and not the right side.
And we can use similar logic for the top and the bottom.
So we need to calculate all these overlaps.
The left overlap, the right overlap. The top overlap, from the top of the brick to the bottom edge
of the ball. And the bottom overlap, from the top edge of the ball to the bottom edge of the brick.
And then if the left overlap is less than the right overlap, we know the ball hit on the left. And
so on, for the others.
However, it is possible for the ball to hit two sides, if it comes in to one of the corners.
So in this case, we look at the left/right overlap and the top/bottom overlap, and the left/right overlap
is smaller.
So we regard this as a hit on the left side, and not a hit on the bottom.
So when the ball bounces, we expect the ball to go to the left.
I have made a change to constants, which is just for this video. It is just to slow the ball down, so
I can talk between collisions.
You do not need to make this change in your own code. In the entity class,
we have this member which will tell us if the brick has been destroyed.
We have these helper functions for getting the edges of the sprite, and we also have the accessor
functions for the status.
In the entity implementation.
We have the implementation of these member functions.
So we get the bounding box. And then we go, from the centre of the box, to the edge that we want.
Remember that I redefined the origin, so the origin returned by x() and y() is the centre of the bounding
box.
So if we go from the centre of the box and we move left, by half the width of the box, then we get
to the left side of the box.
If we start in the middle and move right by half the width of the box, then we get the right edge
of the box.
And if we move up by half the height, we get the top and so on.
We need to implement this move_down() member function in the moving_entity objects. So that is ball and
paddle. In ball, we just do the opposite of moving up.
So instead of making the "y" member of velocity negative, we make it positive.
And in paddle. The paddle, cannot move up and down.
So these are both empty functions.
In the interactions header,
we need to add the overload for the ball and the brick.
This can modify the brick object, so we just use a reference, and not a const reference.
In the main function, we do the updates. And then we handle the collision between the ball and the paddle,
and then we iterate over all the bricks. And we handle the collision between the ball and each brick.
And we need to use a reference for the loop variable, because we want to modify the actual brick, and not
a copy of the brick object.
So if there are any collisions, then the brick objects in this vector will be marked as destroyed.
And then we need to remove all these destroyed bricks from the vector. So we can call the remove_if()
algorithm. We provide the begin() and end() for the vector
as the iterators. And then we have a predicate which returns the destroyed status.
So this will move all the destroyed bricks to the end of the vector, and it will return an iterator
to the first destroyed brick.
And then we can use the return value as the first iterator to a call to erase. And then we can pass end()
as the second iterator.
And that will actually delete the brick objects from that vector.
So when we draw the window, the destroyed bricks will no longer appear.
For the actual collision code.
Again, we first check if there is a collision. And if there is no collision, then we return straightaway.
If there is a collision, then we mark the brick as destroyed and then we calculate the overlaps.
So the left overlap is from the right edge of the ball to the left edge of the brick. And the same for all
the others.
And if the left overlap is less than the right overlap, then we struck on the left, otherwise the
right. And the same for top and bottom.
And then, if we have an ambiguous case, if the overlap at the side is less than the overlap at the top
or bottom, then we make the ball move to the side.
So if the ball came from the left, we make it bounce to the left, otherwise it bounces to the right.
If the top or bottom overlap is smaller, then the ball bounces upwards, if it came from the top, and
it bounces downwards, if it came from the bottom.
So here we are, with the ball moving at sixth of the normal speed.
It looks like we are playing this on the moon! But it does give us time to see what is happening.
So there we are.
The ball came in here.
So that was on the bottom.
So it bounced downwards. The bottom overlap was the smallest, not the left or the right or the top.
That one came in from the right, so it bounced to the right. And there were some others, which I missed,
because I was too busy talking!
And then down we go.
And back.
And where is this one going?
So.
That was over there.
So that was on the bottom.
So that bounced downwards
again.
And so on.
Okay.
I think you get the idea.
So that is it for this video.
I will see you next time.
Until then, keep coding!