251 lines
8.0 KiB
JavaScript
251 lines
8.0 KiB
JavaScript
function gravityForce(ball) {
|
|
|
|
/* We simulate a kind of gravity towards the target point of each ball. This force will make the ball to keep pushing to reach that point. */
|
|
|
|
const coulomb = .00001;
|
|
const minForce = 0.01;
|
|
|
|
var d = Math.sqrt(Math.pow(ball.targetPosition.x - ball.currentPosition.x, 2) + Math.pow(ball.targetPosition.y - ball.currentPosition.y, 2)); // ... we calculate the distance ...
|
|
|
|
var force = coulomb * d * d / ball.currentMass; // In this case the mass of the ball affects the gravity force that it receives, that gives priority to target position to bigger balls.
|
|
|
|
if (force < minForce) { // We need this attraction force to overcome the friction we imposed to the system.
|
|
force = minForce;
|
|
}
|
|
|
|
var pos1 = {
|
|
x: ball.currentPosition.x,
|
|
y: ball.currentPosition.y
|
|
};
|
|
|
|
var pos2 = {
|
|
x: ball.targetPosition.x,
|
|
y: ball.targetPosition.y
|
|
};
|
|
|
|
var posDiff = { // Next we need the vector resulting from the 2 positions.
|
|
x: pos2.x - pos1.x,
|
|
y: pos2.y - pos1.y
|
|
};
|
|
|
|
var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector.
|
|
x: posDiff.x / d,
|
|
y: posDiff.y / d
|
|
};
|
|
|
|
var forceVector = {
|
|
x: unitVector.x * force,
|
|
y: unitVector.y * force
|
|
};
|
|
|
|
/* We add the force vector to the speed vector */
|
|
|
|
ball.currentSpeed.x = ball.currentSpeed.x + forceVector.x;
|
|
ball.currentSpeed.y = ball.currentSpeed.y + forceVector.y;
|
|
|
|
}
|
|
|
|
function repulsionForce(currentBall) {
|
|
|
|
/* We generate a repulsion force between balls, that prevents them to be collisioning so often. */
|
|
|
|
const coulomb = 2;
|
|
|
|
var ball1 = balls[currentBall];
|
|
|
|
for (var i = 0; i < balls.length; i++) { // The force to be applied is considering all other balls...
|
|
|
|
if (i !== currentBall) { // ... except for the current one.
|
|
|
|
var ball2 = balls[i]; // So, for each ball...
|
|
|
|
var d = Math.sqrt(Math.pow(ball2.currentPosition.x - ball1.currentPosition.x, 2) + Math.pow(ball2.currentPosition.y - ball1.currentPosition.y, 2)); // ... we calculate the distance ...
|
|
|
|
var force = coulomb * ball2.currentMass / (d * d); // ... and with it the repulsion force.
|
|
|
|
/* We need to put a hard limit to this force, in order to to eject very little balls to the infinite and beyond. */
|
|
|
|
if (force > 1) {
|
|
force = 1;
|
|
}
|
|
|
|
var pos1 = {
|
|
x: ball1.currentPosition.x,
|
|
y: ball1.currentPosition.y
|
|
};
|
|
|
|
var pos2 = {
|
|
x: ball2.currentPosition.x,
|
|
y: ball2.currentPosition.y
|
|
};
|
|
|
|
var posDiff = { // Next we need the vector resulting from the 2 positions.
|
|
x: pos2.x - pos1.x,
|
|
y: pos2.y - pos1.y
|
|
};
|
|
|
|
var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector.
|
|
x: posDiff.x / d,
|
|
y: posDiff.y / d
|
|
};
|
|
|
|
var forceVector = {
|
|
x: unitVector.x * force,
|
|
y: unitVector.y * force
|
|
};
|
|
|
|
/* We substract the force vector to the speed vector of the current ball */
|
|
|
|
ball1.currentSpeed.x = ball1.currentSpeed.x - forceVector.x;
|
|
ball1.currentSpeed.y = ball1.currentSpeed.y - forceVector.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function colliding(ball1, ball2)
|
|
|
|
{
|
|
/* This function detects weather 2 balls collide with each other. */
|
|
|
|
var r1 = ball1.currentRadius;
|
|
var r2 = ball2.currentRadius;
|
|
|
|
var distance = Math.sqrt(Math.pow(ball2.currentPosition.x - ball1.currentPosition.x, 2) + Math.pow(ball2.currentPosition.y - ball1.currentPosition.y, 2));
|
|
|
|
if (distance > (r1 + r2)) {
|
|
// No solutions, the circles are too far apart.
|
|
return false;
|
|
}
|
|
else if (distance <= r1 + r2) {
|
|
// One circle contains the other.
|
|
return true;
|
|
}
|
|
else if ((distance === 0) && (r1 === r2)) {
|
|
// the circles coincide.
|
|
return true;
|
|
}
|
|
else return true;
|
|
}
|
|
|
|
|
|
function isInside(x, y) {
|
|
|
|
/* This function detects weather the point x,y is inside any of the balls. */
|
|
|
|
for (var i = 0; i < balls.length; i++) {
|
|
var ball = balls[i];
|
|
var distance = Math.sqrt(Math.pow(ball.currentPosition.x - x, 2) + Math.pow(ball.currentPosition.y - y, 2));
|
|
|
|
if (distance < ball.currentRadius) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
function isInsideBall(ballIndex, x, y) {
|
|
|
|
/* This function detects weather the point x,y is inside one particular balls. */
|
|
|
|
|
|
var ball = balls[ballIndex];
|
|
var distance = Math.sqrt(Math.pow(ball.currentPosition.x - x, 2) + Math.pow(ball.currentPosition.y - y, 2));
|
|
|
|
if (distance < ball.currentRadius) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
function distance(x1, y1, x2, y2) {
|
|
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
|
}
|
|
|
|
|
|
function resolveCollision(ball1, ball2) {
|
|
|
|
/* This function changes speed and position of balls that are in collision */
|
|
|
|
var collisionision_angle = Math.atan2((ball2.currentPosition.y - ball1.currentPosition.y), (ball2.currentPosition.x - ball1.currentPosition.x));
|
|
|
|
var speed1 = Math.sqrt(ball1.currentSpeed.x * ball1.currentSpeed.x + ball1.currentSpeed.y * ball1.currentSpeed.y); // Magnitude of Speed Vector for ball 1
|
|
var speed2 = Math.sqrt(ball2.currentSpeed.x * ball2.currentSpeed.x + ball2.currentSpeed.y * ball2.currentSpeed.y); // Magnitude of Speed Vector for ball 2
|
|
|
|
var direction_1 = Math.atan2(ball1.currentSpeed.y, ball1.currentSpeed.x);
|
|
var direction_2 = Math.atan2(ball2.currentSpeed.y, ball2.currentSpeed.x);
|
|
|
|
var new_xspeed_1 = speed1 * Math.cos(direction_1 - collisionision_angle);
|
|
var new_yspeed_1 = speed1 * Math.sin(direction_1 - collisionision_angle);
|
|
var new_xspeed_2 = speed2 * Math.cos(direction_2 - collisionision_angle);
|
|
var new_yspeed_2 = speed2 * Math.sin(direction_2 - collisionision_angle);
|
|
|
|
var final_xspeed_1 = ((ball1.currentMass - ball2.currentMass) * new_xspeed_1 + (ball2.currentMass + ball2.currentMass) * new_xspeed_2) / (ball1.currentMass + ball2.currentMass);
|
|
var final_xspeed_2 = ((ball1.currentMass + ball1.currentMass) * new_xspeed_1 + (ball2.currentMass - ball1.currentMass) * new_xspeed_2) / (ball1.currentMass + ball2.currentMass);
|
|
var final_yspeed_1 = new_yspeed_1;
|
|
var final_yspeed_2 = new_yspeed_2;
|
|
|
|
var cosAngle = Math.cos(collisionision_angle);
|
|
var sinAngle = Math.sin(collisionision_angle);
|
|
|
|
|
|
ball1.currentSpeed.x = cosAngle * final_xspeed_1 - sinAngle * final_yspeed_1;
|
|
ball1.currentSpeed.y = sinAngle * final_xspeed_1 + cosAngle * final_yspeed_1;
|
|
|
|
ball2.currentSpeed.x = cosAngle * final_xspeed_2 - sinAngle * final_yspeed_2;
|
|
ball2.currentSpeed.y = sinAngle * final_xspeed_2 + cosAngle * final_yspeed_2;
|
|
|
|
|
|
|
|
|
|
|
|
var pos1 = {
|
|
x: ball1.currentPosition.x,
|
|
y: ball1.currentPosition.y
|
|
};
|
|
|
|
var pos2 = {
|
|
x: ball2.currentPosition.x,
|
|
y: ball2.currentPosition.y
|
|
};
|
|
|
|
// get the mtd
|
|
var posDiff = {
|
|
x: pos1.x - pos2.x,
|
|
y: pos1.y - pos2.y
|
|
};
|
|
|
|
var d = Math.sqrt(Math.pow(ball2.currentPosition.x - ball1.currentPosition.x, 2) + Math.pow(ball2.currentPosition.y - ball1.currentPosition.y, 2));
|
|
|
|
// minimum translation distance to push balls apart after intersecting
|
|
var scalar = (((ball1.currentRadius + ball2.currentRadius) - d) / d);
|
|
|
|
var minTD = {
|
|
x: posDiff.x * scalar,
|
|
y: posDiff.y * scalar
|
|
};
|
|
|
|
// resolve intersection --
|
|
// computing inverse mass quantities
|
|
var im1 = 1 / ball1.currentMass;
|
|
var im2 = 1 / ball2.currentMass;
|
|
|
|
// push-pull them apart based off their mass
|
|
|
|
pos1.x = pos1.x + minTD.x * (im1 / (im1 + im2));
|
|
pos1.y = pos1.y + minTD.y * (im1 / (im1 + im2));
|
|
pos2.x = pos2.x - minTD.x * (im2 / (im1 + im2));
|
|
pos2.y = pos2.y - minTD.y * (im2 / (im1 + im2));
|
|
|
|
ball1.currentPosition = pos1;
|
|
ball2.currentPosition = pos2;
|
|
}
|