<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Circle Collision NFT - 7 Balls with Gradient Background</title>
<script src="
cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<style>
body { margin: 0; padding: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script>
let balls = [];
const numBalls = 7;
let bgColor1, bgColor2, targetBgColor1, targetBgColor2;
const bgColorChangeSpeed = 0.005;
class Ball {
constructor(x, y, r) {
this.position = createVector(x, y);
this.velocity = p5.Vector.random2D().mult(3);
this.r = r;
this.m = r * 0.1;
this.color = color(random(255), random(255), random(255));
this.targetColor = color(random(255), random(255), random(255));
this.colorChangeSpeed = 0.01;
}
update() {
this.position.add(this.velocity);
this.updateColor();
}
updateColor() {
this.color = lerpColor(this.color, this.targetColor, this.colorChangeSpeed);
if (this.color.toString() === this.targetColor.toString()) {
this.targetColor = color(random(255), random(255), random(255));
}
}
checkBoundaryCollision() {
if (this.position.x > width - this.r || this.position.x < this.r) {
this.velocity.x *= -1;
this.position.x = constrain(this.position.x, this.r, width - this.r);
}
if (this.position.y > height - this.r || this.position.y < this.r) {
this.velocity.y *= -1;
this.position.y = constrain(this.position.y, this.r, height - this.r);
}
}
checkCollision(other) {
let distanceVect = p5.Vector.sub(other.position, this.position);
let distanceVectMag = distanceVect.mag();
let minDistance = this.r + other.r;
if (distanceVectMag < minDistance) {
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
let correctionVector = distanceVect.copy().normalize().mult(distanceCorrection);
other.position.add(correctionVector);
this.position.sub(correctionVector);
let theta = distanceVect.heading();
let sine = sin(theta);
let cosine = cos(theta);
let bTemp = [createVector(), createVector()];
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
let vTemp = [createVector(), createVector()];
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
let vFinal = [createVector(), createVector()];
vFinal[0].x = ((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (this.m + other.m);
vFinal[0].y = vTemp[0].y;
vFinal[1].x = ((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) / (this.m + other.m);
vFinal[1].y = vTemp[1].y;
bTemp[0].x += vFinal[0].x;
bTemp[1].x += vFinal[1].x;
let bFinal = [createVector(), createVector()];
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
other.position.x = this.position.x + bFinal[1].x;
other.position.y = this.position.y + bFinal[1].y;
this.position.add(bFinal[0]);
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
}
}
display() {
noStroke();
fill(this.color);
ellipse(this.position.x, this.position.y, this.r * 2);
}
}
function setup() {
createCanvas(710, 400);
for (let i = 0; i < numBalls; i++) {
let x = random(width);
let y = random(height);
let r = random(20, 40); // Random radius between 20 and 40
balls.push(new Ball(x, y, r));
}
// Initialize background colors
bgColor1 = color(random(255), random(255), random(255));
bgColor2 = color(random(255), random(255), random(255));
targetBgColor1 = color(random(255), random(255), random(255));
targetBgColor2 = color(random(255), random(255), random(255));
}
function draw() {
// Update background colors
bgColor1 = lerpColor(bgColor1, targetBgColor1, bgColorChangeSpeed);
bgColor2 = lerpColor(bgColor2, targetBgColor2, bgColorChangeSpeed);
// Check if colors have reached their targets
if (bgColor1.toString() === targetBgColor1.toString()) {
targetBgColor1 = color(random(255), random(255), random(255));
}
if (bgColor2.toString() === targetBgColor2.toString()) {
targetBgColor2 = color(random(255), random(255), random(255));
}
// Draw gradient background
for(let y = 0; y < height; y++){
let inter = map(y, 0, height, 0, 1);
let c = lerpColor(bgColor1, bgColor2, inter);
stroke(c);
line(0, y, width, y);
}
for (let i = 0; i < balls.length; i++) {
let b = balls[i];
b.update();
b.display();
b.checkBoundaryCollision();
for (let j = i + 1; j < balls.length; j++) {
b.checkCollision(balls[j]);
}
}
}
</script>
</body>
</html>