const minRadiusOfBall = 16;
const maxRadiusOfBall = 8;
const forceOfAttraction = 4;
p5.disableFriendlyErrors = true;
createCanvas(960, 540, WEBGL);
directionalLight(color("white"), 0, 0, -1);
directionalLight(color("gray"), 0, -1, -1);
worms.forEach((e) => e.moveHead());
worms.forEach((e) => e.attractNeighborParts());
balls.forEach((e) => e.wrap());
balls.forEach((e) => e.update());
worms.forEach((e) => e.show());
for (let i = numOfWorms; i--; ) {
let radius = random(minRadiusOfBall, maxRadiusOfBall);
for (j = 0; j < lengthOfWorm; j++) {
const ball = new Ball(j ? radius : radius * 1.5);
worms.push(new Worm(group));
pos: createVector(mouseX - width / 2, mouseY - height / 2),
function avoidOverlapping() {
const all = balls.concat(player);
for (let i = all.length; i--; ) {
const delta = A.pos.copy().sub(B.pos);
const distance = sqrt(delta.x ** 2 + delta.y ** 2);
const sumRadius = A.radius + B.radius;
if (distance < sumRadius) {
const k = 1 - distance / sumRadius;
const force = delta.mult(k);
constructor(arrayOfBalls) {
this.parts = arrayOfBalls;
this.color = color(random(50, 256), random(50, 256), random(50, 256));
this.direction = random(2 * PI);
this.rotation = random(2) < 1 ? -0.01 : 0.01;
const head = this.parts[0];
this.direction += this.rotation;
const unitVector = createVector(1, 0).rotate(this.direction);
head.vel.add(unitVector);
let prev = this.parts[0];
for (let i = 1; i < this.parts.length; i++) {
const current = this.parts[i];
const delta = current.pos.copy().sub(prev.pos);
const force = delta.normalize().mult(forceOfAttraction);
this.parts.forEach((p, index) => {
torus(p.radius / 1.5, p.radius / 4);
const signal = 1 >= p.vel.x ** 2 + p.vel.y ** 2;
this.pos = createVector(random(-1, 1), random(-1, 1));
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.vel.add(this.acc.div(2));
const r = this.radius + margin;
this.pos.x = constrain(this.pos.x, r - width / 2, width / 2 - r);
this.pos.y = constrain(this.pos.y, r - height / 2, height / 2 - r);