Reputation: 716
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
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