pong game ball reflecting (C++ SFML)

Started by
19 comments, last by coope 7 years, 11 months ago

Hello,

Ive researched a lot about this problem but i dont understand their logics about this.

so i have this code


void Ball::update(const sf::RenderWindow& window,Paddle& p1,Paddle& p2,float delta)
{

    if ( isBallCollidedToPaddle(p1) )
    {
        if ( pongball.getPosition().y < p1.getPad().getPosition().y )// if the ball collides to the upper part of player 1 paddle
        {
            if ( angle > 90 && angle < 180 ) 
            {
                angle = 180 - angle;
            }
            else
            {
                angle = -angle;
            }
        }
        else if ( pongball.getPosition().y > p1.getPad().getPosition().y )// if the ball collides to the lower part of player 1 paddle
        {
            if ( angle > 90 && angle < 180 )
            {
                angle = -angle;
            }
            else
            {
                angle = 180 - angle;
            }
        }
    }
    else if ( isBallCollidedToPaddle(p2) )
    {
        if ( pongball.getPosition().y < p2.getPad().getPosition().y ) // if the ball collides to the upper part of player 2 paddle
        {
            if ( angle < 90 && angle > 0 )
            {
                angle = 180 - angle;
            }
            else
            {
                angle = -angle;
            }
        }
        else if ( pongball.getPosition().y > p2.getPad().getPosition().y ) // if the ball collides to the lower part of player2 paddle
        {
            if ( angle < 90 && angle > 0 )
            {
                angle = -angle;
            }
            else
            {
                angle = 180 - angle;
            }
        }
    }

    pongball.move(speed.x * cos(angle*Ball::pi/180)*delta,speed.y * sin(angle*Ball::pi/180)*delta);
}

so far this code is only able to do the basic reflection,I based the reflection from ponggame.org

, but i want to know how to make it reflect as horizontal, for example if the ball collides at the center of the paddle the ball will reflect horizontally, and also the reflection for when the ball collides on the edge of the paddle

some people reflects the ball depends on how far it collides from the middle of the paddle, i dont want to copy paste their computation without understanding it so can anyone elaborate the logic for this way?

thanks and sorry for my english

Advertisement

This looks incorrect in many different ways...

Before launching into all of that, though, what is the angle orientation here? It looks like there's trig going on, which would suggest that 0 is toward X+ (which is rightwards, I hope), but what direction is Y+? Also, which paddle is on which side?

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

thanks for the reply @Khatharr

sorry for late reply it was already 5am when i created this thread.

p1 (player 1 paddle is on left side )

p2 (player 2 paddle is on right side )

Y+ will go to down side

X+ will go to right side

what is the angle orientation here?

what do you mean?


        if ( pongball.getPosition().y < p1.getPad().getPosition().y )// if the ball collides to the upper part of player 1 paddle
        {
            if ( angle > 90 && angle < 180 ) // if the ball was moving at angle between 90 and 180
            {
                angle = 180 - angle; // it should reflect it
            }
            else // if not, then im sure it was moving at angle between 180 and 270
            {
                angle = -angle; // and it should negate it
            }
        }

i put comments to the code, like i said i based the angle reflection from ponggame.org , try play it and you will see it would do same thing

Y+ will go to down side
X+ will go to right side


So 45 degrees points toward the bottom-right corner of the screen?

try play it and you will see it would do same thing


I'm not going to look at (or run) external code due to a lack of interest.



Looking at the last line from OP, I see


speed.x * cos(angle*Ball::pi/180)*delta
speed.y * sin(angle*Ball::pi/180)*delta

Which tells me

  • You like verbose operations rather than saving pi/180 as a constant somewhere.
  • No rotation or flipping is being applied to the trig, so 45 degrees should be down-right or else there's a problem.
  • This operation is wrong anyway because you're multiplying velocity vector elements instead of velocity vector magnitude. (Unless that's there to stretch the board, in which case: Don't do that.)

Then when I look at the segment that you repeated I see:


        if ( pongball.getPosition().y < p1.getPad().getPosition().y ) {
            if ( angle > 90 && angle < 180 ) { 
                angle = 180 - angle;
            }
            else {
                angle = -angle;
            }
        }

You said P1 is on the left, so 90 to 270 could represent a collision against the inward wide face of the paddle. You're using volumetric collision, though, so you're not considering:

  1. What if the ball hits the narrow face of the paddle?
  2. What if the ball hits the paddle and is deflected, but then is still in collision with the paddle on the next frame?

Further, scribbling this on paper I see some problems with the angle manipulation:

90 - 180 degrees is the down-left quadrant. 180 - angle will deflect acceptably because it's just negating the X speed.

