const forceMultiplier = 100;
const wall = min(mouseX, 500);
rect(0, 0, wall, height);
if (ballArray.length < ballAmount) {
const x = (wall + width) / 2;
ballArray.push(new ball(x, y));
for (let i = 0; i < subStep; i++) {
communicateBetweenBalls();
ballArray.forEach((ball) => ball.update());
ballArray.forEach((ball) => ball.resolveEdges(wall));
ballArray.forEach((ball) => ball.show());
function communicateBetweenBalls() {
for (let i = 0; i < ballArray.length; i++) {
const current = ballArray[i];
const rest = ballArray.slice(i + 1);
for (const target of rest) {
current.checkCollision(target);
const ball = function (x, y) {
this.pos = createVector(x, y);
this.vel = createVector(1, 0).rotate(random(PI));
this.acc = createVector(0, 0);
this.radius = random(minRadius, maxRadius);
this.mass = this.radius ** 2;
this.color = color(random(256), random(256), random(256));
this.checkCollision = function (target) {
const difference = this.pos.copy().sub(target.pos);
const distance = difference.mag();
const totalRadius = this.radius + target.radius;
if (distance < totalRadius) {
const nonZeroDistance = max(distance, 0.1);
const overlapRatio = totalRadius / nonZeroDistance - 1;
const totalMass = this.mass + target.mass;
const shareA = target.mass / totalMass;
const shareB = this.mass / totalMass;
this.acc.add(force.copy().mult(shareA));
target.acc.sub(force.copy().mult(shareB));
this.show = function () {
ellipse(this.pos.x, this.pos.y, this.radius * 2);
this.update = function () {
this.vel.add(this.acc.div(subStep));
this.vel.limit(speedLimit);
this.acc.y = gravity / subStep;
this.resolveEdges = function (wall) {
if (this.pos.x < this.radius + wall) {
this.pos.x = this.radius + wall;
} else if (this.pos.x > width - this.radius) {
this.pos.x = width - this.radius;
if (this.pos.y > height - this.radius) {
this.pos.y = height - this.radius;
function mousePressed() {