5
votes

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();
    }
}
1
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
If I need to upload anything, such as pictures, videos or more code I am willing to do it!TheGeniusDev
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
See stackoverflow.com/questions/3746274/… , stackoverflow.com/questions/5221725/… 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

1 Answers

0
votes

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 /* .... */;