With our paddles and ball moving in the previous tutorial, the next step is to allow the two to interact with one another. We will do this with some very basic collision detection. We must first determine the moment when a paddle collides with a ball, or the ball collides with a wall, and then decide how to react when that happens.

First, let’s handle ball-and-wall collisions. The top and bottom edges of our stage are effectively going to be walls, despite the fact that we don’t actually see them. When the ball touches the top or bottom borders of our game, we want the ball to bounce.

In PDGame.cs, edit the Update function of the PDGame class to reflect the code below.

You can find the code used to detect and handle wall collisions by finding the commented line for it. We take the new y value of our ball, add half the balls height, and determine if it is greater or equal to the y value of the top border of the screen. Why do we add half the height of the ball? The anchor and origin for our ball is, by default, set to its center. If we just used the y value of the ball, we would be checking to see if the center of the ball collided with the wall. What we really need to do is check if the top of the ball collides with the wall. In the same if statement, we check to see if the bottom of our ball has collided with the bottom wall. When a collision is detected, the y velocity will be reversed, effectively mirroring the angle at which the ball struck the wall.

UPDATE: In the ball-and-wall collision check, I changed this to prevent rapid collisions. This is not reflected in the webplayer demo or the assets file, but it is reflected now in the code above. I changed this during Part 8 of the tutorial series, so the next webplayer demo and assets file will not have the new collision code either.

Unfortunately, we can’t really test this collision test yet because our ball will never start at an angle that hits a wall. We will need to get the paddle collision detection working first.

The first thing we do is create copies of the rectangles that define the bounds of our sprites at their current locations. In other words, for the purposes of collision detection, we create virtual rectangles (we don’t draw them) that represent the area occupied by our sprites. This is an incredibly basic aspect of collision detection that you should already be familiar with, since teaching this is not within the scope of these tutorials.

We then use the CheckIntersect method to determine if any point on the ball collides with any point on the paddle. The xVelocity is reversed, reflecting the angle at which the ball came in at. Go ahead and execute the code, and you should be able to see the ball bounce off the walls and paddles.

It shouldn’t take long for you to notice a few issues. First, the only thing you can achieve with the paddle is reflecting the ball’s angle. To be fun, you need to be able to ‘aim’ the ball depending upon where it strikes the paddle. Second, if the ball hits the top of a paddle, there is a good chance that the ball will react erratically, ping-ponging back and forth in collision hell. That is because multiple collisions are occurring with the same paddle over and over again.

The latter problem is easy to fix in a hackish manner by changing the if statements to the following.

All this does is ensure that the paddle will only collide with the ball once per volley by checking the direction of the ball. There may be better ways to achieve this, mind you. For discussion purposes, if anyone would like to suggest a different method, post it in the comments for others to learn.

As for being able to direct the ball with the paddle, many Pong games disregard the incoming angle, and assign a new one depending on where the ball strikes the paddle. We’ll be doing the same. First, in your PDGame class, create a BallPaddleCollision function from the code below.

public void BallPaddleCollision(PDPaddle player, float newBallY, float newPaddleY) {
float localHitLoc = newBallY - newPaddleY; // Where did the ball hit, relative to the paddle's center?
float angleMultiplier = Mathf.Abs(localHitLoc / (player.height/2)); // Express local hit loc as a percentage of half the paddle's height
// Use the angle multiplier to determine the angle the ball should return at, from 0-65 degrees. Then use trig functions to determine new x/y velocities. Feel free to use a different angle limit if you think another one works better.
float xVelocity = Mathf.Cos(65.0f * angleMultiplier * Mathf.Deg2Rad) * ball.currentVelocity;
float yVelocity = Mathf.Sin(65.0f * angleMultiplier * Mathf.Deg2Rad) * ball.currentVelocity;
// If the ball hit the paddle below the center, the yVelocity should be flipped so that the ball is returned at a downward angle
if (localHitLoc < 0) {
yVelocity = -yVelocity;
}
// If the ball came in at an xVelocity of more than 0, we know the ball was travelling right when it hit the paddle. It should now start going left.
if (ball.xVelocity > 0) {
xVelocity = -xVelocity;
}
// Set the ball's x and y velocities to the newly calculated values
ball.xVelocity = xVelocity;
ball.yVelocity = yVelocity;
}

BallPaddleCollision takes the paddle/player that has collided with the ball, as well as the ball and paddle’s new y positions as parameters. The commentes in the code should explain what is happening, but in a nutshell, the further from the center of the paddle that the ball hits, the wider the angle, up to a maximum of 65 degrees. If hit its above the center of the paddle, the ball will be angled up, and if it hits below the center of the paddle, it will be angled down.

Finally, in order to put this function into play, we need to edit our collision checks to make a call to it.

Execute the code and give it a look. Our Pong game is starting to take the form of a game. I chose to change the ball’s velocity to 200.0f since it was a bit slow, and you can do the same if you’d like. Both players can interact with the ball, and even though there are no win conditions present, a player can still ‘win.’ The next tutorial will address this issue, as well as covering scoring and the user interface.

Your solution to the “collide once per volley” problem seems fine to me, but another common approach is to push the ball out of the paddle by the intersection amount (essentially making it stop intersecting). It’d look something like this, when the intersection happens:

This approach is definitely cleaner, and the concept can similarly be applied to the ball’s y value when striking a wall, since there is no sanity check there. If I find the time I’ll change the post to reflect it.

When I was going through this, I noticed that the paddles kept going off screen. It was driving me crazy, so I added a little extra code for Paddle-to-Wall collisions. Its a pretty simple solution, but I feel like it makes the game a bit more playable. Sorry if you intend to cover this later and I’m spoiling the surprise =D. Anyway, I pasted the code below. It just checks to make sure the new position isn’t out of the screen. If it is, it sets it to a max y postion (the top of the screen.)

Hi Gary, you definitely didn’t spoil anything. This is one of those things that I sort of left to the imagination of the developer. I definitely should have taken a few seconds to throw it in there tough.