Inspiration
The inspiration for this sketch is a supernova. A supernova is a powerful and luminous explosion that occurs at the end of a star’s life cycle. It marks the catastrophic death of a star, resulting in the release of an immense amount of energy and light, often outshining entire galaxies for a brief period.
Sketch
Highlight of Code
let stars = []; let numStars = 5000; let attractor; let state = 'attract'; let attractionStrength = 0.1; let explosionSpeed = 2; let explosionStartFrame; let damping = 0.95; // array of possible attractor positions let attractorPositions = []; let attractorIndex = 0; function setup() { createCanvas(800, 800); // define the attractor positions: center, 1/4, and 3/4 attractorPositions = [ createVector(width / 2, height / 2), // center createVector(width / 4, height / 4), // top-left (1/4) createVector(3 * width / 4, 3 * height / 4) // bottom-right (3/4) ]; attractor = attractorPositions[attractorIndex]; // initialize stars with random positions for (let i = 0; i < numStars; i++) { let x = random(width); let y = random(height); stars.push(new Star(x, y)); } } function draw() { background(0); // updates stars based on the current state for (let star of stars) { if (state === 'attract') { star.attractToCenter(attractor, attractionStrength); } else if (state === 'explode') { star.attractToCenter(attractor, -1 * attractionStrength); } star.display(); } if (state === 'attract' && stars.every(star => star.isAtCenter())) { state = 'explode'; explosionStartFrame = frameCount; } else if (state === 'explode' && frameCount > explosionStartFrame + 180) { state = 'attract'; changeAttractorPosition(); // change attractor position after each explosion } } // change the attractor's position function changeAttractorPosition() { attractorIndex = (attractorIndex + 1) % attractorPositions.length; // cycle through positions attractor = attractorPositions[attractorIndex]; } // star class class Star { constructor(x, y) { this.position = createVector(x, y); this.initialPosition = createVector(x, y); this.velocity = createVector(0, 0); this.exploding = false; this.distanceToCenter = p5.Vector.dist(this.position, attractor); // initial distance to center } // attracts/repulse to/from the center attractToCenter(center, attractionStrength) { let force = p5.Vector.sub(center, this.position); force.normalize(); force.mult(attractionStrength); this.velocity.add(force); // add the positive attraction force to the velocity this.velocity.mult(damping); // apply damping to gradually slow down stars as they approach the center this.position.add(this.velocity); this.distanceToCenter = p5.Vector.dist(this.position, center); } // check if the star is close to the center isAtCenter() { return this.distanceToCenter < 5; } display() { noStroke(); fill(255, 204, 0); // yellow color for the stars ellipse(this.position.x, this.position.y, 5); } }
The full code for the project is attached above. The hardest part was getting the attractor right. I’m using the attractor as a repulsor with a negative attraction strength which makes the force vetro opposite and that was challenging to implement at first. I had also to include a dumping factor to make the simulation go smoothly otherwise the force will just pull all the stars to the attractor and repulse them because the vector becomes negative. For instance, changing the dumping to one makes the simulation an infinite loop of attraction and repulsion without any obvious explosion.