Ok, I admit outright, this part was a long time in releasing and I apologize for that. A big part of the reason for the delay is in my first few drafts I attempted to teach the mathematics behind this chapter, which I initially believe would be a minor task., I was wrong. Teaching mathematics requires so much prior knowledge that I cannot safely assume you have, but once you start getting into one subject you realize you have to explain a few dozen others before it makes sense. After a few dozen attempts I did the pragmatic thing… I gave up. So in this chapter there is some relatively basic math that will be lacking a detailed explanation of “why” it works. Frankly it is a (massive) topic all it’s own. As a result I will scour the net and various books and put together a reference post on math for game programmers at some point in the future.
Alright, that covers what this chapter isn’t, lets get into what it is. In this chapter we will set the ball in motion and add some basic collision detection. We are also going to cover C++ casting but other than that, there isn’t much new C++ coverage this chapter. The physics are a little bit more involved than a typical pong clone, but nothing too complex. For the most part, all of this logic is going to take place in the GameBall class, but first we need to make some basic changes to it’s base class VisibleGameObject. First lets open up VisibleGameObject.h and we want to add the following:
virtual float GetWidth() const;
virtual float GetHeight() const;
virtual sf::Rect<float> GetBoundingRect() const;
Click here to download VisibleGameObject.h
Now we need to implement these changes in VisibleGameObject.cpp:
float VisibleGameObject::GetHeight() const
float VisibleGameObject::GetWidth() const
sf::Rect<float> VisibleGameObject::GetBoundingRect() const
sf::Vector2f size = _sprite.GetSize();
sf::Vector2f position = _sprite.GetPosition();
position.x - size.x/2,
position.y - size.y/2,
position.x + size.x/2,
position.y + size.y/2
Click here to download VisibleGameObject.cpp
The first two methods are super straight forward accessor methods which we will be calling a lot. Another reason for these methods existence is I personally find SFML’s use of x and y for width and height very unintuitive.
The GetBoundingRect() method simply returns a rectangle that defines the boundaries of our sprite. We will use this quite often for checking for collisions. Keep in mind that the results are in screen space coordinates and since we used SetCenter to define our sprites position to be relative to it’s middle as opposed to it’s top left corner, we obtain the four corners of the rectangle by add and subtracting half the width or height of the sprite relative to it’s current position.
As I said earlier, the majority of the changes occur in the GameBall class. Previously it was mostly just a stub, now we are going to add a great deal more functionality. The GameBall is going to be in charge of determining if a collision occurred and eventually much more. Open up GameBall.h and add the edit it as follows:
class GameBall :
float LinearVelocityX(float angle);
float LinearVelocityY(float angle);
Click here to download GameBall.h
Notice that now instead of letting our base class VisibleGameObject handle Update(), we are overriding it and implementing it ourselves. As you will see shortly, Update is where the majority of changes took place. Beyond that, we added a couple private member variables, _velocity, _angle and _elapsedTimeSinceStart, as well as the two functions LinearVelocityX and LinearVelocityY. Let’s take a look at their implementation below in GameBall.cpp:
_angle = (float)sf::Randomizer::Random(0,360);
void GameBall::Update(float elapsedTime)
_elapsedTimeSinceStart += elapsedTime;
// Delay game from starting until 3 seconds have passed
if(_elapsedTimeSinceStart < 3.0f)
float moveAmount = _velocity * elapsedTime;
float moveByX = LinearVelocityX(_angle) * moveAmount;
float moveByY = LinearVelocityY(_angle) * moveAmount;
//collide with the left side of the screen
if(GetPosition().x + moveByX <= 0 + GetWidth()/2
|| GetPosition().x + GetHeight()/2 + moveByX >= Game::SCREEN_WIDTH)
_angle = 360.0f - _angle;
if(_angle > 260.0f && _angle < 280.0f) _angle += 20.0f;
if(_angle > 80.0f && _angle < 100.0f) _angle += 20.0f;
moveByX = -moveByX;
PlayerPaddle* player1 =
if(player1 != NULL)
sf::Rect<float> p1BB = player1->GetBoundingRect();
_angle = 360.0f - (_angle - 180.0f);
if(_angle > 360.0f) _angle -= 360.0f;
moveByY = -moveByY;
// Make sure ball isn't inside paddle
if(GetBoundingRect().Bottom > player1->GetBoundingRect().Top)
SetPosition(GetPosition().x,player1->GetBoundingRect().Top - GetWidth()/2 -1 );
// Now add "English" based on the players velocity.
float playerVelocity = player1->GetVelocity();
if(playerVelocity < 0)
// moving left
_angle -= 20.0f;
if(_angle < 0 ) _angle = 360.0f - _angle;
else if(playerVelocity > 0)
_angle += 20.0f;
if(_angle > 360.0f) _angle = _angle - 360.0f;
_velocity += 5.0f;
if(GetPosition().y - GetHeight()/2 <= 0)
_angle = 180 - _angle;
moveByY = -moveByY;
if(GetPosition().y + GetHeight()/2 + moveByY >= Game::SCREEN_HEIGHT)
// move to middle of the screen for now and randomize angle
_angle = (float)sf::Randomizer::Random(0,360);
_velocity = 220.0f;
_elapsedTimeSinceStart = 0.0f;
float GameBall::LinearVelocityX(float angle)
angle -= 90;
if (angle < 0) angle = 360 + angle;
return (float)std::cos( angle * ( 3.1415926 / 180.0f ));
float GameBall::LinearVelocityY(float angle)
angle -= 90;
if (angle < 0) angle = 360 + angle;
return (float)std::sin( angle * ( 3.1415926 / 180.0f ));
Click here to download GameBall.cpp
Yeah, it’s a bit of a monster at first, but don’t worry, it’s not really all that complex. Lets start at the top with GameBall’s constructor. First of all we initialize _velocity to 230 and _elapsedTimeSinceStart to 0. _velocity represents the speed that ball is going to move. A value of 230 means the ball will move at 230 pixels/second. You can change the game greatly by tweaking this setting. _elapsedTimeSinceStart represents that mount of time ( in seconds ) since the game gameball was created. It’s use will make sense shortly.
Next up is our Update() method, which we will return to later. First lets take a look at LinearVelocityX and LinearVelocityY methods. Each of these methods returns a float denoting how far to move in a given direction given an angle. Remember earlier when I said that explaining the math was well beyond the scope of this tutorial, well, this is one such example! Essentially it all comes down to Pythagoreans theorem. Do you remember back in school when you were taught SohCahToa? Well, now is the time to apply that knowledge!
Essentially the angle –= 90 is make it so in our coordinate system 0 is up instead of to the right. The next if statement makes sure that subtracting 90 from our angle didn’t result in a value like –20 but instead gives us 340 ( 360 degrees – 20 degrees ) for our angle. Now for the math I simply cannot explain. To get the direction of movement in the X direction, you simply take the cosine of the angle. The catch is, you take the cosine of the angle in radians. Radians can basically be thought of as segments of a circle, where an entire circle represents 2 times pi in radians ( or 6.28 rounded), therefore a single radian is 57.3 degrees ( rounded again ). To convert from degrees to radians, we multiple our angle by pi over 180 degrees. Obviously in my example, I rounded off pi rather significantly. To calculate movement by a certain angle in the y direction, you do exactly the same thing, but using Sine instead of the Cosine.
Alright, now that we’ve covered that, lets jump into Update(). The very first thing we do is update _elapsedTimeSinceStart with the elapsedTime that is passed into Update(). Remember that elapsed time is the amount of time since SFML last updated, so it will be a very small number representing a fraction of a second. Next we check that _elapsedTimeSinceStart has reached 3 seconds and if it hasn’t we stop updating until it has. This is so the game doesn’t instantly start the ball moving right when the game starts. If you wanted you could add a count down like “Starting in 3… 2… 1…”, I leave that as an exercise for the reader.
So once _elapsedTimeSinceStart is greater than 3 seconds, we continue through our update and figure out the amount we want the ball to move. This is where our velocity comes in, along with the elapsedTime. Say for example elapsed time is 1/5th a second ( 0.2 ) and given that our _velocity is 230 pixels per second, multiplying _velocity by 0.2 will give up 46 pixels, meaning that to move 230 pixels in a second, in this update we want to move 46 pixels. Like with the paddle, this keeps our speed the same regardless to the speed of the computer we are running on. Generally though elapsed time will be much smaller than 0.2 and Update() will be called many more times a second than 5!
So now that we have the amount to move to maintain our _velocity, when need to determine where we want to move. This is where the results of LinearVelocityX/LinearVelocityY come in. By multiplying the result by our current velocity, we now know how much we want to move in the X and Y directory this frame.
Before we actually move the ball, we check to see if our movement is going to cause a collision of some kind. Remember, since we set our coordinates to be relative to the sprites center as opposed to the top left, we need to add half the sprites width and height to any checks. First we check to see if we hit the left or right side of the screen. For reasons I can’t really explain, instead of making my Pong clone left and right like everyone else, I made Pang vertical. Other than altering the math slightly, it really has no effect.
If our sprite position was going to go off the side of the screen on either the left or right, we ricochet off the side by inverting the angle. For example, if the sprite was going to hit the right side of the screen at 90 degrees, it will ricochet out at 270 degrees. That said, if the sprite did in fact come in to the side at near to a right angle, that is going to result in the ball bouncing back out at nearly a straight line thus boring the hell out of the player as their ball slowly ricochet’s left and right over and over. Therefore if the ball hits either side at +- 10 degrees to straight on, we add 20 degrees to the resulting angle. This has an interesting side effect in that the ball can actually bounce back at the player who hit it, which is actually kind of fun in my opinion, but then I am a big table hockey fan! Finally we flip the sign on the x move amount, so if we were going left ( – ) we are now going right ( + ) and vice versa.
Next we introduce a new C++ concept, the dynamic_cast. Truth told, in this case it is overkill but I wanted to demonstrate the usage. We call Get() on our GameObjectManager looking for a VisibleGameObject named “Paddle1”. If dynamic_cast<> is called on an object that isn’t capable of being casted to the type it’s being asked to cast to, it will return NULL, otherwise it will return a pointer to our game PlayerPaddle object. Since Get() returns a VisibleGameObject pointer, the cast is required if we want to use any of the methods that are specific to the derived PlayerPaddle class. Again, this step really wasn’t required in Pang as we never actually used any methods that are specific to PlayerPaddle, but it is a very valuable thing to learn.
Now that we have a pointer to the player's paddle, we make sure the cast didn't fail and return NULL. If it did return NULL something really bad happened and the Paddle wasn't found. If this actually occurred in a more complex program we would do something much more severe than just skip updating!
Now we want to check if the GameBall is about to collide with the player’s paddle. We do this by getting the bounding box ( a sfml rect ) of the PlayerPaddle and testing if it intersects the GameBall’s bounding rectangle. There is an obvious flaw here, but I can live with it in this example. Our ball is a circle, not a rectangle, so it is possible if the ball was on a certain angle it could report a collision when in fact the corner’s didn’t actually hit. To correct this we would have to check the rect against a bounding circle. This wiki entry has more details on implementing a circle collision test if you are interested.
Once we determine that a collision occurred, we need to decide how the ball will ricochet. This process is very similar to when the ball hit the sides of the screen. Once we calculate the angle the ball will bounce out at we invert the Y direction. If by some fluke the ball actually managed to be inside the bounds of the paddle, we now make sure it is moved above the paddle instead. This also handles the situation where the ball might collide with the side instead of the top of the paddle. It would be more elegant ( and complex ) to check for collision against the top and both sides instead and perform a different result depending on direction.
Next we add “English” to the ball. For those unfamiliar with the term, you can apply “English” to the cue ball in pool based on how you hit it, resulting in certain amount of “spin” on collision. We are doing something similar based on how the player is moving at the time of the collision. If the player is moving to the left ( negative velocity ) we subtract 20 degrees from the ricochet angle, while if the player is moving right ( positive velocity ) we add 20 degrees to the ricochet angle. This step is completely optional, but adds a little variety to the game and gives the player a bit more control over how the ball rebounds. Arkanoids uses a similar system I believe. Finally we increase the velocity by 5 ( pixels / second ) each time the player hits the ball, again just to make things a bit more interesting. In testing I had this set to 50 instead, which made for extremely interesting games!
Now that we have handled a collision with the players paddle, we need to handle the ball hitting the top and bottom of the screen. For now if the ball gets to the top of the screen ( 0 Y ), we simply bounce it back by inverting the angle and direction of the ball. In the case however the ball get’s past the Players paddle, we move the ball back to the middle of the screen, restart the 3 second count down then send the ball back out at a random angle slowed back down to 220 pixels per second. In the future, this is where we would have updated the games score.
Finally, after all the direction calculations, collision detections and angle corrections, we finally move the ball! Now are game has collisions and movement, we are one step closer to a full game. Here now, is Pang in action:
To download the entire project solution click here.
EDIT(5/14/2012): Download SFML 2.0RC project here. This is the above tutorial ported to SFML 2.0. Note, this was ported by a reader. The code will vary slightly from the tutorial above.