LuisBento
LuisBento

Reputation: 716

JS Arkanoid collision detection (sides vs bottom and top)

I know there are many threads with similar questions, and I have read and tried many of them, but still i can't get the result I am looking for. Maybe someone can help me.

I am writing a JS Arkanoid (Breakout) type game to improve my JS skills and I am having some trouble with the collision detection. Collision with the paddle or the walls is working, but not with the bricks.

The ball and the bricks are instances of the classes Ball and Brick, each having it's own

pos: {
    x: ...
    y: ...
}

The ball is draw from the center (using ball.pos.x and ball.pos.y) and it has a radius ball.r. The ball also has a x and y velocity (ball.vel.x and ball.vel.y).

The bricks are drawn from the top left corner (brick.pos.x and brick.pos.y) and they have a height (brick.h) and width (brick.w). i also added a center point to the bricks (brick.center.x and brick.center.y).

In the ball's update function I check for collisions with each brick like this:

for (let i = 0; i < bricks.length; i++) {
    let collision = detectCollision(this, bricks[i]);
}

and the detectCollisions is

function detectCollision(ball, brick) {
    let xDist = calculateDistance(ball.pos.x, brick.center.x);
    let yDist = calculateDistance(ball.pos.y, brick.center.y);

if (xDist < (ball.r + brick.w / 2) && yDist < (ball.r + brick.h / 2)) {
    return true;
} else {
    return false;
}

function calculateDistance(pointA, pointB) {
    return Math.abs(pointA - pointB);
}

I know now like this the code isn't really doing anything. i just store it in the collision variable. It is just to show you what my idea is. I can with this function detect if the ball and the brick collide, but can't detect with which side has the ball collided.

What I now am missing and can't seem to understand is how to detect if the collision was with the top, the bottom, or one of the sides. If the collision was with the top or bottom i have to flip the ball.vel.y and if it was with one of the sides i have to flip the ball.vel.x.

Upvotes: 0

Views: 872

Answers (1)

Bergi
Bergi

Reputation: 664297

I would start with

function detectCollision(ball, brick) {
    let xDist = calculateDistance(ball.pos.x, brick.center.x) - brick.w / 2;
    let yDist = calculateDistance(ball.pos.y, brick.center.y) - brick.h / 2;

    if (xDist < ball.r && yDist < ball.r) {
        return true;
    } else {
        return false;
    }
}

where xDist and yDist are now the absolute distances between the ball and the nearest edges of the brick (intersecting at the nearest corner of the brick). You now can not only make the equation work with round balls:

xDist < ball.r && yDist < 0 || yDist < ball.r && xDist < 0 || xDist**2 + yDist**2 < ball.r**2

but also distinguish the sides by the ratio between xDist and yDist:

if (/* collides */) {
    if (xDist < yDist)
        return "vertical"; // from top or bottom
//  else if (xDist == yDist)
//      return "45°";
    else
        return "horizontal"; // from left or right
} else {
    return null;
}

Upvotes: 0

Related Questions