xxxxxxxxxx
146
const balls = [];
function setup() {
createCanvas(400, 400);
frameRate(60);
createBalls(20);
}
function draw() {
background(32);
for (let b1 = 0; b1 < balls.length; b1++) {
balls[b1].update();
balls[b1].draw();
for (let b2 = b1 + 1; b2 < balls.length; b2++) {
if (balls[b1].checkBallCollision(balls[b2])) {
balls[b1].handleBallCollision(balls[b2]);
}
}
}
}
class Ball {
constructor(x, y, vel, radius, colour) {
this.x = x;
this.y = y;
this.vel = vel;
this.radius = radius;
this.mass = Math.PI * Math.pow(radius, 2);
this.colour = colour;
}
draw() {
fill(this.colour);
circle(this.x, this.y, this.radius * 2);
}
update() {
this.x += this.vel.x * deltaTime;
this.y += this.vel.y * deltaTime;
this.handleBoundaryCollision(
this.checkBoundaryCollision()
);
}
checkBoundaryCollision() {
const res = [0, 0];
if (this.x - this.radius < 0) {
res[0] = -1;
} else if (this.x + this.radius > width) {
res[0] = 1;
}
if (this.y - this.radius < 0) {
res[1] = -1;
} else if (this.y + this.radius > width) {
res[1] = 1;
}
return res;
}
handleBoundaryCollision(col) {
if (col[0] !== 0) {
this.vel.x *= -1;
this.x += this.vel.x * deltaTime;
}
if (col[1] !== 0) {
this.vel.y *= -1;
this.y += this.vel.y * deltaTime;
}
}
checkBallCollision(b2) {
const dist = Math.sqrt(Math.pow(this.x - b2.x, 2) + Math.pow(this.y - b2.y, 2));
return dist < this.radius + b2.radius;
}
handleBallCollision(b2) {
const vNorm = createVector(b2.x - this.x, b2.y - this.y);
const uvNorm = p5.Vector.normalize(vNorm);
const uvTang = createVector(-uvNorm.y, uvNorm.x);
const v1Norm = uvNorm.dot(this.vel);
const v1Tang = uvTang.dot(this.vel);
const v2Norm = uvNorm.dot(b2.vel);
const v2Tang = uvTang.dot(b2.vel);
const newV1Norm = ((v1Norm * (this.mass - b2.mass)) + (v2Norm * 2 * b2.mass)) / (this.mass + b2.mass);
const newV2Norm = ((v2Norm * (b2.mass - this.mass)) + (v1Norm * 2 * this.mass)) / (this.mass + b2.mass);
const vNewV1Norm = p5.Vector.mult(uvNorm, newV1Norm);
const vNewV1Tang = p5.Vector.mult(uvTang, v1Tang);
const vNewV2Norm = p5.Vector.mult(uvNorm, newV2Norm);
const vNewV2Tang = p5.Vector.mult(uvTang, v2Tang);
const vNewV1 = p5.Vector.add(vNewV1Norm, vNewV1Tang);
const vNewV2 = p5.Vector.add(vNewV2Norm, vNewV2Tang);
this.vel = vNewV1;
b2.vel = vNewV2;
// Handle overlap by pushing balls apart by the overlap amount
const overlap = (this.radius + b2.radius) - vNorm.mag();
if (overlap > 0) {
const vOverlap = p5.Vector.mult(uvNorm, overlap / 2);
this.x -= vOverlap.x;
this.y -= vOverlap.y;
b2.x += vOverlap.x;
b2.y += vOverlap.y;
}
// Handle overlap by applying velocity to position as this is the most that the balls could overlap anyway
// this.update();
// b2.update();
}
}
function createBalls(n) {
let counter = 0;
while (true) {
if (counter >= n) {
break;
}
const r = map(random(), 0, 1, 10, 25);
const newBall = new Ball(
map(random(), 0, 1, r, width - r),
map(random(), 0, 1, r, height - r),
createVector(
map(random(), 0, 1, -0.15, 0.15),
map(random(), 0, 1, -0.15, 0.15),
),
r,
random(["red", "green", "blue", "yellow", "purple", "pink", "cyan", "magenta"]),
);
let collision = false;
for (let ball in balls) {
if (balls[ball].checkBallCollision(newBall)) {
collision = true;
break;
}
}
if (!collision) {
balls.push(newBall);
counter += 1;
}
}
}