1

I have a "physics ball" that can bounce around the screen off the edges which works fine. But I wanted to be able to add boxes and have my ball be able to bounce of those, too. I have tried to create something and it feels like it is quite close, but there is flaw that I understand why it exists, but am unsure on how I can get around it.

if (colliding(ball, block))
        {
            if (ball.velocity.x > 0)
            {
                ball.velocity.x *= -ball.restitution;
                ball.vector.x = block.vector.x - ball.radius;
            }
            else
            {
                ball.velocity.x *= -ball.restitution;
                ball.vector.x = block.vector.x + block.width + ball.radius;
            }

            if (ball.velocity.y > 0)
            {
                ball.velocity.y *= -ball.restitution;
                ball.vector.y = block.vector.y - ball.radius;
            }
            else
            {
                ball.velocity.y *= -ball.restitution;
                ball.vector.y = block.vector.y + block.height + ball.radius;
            }
        }

colliding():

boolean colliding(MassEntity ball, Block block)
    {
        return PVector.dist(ball.vector, block.vector) < ball.radius
                || PVector.dist(ball.vector, new PVector(block.vector.x + block.width, block.vector.y)) < ball.radius
                || PVector.dist(ball.vector, new PVector(block.vector.x + block.width, block.vector.y + block.height)) < ball.radius
                || PVector.dist(ball.vector, new PVector(block.vector.x, block.vector.y + block.height)) < ball.radius
                || (ball.vector.x - ball.radius < block.vector.x + block.width && ball.vector.x + ball.radius > block.vector.x
                && ball.vector.y - ball.radius < block.vector.y + block.height && ball.vector.y + ball.radius > block.vector.y);
    }

(I know the if statement is a little monstrous, but I don't know what happened to the formatting honestly)

The issue is that when the ball collides with the rectangle, since the ball is "teleported" to outside of the rectangle (so it doesn't stay inside the rectangle due to the velocity being flipped), it teleports on both axes so pretty much the ball will weirdly teleport to the end of one of the edges.

I just need to somehow make if statements for the respective axes to only be considered in the appropriate situation.

turke1034
  • 68
  • 1
  • 7

1 Answers1

0

First, compute P, the nearest point to the ball that is in the box :

PVector P = new PVector(
    max(min(ball.vector.x, box.vector.x + box.width / 2), box.vector.x - box.width / 2), 
    max(min(ball.vector.y, box.vector.y + box.height / 2), box.vector.y - box.height / 2)
);

To check if there is a collision, you can check if the distance between P and the center of the ball is smaller than the radius of the ball.

To update the speed of the ball, you can do this :

PVector n = normalize(ball.vector.copy().sub(P));
ball.velocity.sub(n.mult(2 * n.dot(ball.velocity)));

n is the normal vector a the collision's position and to reflect the speed on the surface you have to delete the component of the velocity that is parallel to it. Then you have to add this same component multiplied by -1. As those two operations are the same, you can just do it one time with a factor 2.

A last precision I have to make is that you may need to check if the ball is going away from the box to avoid reversing the speed in that case :

PVector n = normalize(ball.vector.copy().sub(P));
float f = n.dot(ball.velocity);
if (f < 0)
    ball.velocity.sub(n.mult(2 * f));

I haven't tested my code so tell me if there is a problem.

Cadeyrn
  • 545
  • 2
  • 12