let particles = []; const numParticles = 25; let cylinderRadius = 200; let cylinderHeight = 400; let sphereRadius = 300; let rotationAngle = 0; let zoom = 1; let zoomDirection = 1; function setup() { createCanvas(800, 800, WEBGL); colorMode(HSB, 360, 100, 100); for (let i = 0; i < numParticles; i++) { particles.push(new Particle( random(-cylinderRadius, cylinderRadius), random(-cylinderHeight/2, cylinderHeight/2), random(-cylinderRadius, cylinderRadius), i * (360/numParticles) )); } } function draw() { background(0); scale(zoom); zoom += 0.002 * zoomDirection; if (zoom > 1.5) zoomDirection = -1; if (zoom < 0.8) zoomDirection = 1; rotateY(rotationAngle); rotationAngle += 0.005; push(); noFill(); stroke(200, 50, 50, 50); sphere(sphereRadius); pop(); push(); noFill(); stroke(100, 50, 50, 50); cylinder(cylinderRadius, cylinderHeight); pop(); for (let particle of particles) { particle.update(); particle.checkCollisions(); particle.display(); } } class Particle { constructor(x, y, z, hue) { this.pos = createVector(x, y, z); this.vel = p5.Vector.random3D().mult(random(2, 5)); this.radius = 8; this.hue = hue; this.trail = []; this.maxTrailLength = 20; } update() { this.pos.add(this.vel); this.trail.push(this.pos.copy()); if (this.trail.length > this.maxTrailLength) { this.trail.splice(0, 1); } } checkCollisions() { let radialDist = sqrt(this.pos.x * this.pos.x + this.pos.z * this.pos.z); if (radialDist + this.radius > cylinderRadius) { let normal = createVector(this.pos.x, 0, this.pos.z).normalize(); let dotProduct = this.vel.dot(normal); this.vel.sub(normal.mult(2 * dotProduct)); this.pos.set( this.pos.x * (cylinderRadius - this.radius) / radialDist, this.pos.y, this.pos.z * (cylinderRadius - this.radius) / radialDist ); } if (this.pos.y + this.radius > cylinderHeight/2) { this.vel.y = -abs(this.vel.y); this.pos.y = cylinderHeight/2 - this.radius; } if (this.pos.y - this.radius < -cylinderHeight/2) { this.vel.y = abs(this.vel.y); this.pos.y = -cylinderHeight/2 + this.radius; } let distFromCenter = this.pos.mag(); if (distFromCenter + this.radius > sphereRadius) { let normal = this.pos.copy().normalize(); let dotProduct = this.vel.dot(normal); this.vel.sub(normal.mult(2 * dotProduct)); this.pos.setMag(sphereRadius - this.radius); } } display() { push(); noFill(); strokeWeight(2); beginShape(); for (let i = 0; i < this.trail.length; i++) { let alpha = map(i, 0, this.trail.length, 0, 100); stroke(this.hue, 80, 100, alpha); vertex(this.trail[i].x, this.trail[i].y, this.trail[i].z); } endShape(); fill(this.hue, 80, 100); noStroke(); translate(this.pos.x, this.pos.y, this.pos.z); sphere(this.radius); pop(); } }