5

I'm making a Pong game, and I've come across a problem. When the ball (a rectangle) collides with the racket (or the bat) below or above the racket, I get a strange bug where the ball moves into the rectangle and goes left-right-left-right reaching high speeds(because I added acceleration) and jumps out at the opposite side. I know why this bug is happening:

if (ballrec.Intersects(player1rec)
        && ball.x <= 20
        && ball.y + 20 >= player.y
        && ball.y <= player.y + 100) //checks the front rebound-here's the bug
{
    ball.vx *= -1; //changes x-direction
    if (ball.vx < 0)
        ball.vx -= 1; //increases x-velocity
    effect.Play();
    if (R.Next(4) == 0)
    {
        if (ball.vy < 0) ball.vy--;
        else ball.vy++; //increases y-velocity on a special occasion
    }
}
else
{
    if (ballrec.Intersects(player1rec))
    {
        ball.vy *= -1;
        effect.Play();
    }
}

ball.vy=velocity y-axis: I multiply it with -1 to change the direction

effect=sound

The bug: To make the ball rebound at any given location on the front of the racket, it says that the ball's lower side (that +20) mustn't be higher than the racket's upper side and the ball's upper side mustn't be lower than the racket's lower side. However because of the x coordinates (ball.x<=20, 20=the width of the racket), the front rebound effect consumes the top and the bottom side of the racket, and then the rebound there can't work.

When I try to solve it, my best non-complicated solution (because next year I'm starting middle school (14-18 in my country) and don't know a lot of fancy maths), I don't get a good solution (check below).

My solution (which I'm not happy with): I lower the area required for the front rebound to ball.y>=player.y and ball.y+20<=player.y+100(the length) and the up and down rebound work, but if the ball hits a corner of the racket, the same bug appears only in this case the ball moves up-down-up-down.

My question: How to fix the bug? Thank you for your time! Hope that wasn't too long!

Current solution (not perfect):

if (ballrec.Intersects(player1rec)
        && ball.x <= 20
        && ball.y >= player.y
        && ball.y + 20 <= player.y + 100)
{
    ball.vx *= -1;
    if (ball.vx < 0)
        ball.vx -= 1;
    effect.Play();
    if (R.Next(4) == 0)
    {
        if (ball.vy < 0) ball.vy--;
        else ball.vy++;
    }
}
else
{
    if (ballrec.Intersects(player1rec))
    {
        ball.vy *= -1;
        effect.Play();
    }
}
csharpwinphonexaml
  • 3,659
  • 10
  • 32
  • 63
  • This is a case of one rectangle "jumping though" the other - then getting a hit-detection in the new location. A simple way to handle this interaction is to do a line-polygon intersection test with the paddle (along the vector of the balls travel and the paddle). – user2864740 Mar 10 '14 at 17:57
  • If I need to upload anything, such as pictures, videos or more code I am willing to do it! – TheGeniusDev Mar 10 '14 at 17:59
  • Thank you for the quick response, but simply, I don't know how to do it :D Can you please send a link so that I can learn it? – TheGeniusDev Mar 10 '14 at 18:00
  • See http://stackoverflow.com/questions/3746274/line-intersection-with-aabb-rectangle , http://stackoverflow.com/questions/5221725/get-intersection-point-of-rectangle-and-line?lq=1 The line segment is the *starting* point of the ball and the *ending* point of the ball for the collision time-delta, trivially this doesn't account for paddle movement speed, as the paddle is represented by a fixed rectangle across the entire time delta, but it should be sufficient here. Alternatively, it may be sufficient to increase the physics checks - i.e. separate the CD from UI rendering to "avoid" the issue. – user2864740 Mar 10 '14 at 18:02
  • 2
    Does this help: http://stackoverflow.com/questions/21238792/java-pong-ball-glides-on-paddle – Goose Mar 10 '14 at 18:03
  • In a nutshell, your bug happens because there are circumstances under which the collision isn't resolved after being detected. You need to guarantee resolution of the collision before executing the resulting code path again. Related, over at gamedev.se: http://gamedev.stackexchange.com/questions/54603/breakout-style-ball-paddle-bounce-error-at-corner/54608#54608 – Seth Battin Mar 10 '14 at 18:16
  • I tried the spawning the ball at the place before it collided. Didn't help :( I think that I need to find if the ball hit the top, the bottom or the front, because I think that this solution will always load the if before the else because they are detected at the same spot. But if I change the region so that they don't check the same spot, if the ball hits the corner, it will go through it. – TheGeniusDev Mar 10 '14 at 18:24
  • Now I saw your comment Seth, thanks, will look into that – TheGeniusDev Mar 10 '14 at 18:25
  • Maybe I didn't write this spawning solution well. Will try again! – TheGeniusDev Mar 10 '14 at 18:28
  • Any code would be appreciated :D I've run out of ideas :( – TheGeniusDev Mar 10 '14 at 18:40
  • I think I'll just stick with my solution for now (the last paragraph), unless someone posts a better a better one. It works, but there are a few special cases which I will try to solve (for example hitting the corner of the paddle with the ball - I will definitely work on that one). Although it would be nice to know how to do these things :D – TheGeniusDev Mar 10 '14 at 19:55

1 Answers1

0

Solution 1: Check speed Vector

One solution would be to take the direction of the Speep vector (ball.vx) into account. Just allow the player1 to flip the balls x speed if the speed is negative (e.g. moving towards the left screen and vice versa for the second player) If this is a simple pong game, this would be perfectly fine:

// Player 1
if (ballrec.Intersects(player1rec)
    && ball.x <= 20
    && ball.y >= player.y
    && ball.y + 20 <= player.y + 100
    && ball.vx <= 0 ) //<--- Here
{
// .....
}

// Player 2
if (ballrec.Intersects(player2rec)
    // ....
    && ball.vx >= 0 ) //<--- Here
{
// .....
}

Solution 2: Save the collision state of the Ball

Another solution is to save the current collision state (colliding or not colliding and only flip the speed when this status switches from not colliding to colliding):

public class Ball
{
    public bool colliding = false;
}

//In Update of Ball/Game
bool player1Collision = ballrec.Intersects(player1rec)
    && ball.x <= 20
    && ball.y >= player.y
    && ball.y + 20 <= player.y + 100;
if( player1Collision && !ball.colliding )
{
    // Set state here, so reduce issues when there is a chance that different players can overlap
    ball.colliding = true;
    // .....
}

// Same for player 2,3,4,5 .....

//Update state for next frame
ball.colliding = player1Collision || player2Collision /* .... */;
MarvinPohl
  • 156
  • 3