# Making a Pong ball reflect off the paddle

I am currently making Pong in C++/SDL2 and after a while of tinkering, I have come up with a solution!

This function gets the hit position and returns the necessary direction change:

MoveDirection Ball::getHitPos(const Player& player) const
{
MoveDirection dir; //Direction of movement

//If ball is moving left
if (m_dir == MoveDirection::LEFT)
{
std::cout << "Yes";
int hitPos = m_pos.y - player.getPos().y; //Get hit position
int playerSize = player.getPos().h / 2;
int offSet = 25; //Enables to split up positions into three seperate parts
//Calculate dir change
if (hitPos <= playerSize - offSet) {
dir = MoveDirection::RIGHTUP;
}
else if (hitPos >= playerSize + offSet) {
dir = MoveDirection::RIGHTDOWN;
}
else {
dir = MoveDirection::RIGHT;
}
}

//If Ball is moving right
if (m_dir == MoveDirection::RIGHT)
{
int hitPos = m_pos.y - player.getPos().y; //Get hit position
int playerSize = player.getPos().h / 2;
int offSet = 25; //Enables to split up positions into three seperate parts
//Calculate dir change
if (hitPos <= playerSize - offSet) {
dir = MoveDirection::LEFTUP;
}
else if (hitPos >= playerSize + offSet) {
dir = MoveDirection::LEFTDOWN;
}
else {
dir = MoveDirection::LEFT;
}
}

return dir;
}


Here are all of the possible movement directions:

enum class MoveDirection
{
UP,
DOWN,
LEFT,
RIGHT,
LEFTUP, //Ball diagonal movement
LEFTDOWN, //Ball diagonal movement
RIGHTUP, //Ball diagonal movement
RIGHTDOWN //Ball diagonal movement
};


And here is the height of the racket:

static constexpr int SIZE_HEIGHT = 75;


I must also note that m_pos is SDL_RECT and player.getPos().y is getting the y element of SDL_RECT.

• Is this real code? The function calculates dir and then discard the result. – Edward Mar 18 '16 at 20:24
• Oh! Oops, sorry that was there for test purposes on the actual function its self. Sorry! I thought I uploaded the working one, my mistake. – Ryan Swann Mar 18 '16 at 21:09

Your ball can only move in the eight (semi)cardinal directions? It can't move at, say, a 30-degree angle?

Well, even so, it will simplify your code to treat the ball as if it can move in any direction. Either:

struct MoveDirection {
double angle;
double speed;
};


or more likely:

struct MoveDirection {
double vx;
double vy;
};


And then rewrite your getHitPos function as something more like

MoveDirection Ball::getHitPos(const Player& player) const
{
MoveDirection dir; //Direction of movement

//If ball is moving left
if (m_dir.vx < 0)
{
std::cout << "Yes";
int hitPos = m_pos.y - player.getPos().y; //Get hit position
int playerSize = player.getPos().h / 2;
int offSet = 25; //Enables to split up positions into three seperate parts
//Calculate dir change
dir.vx = +1;
if (hitPos <= playerSize - offSet) {
dir.vy = +1;
}
else if (hitPos >= playerSize + offSet) {
dir.vy = -1;
}
else {
dir.vy = 0;
}
}
else if (m_dir.vx > 0)  // ball is moving right
...


Then just keep refactoring and turning branches into arithmetic expressions until you're happy. It might end up looking something like

MoveDirection result;
result.vx = -m_dir.vx;
const double hitPos = m_pos.y - player.getPos().y; //Get hit position
const double playerSize = player.getPos().h / 2;
result.vy = (hitPos > playerSize + 25) - (hitPos < playerSize - 25);
return result;


## Think carefully about object responsibilities

It seems peculiar to me that Ball is responsible for determining where on the Player it has hit. I'd suggest refactoring so that yo have the paddle divided into regions and have a Player member enum class and function like this:

enum class PaddleRegion { LOW, MID, HI};


## Make your class more data-centric

The resulting direction is a function of the original direction of the ball and the region in which it hit. None of these is dynamic. That is, given a direction and region, the output will always be the same. This suggests that perhaps the Ball class could instead incorporate a static table like this:

class Ball {
// other stuff...
struct Rebound {
MoveDirection incomingDir;
MoveDirection outgoingDir;
};
const static Rebound bounce[];
};


It could then be populated like this:

const Ball::Rebound Ball::bounce[]
{
};


Now the code for Ball::getHitPos() looks like this:

MoveDirection Ball::getHitPos(const Player& player) const {