180 - 270 degrees is the up-left quadrant. Negating the angle makes no kind of sense. Figure an angle of 185 degrees. Negated that's 360-185 = 175. 175 is still a very leftward angle. In fact, it's a negation of the Y speed, which would only make sense if you struck the top or bottom surface of the paddle, but that's not what you're testing for here.

Fixing (some) things:

First you need to decide what this function is doing. Right now it's trying to do collision and motion, and since you're passing in a RenderWindow I'm guessing you're thinking about tossing in drawing as well. You need to break this up a bit.

Secondly - while I would much prefer that you use an x,y vector for velocity and not touch angles at all - if you do use angles then you need to have angle, speed and not angle speed{x,y}. Your last line should look more like this:


float radians = degToRad(angle);
float distance = speed * delta;
move(distance * cos(radians), distance * sin(radians));

.

Thirdly, you're referring to some object called 'pongball' throughout this function. That looks like a very bad thing, since this function is a member of 'Ball'. What's going on with that?

Fourthly, I don't know what's actually intended with your angle manipulation. There's no circumstance where a ball striking a vertical surface should experience a flip its y value. It would be forced to tunnel into the wall because of the way the code is structured, and then it's going to get stuck in there because it's penetrating by 2 frames worth of distance and every frame it will continue to collide and get 'jostled' around inside the paddle. Can you explain what you want to have happen when it hits the paddle? Please use pictures if necessary.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

So 45 degrees points toward the bottom-right corner of the screen?

damn, all this time i based the angle from cartesian plane, i didnt know 45 degrees would be in bottom-right i thought it was upper right. but i guess its still the same

I'm not going to look at (or run) external code due to a lack of interest.

i mean play the ponggame.org, you can see there wht im trying to achieve

What if the ball hits the paddle and is deflected, but then is still in collision with the paddle on the next frame?

i already experienced this many times in this pong game, thats why the reflection logic and pongball.move() are on the same function so it can avoid that from happening

Negating the angle makes no kind of sense

like i said i based it from ponggame.org when i was playing it i realized when the ball hits the lower part of player1's paddle at angle 91-269 its just negated it, same with player2 paddle

speed and not angle speed{x,y}

what do you mean about this? my speed vector is just the speed of the ball. actually im using a vector with only x and y and operators overloaded with it

That looks like a very bad thing, since this function is a member of 'Ball'. What's going on with that?

oh sorry, nevermind it pongball is just a sprite, and Ball encapsulates it

Can you explain what you want to have happen when it hits the paddle?

my function is doing fine, but i still dont have the logic when it hits the middle and the edges of the paddle.

but it looks like im doing it very wrong, can you tell me a more standard way of doing this pong game?

you know im really really newbie in game dev. as you see my class design is bad too(but nvm that)

can we do it while avoiding trigo?

So 45 degrees points toward the bottom-right corner of the screen?
damn, all this time i based the angle from cartesian plane, i didnt know 45 degrees would be in bottom-right i thought it was upper right. but i guess its still the same

The unit circle assumes upward Y. If Y is downward you have to flip the circle over so that +X and +Y are in the right directions.

I'm not going to look at (or run) external code due to a lack of interest.
i mean play the ponggame.org, you can see there wht im trying to achieve

This didn't help me. I don't have the patience to sit here and play a Pong clone long enough to dissect the paddle reactions during gameplay. If you would explain exactly what you want to happen it would probably help both of us.

What if the ball hits the paddle and is deflected, but then is still in collision with the paddle on the next frame?
i already experienced this many times in this pong game, thats why the reflection logic and pongball.move() are on the same function so it can avoid that from happening

What? Anyway, correcting the problem would be better than working around it.

Negating the angle makes no kind of sense
like i said i based it from ponggame.org when i was playing it i realized when the ball hits the lower part of player1's paddle at angle 91-269 its just negated it, same with player2 paddle

Negating the angle is going to flip vertically. Think about 45 degrees vs -45 degrees.

[attachment=31764:negate.jpg]

speed and not angle speed{x,y}
what do you mean about this? my speed vector is just the speed of the ball. actually im using a vector with only x and y and operators overloaded with it

Vector representations:


struct Vector2D {
  float angle;
  float length;
};

//or

struct Vector2D {
  float x, y;
};

//NOT
struct Vector2D {
  float angle;
  float x, y;
};

Consider this:


speed.x * cos(angle*Ball::pi/180)*delta

