Search code examples
javascriptmathcollision-detectiontrigonometryangle

How to change angle when a ball collides with a rectangle?


If a circle hits a rectangle and needs to bounce, I need to calculate its new direction.

This is what I have

    function tick() {
        var dx = Math.cos(ball.direction * (Math.PI / 180))*ball_md.speed;
        var dy = Math.sin(ball.direction * (Math.PI / 180))*ball_md.speed;
        ball.x += dx;
        ball.y -= dy;
        drawGame(); // refresh board

        //console.log(ball);

        paddles.some(function(paddle) {
            var circle={x:ball.x+ball_md.radius, y:ball.y+ball_md.radius, r:ball_md.radius};
            var rect={x:paddle.x, y:paddle.y, w:game_md.paddle.width, h:game_md.paddle.height};
            var hit = RectCircleColliding(circle, rect);

            if (hit) {
                if (Math.floor(ball.y) + ball_md.radius*2 <= paddle.y || Math.ceil(ball.y) >= paddle.y + game_md.paddle.height) { // hit on top or below paddle
                    ball.direction = 360 - ball.direction; 
                } else { // hit left or right side
                    ball.direction = 180 - ball.direction;  
                }
                return true;
            }
        });

        if (ball.y < 0 || ball.y+ball_md.radius*2 >= game_md.height) { // hit top or bottom wall
            ball.direction = 360 - ball.direction; 
        }
        if (ball.x < 0 || ball.x+ball_md.radius*2 >= game_md.width) { // hit left or right wall
            ball.direction = 180 - ball.direction;   
        }
    }

but it doesn't seem to always work. Does anyone know why?

Cases when it fails. In this case, it zigzags really fast on the paddle surface.

enter image description here

DEMO: https://jsfiddle.net/3ok2farw/2/


Solution

  • You need to treat the corner collision separately. When it hits the corner the velocity of the ball doesn't change perpendicular to either the horizontal or vertical axis, but along the line connecting the center of the ball and the corner. I'm adding a drawing to make it a bit clearer. If the collision is perfectly elastic (no energy loss), then the v_normal component gets replaced by its negative, -v_normal. If the collision is perfectly plastic (maximum energy loss), the exit velocity is just v_tangential. Hope this helps!

    corner collision diagram