I have multiple elipses on the canvas in javascript and I want all of them to bounce off each other. I tried using the distance formula and then changing the x and y direction of the ball when the distance is less than the ball radius *2.
This worked well for one ball, but it doesn't work so well for many balls as it often leads to the dreaded 'bounce loop' depicted Here
To remedy this issue, I resolved to change the way the balls bounce depending on where they collide with each other to avoid the bounce loop and to make the game closer to real life physics.
If there's a side to side collision, I want to reverse the x direction of both balls and if there's a top to bottom collision, I want to reverse the y direction of both balls.
So, I calculated all the points, for example, between 45 degrees and 135 degrees that correlate with a degree (that's 90 points) and compared them to all 90 point between 225 degrees and 315 degrees and vice versa.
If the distance between any of the points on the edge of the circle and all the other balls center point is less than the radius, I want the Y direction of both balls to be reversed.
I repeated the same process for 135 degrees and 225 degress to 315 degrees and 405 degrees (equivalent to 45) and reversed the X direction of both balls.
As of right now, I think the balls should bounce off each other how I want them to, but they just don't. They bounce off each other's sides and tops, bottoms, and occasionally at angles, but they tend to dip inside of each other and then change direction. Here is a video of the output.
Below is the code comparing top to bottom:
// radius is the same for all the balls and is at 25.
let ballToBallDistance = (x1, y1, x2, y2) => {
return Math.sqrt((Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)));
}
const ballCollisionY = (start, end) => {
for (let i = start; i <= end; i++) {
return ballObjects[0].ballRadius * Math.sin((i * Math.PI / 180));
}
}
const ballCollisionX = (start, end) => {
for (let i = start; i <= end; i++) {
return ballObjects[0].ballRadius * Math.cos((i * Math.PI / 180));
}
}
const upperYBall = {
bounceTopBottom() {
let n = 0;
for (let i = 0; i < ballObjects.length; i++) {
if (ballObjects.length == 1) {
return;
}
if (n == i) {
continue;
}
let yUpXPoint = ballObjects[n].ballXPos - ballCollisionX(45, 135);
let yUpYPoint = ballObjects[n].ballYPos - ballCollisionY(45, 135);
let centerBallX = ballObjects[i].ballXPos;
let centerBallY = ballObjects[i].ballYPos;
let pointDistance = ballToBallDistance(yUpXPoint, yUpYPoint, centerBallX, centerBallY);
if (pointDistance <= 25) {
ballObjects[n].ballMotionY = ballObjects[n].ballMotionY * -1;
}
if (i == ballObjects.length - 1) {
++n;
i = -1;
continue;
}
}
}
}
const lowerYBall = {
bounceBottomTop() {
let n = 0;
for (let i = 0; i < ballObjects.length; i++) {
if (ballObjects.length == 1) {
return;
}
if (n == i) {
continue;
}
let yDownXPoint = ballObjects[n].ballXPos - ballCollisionX(225, 315);
let yDownYPoint = ballObjects[n].ballYPos - ballCollisionY(225, 315);
let centerBallX = ballObjects[i].ballXPos;
let centerBallY = ballObjects[i].ballYPos;
let pointDistance = ballToBallDistance(yDownXPoint, yDownYPoint, centerBallX, centerBallY);
if (pointDistance <= 25) {
ballObjects[n].ballMotionY = ballObjects[n].ballMotionY * -1;
}
if (i == ballObjects.length - 1) {
++n;
i = -1;
continue;
}
}
}
}
I've been stuck on this feature for two weeks. If anyone has any insight as to what I am doing wrong and perhaps a solution to achieve the desired result, that would be very much appreciated.