First off, you're not altering speed.x anywhere. You're not using the magnitude of speed, but only the magnitude of the x speed. cos() is going to give you the X side of your x:y ratio for the angle you feed it. sin() will give you the Y side. Those both need to be scaled by the same number (the magnitude or "speed") in order to make sense. {cos(angle), sin(angle)} will give a normalized (length of 1) direction vector {x,y}. You multiply that vector by the speed to get the scaled {x,y} that represents the actual velocity. You then multiply that by the time delta to get the displacement vector for that frame. (or you can multiply it by the speed before doing the vector math)

Can you explain what you want to have happen when it hits the paddle?
my function is doing fine, but i still dont have the logic when it hits the middle and the edges of the paddle.
but it looks like im doing it very wrong, can you tell me a more standard way of doing this pong game?
you know im really really newbie in game dev. as you see my class design is bad too(but nvm that)

The simplest way to do it is to use an x,y vector and just negate x when it touches a paddle && is moving toward that paddle's side of the board. (And negate y when it hits a wall.)

I think you're wanting to do some deflection based on what part of the paddle it hits though, so that won't work here. I still want you to describe exactly what kind of reactions you want. You have some kind of input-process-output in mind, but it's not clear to me and I think it's not fully clear to you. Draw me a picture and explain the input and output it in detail and I think the process will become obvious.

If not then it will at least provide a clear vocabulary for discussing the specifics of the problem.

can we do it while avoiding trigo?

The alternative is changing the behavior to not use any angles (as described above), but I don't think that's what you're asking for. That system can be tweaked a little bit based on other factors, but I really want to know what the target behavior is first.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

thanks i get your point in your vector represaentations

Negating the angle is going to flip vertically. Think about 45 degrees vs -45 degrees.

but im not really getting any problem in my computation it works fine

The simplest way to do it is to use an x,y vector and just negate x when it touches a paddle && is moving toward that paddle's side of the board. (And negate y when it hits a wall.)

That was my first attempt when i started this pong game, but i dont know what to do when it hits the upper part and bottom part of the paddle

what i mean is

--- <-- upper part

| |

| |

| |

--- <-- bottom part

this is what i want to happen:

[attachment=31765:werwer.jpg]

violet arrows are talking about the upper part and edges

blue arrows are talking about the upper part and edges

yellows arrows are talking about the middle ( thats what normally happens in a pong game )

It looks like you're negating x in all those cases except striking the middle region of the paddle, and you also reverse y when it hits the top or bottom surface.

What happens in these two cases?

[attachment=31766:cases.jpg]

Ball moving straight right hits upper part

Ball moving down-right hits lower part

etc

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

damn i wasted one day

this is the complete drawing that i want to happen

in this drawing you can notice that this is what happens too in a rounded paddle

[attachment=31767:werwer.jpg]

in this 2nd picture:

[attachment=31768:werwer.jpg]

you will see that the orange arrows are wider angle than the blue arrows same with violet and yellow

it means the farther the ball's distance from the middle the wider the angle

Okay, so you're simulating a curved surface. Let's try a cheap method first and see how it works.

IF the ball is in contact with the paddle AND the ball's motion is toward that paddle's end of the board (left paddle while moving left, etc)

THEN

  • negate X speed
  • find offset distance from center of paddle: center of paddle is zero, top and bottom are negative and positive, depending on which paddle (more on this in a moment)
  • add that offset to the angle of the ball

The idea is like this:

[attachment=31774:angles.jpg]

45 may be a little too steep, so use a const variable for that value so that you can change it later. Basically you want to do what's called a LERP, or "linear interpolation".

When you deflect you start by finding the Y distance between the ball and the center of the paddle. You divide that by the distance between the center of the paddle and its extremes to get a normalized ratio. Then you multiply that by the maximum deflection angle to get the angle to deflect at. Remember to flip the X speed first, and remember that the right-side paddle will need to have its angles reversed.

Walking through this, let's say that the ball is moving at 150 degrees (down-left). The paddle is 100 units tall. The center of the paddle is at Y:150 and the center of the ball is at Y:190. (This is the left-side paddle.) You detect that the paddle and the ball are touching.

The ball is touching the paddle AND the ball is moving left, so we trigger the collision response:

angle = 180 - angle = 180 - 150 = 30 //negate X speed

impact_offset = ball.y - paddle.y = 190 - 150 = 40 //the impact position is +40

deflection_ratio = impact_offset / paddle_half_height = 40 / 50 = 0.8

deflection = deflection_ratio * max_deflection = 0.8 * 45 = 36

angle = angle + deflection = 30 + 36 = 66

Which looks like:

[attachment=31775:example.jpg]

Note that there is a problem with this (the "better" solution involves some physics that you may not be comfortable with), but for now see if you can get it working.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement