xxxxxxxxxx
165
let ripples = [];
let raindrops = [];
let noiseScale = 0.5;
let initialRaindropSpeedRange = [5, 8];
let c1, c2; //
let gradientBG;
function setup() {
createCanvas(windowWidth, windowHeight);
// Gradient colors
c1 = color(143, 184, 255);
c2 = color(63, 191, 191);
// PGraphics object to hold the gradient background
gradientBG = createGraphics(width, height);
// Generate the gradient on the PGraphics object
setGradient(gradientBG, 0, 0, width, height, c1, c2);
}
function draw() {
// Draw the gradient background in every frame
image(gradientBG, 0, 0);
// Update and display each ripple
for (let i = ripples.length - 1; i >= 0; i--) {
ripples[i].update();
ripples[i].display();
// Remove ripples when they fade out
if (ripples[i].isDone()) {
ripples.splice(i, 1);
}
}
// Update and display each raindrop
for (let i = raindrops.length - 1; i >= 0; i--) {
raindrops[i].update();
raindrops[i].display();
// When raindrop hits the 'ground', generate ripple at its position
if (raindrops[i].hitsBottom()) {
ripples.push(new Ripple(raindrops[i].pos.x, raindrops[i].pos.y));
raindrops.splice(i, 1); // Remove raindrop from array
}
}
// Randomly add new raindrops based on mouse interaction
let raindropChance = mouseIsPressed ? 0.9 : 0.2;
if (random(1) < raindropChance) {
let x = random(width); // Random horizontal position for new raindrop
raindrops.push(new Raindrop(x, -20)); // Add new raindrop starting above canvas
}
}
// Create the gradient background using PGraphics
function setGradient(pg, x, y, w, h, c1, c2) {
pg.noFill();
// Loop through the vertical lines to create gradient effect
for (let i = y; i <= y + h; i++) {
let inter = map(i, y, y + h, 0, 1); // Calculate the interpolation factor
let c = lerpColor(c1, c2, inter); // Interpolate between c1 and c2
pg.stroke(c); // Set stroke to current interpolated color
pg.line(x, i, x + w, i); // Draw horizontal line with the current color
}
}
class Raindrop {
constructor(x, y) {
this.pos = createVector(x, y);
this.size = 15;
this.speed = random(initialRaindropSpeedRange[0], initialRaindropSpeedRange[1]);
this.acceleration = 1.2; // Gravity effect
this.targetY = random(height / 6, height); // Random point at which raindrop will stop
}
update() {
this.speed += this.acceleration;
this.pos.y += this.speed;
// If mouse is pressed, make the raindrop fall faster
if (mouseIsPressed) {
this.speed = random(10, 15);
} else {
// Constrain speed within initial speed range
this.speed = constrain(this.speed, initialRaindropSpeedRange[0], initialRaindropSpeedRange[1]);
}
}
display() {
fill(201, 243, 255, 100);
stroke(255);
strokeWeight(0.2);
// Draw the raindrop using a bezier shape
beginShape();
vertex(this.pos.x, this.pos.y);
bezierVertex(this.pos.x - this.size / 2, this.pos.y + this.size, this.pos.x + this.size / 2, this.pos.y + this.size, this.pos.x, this.pos.y);
endShape(CLOSE);
}
// Check if the raindrop has reached its target Y position (ground)
hitsBottom() {
return this.pos.y >= this.targetY;
}
}
class Ripple {
constructor(x, y) {
this.pos = createVector(x, y);
this.size = 0;
this.alpha = 230; // Initial transparency
this.growthRate = 2; // How fast the ripple grows
this.fadeRate = 4; // How fast the ripple fades
this.layers = 6; // Number of ripple layers
this.wideningFactor = 1.1; // Factor to widen the ripple's oval shape
}
update() {
// Increase ripple size
this.size += this.growthRate;
// Decrease transparency so ripple fades out
this.alpha -= this.fadeRate;
}
display() {
noFill();
stroke(201, 243, 255, this.alpha);
strokeWeight(2);
// Draw multiple layers of ripples
for (let i = 0; i < this.layers; i++) {
let layerSize = this.size - i * 10;
let widening = pow(this.wideningFactor, i); // Widen each subsequent ripple
if (layerSize > 0) {
this.drawOvalRipple(layerSize * 2 * widening, layerSize * widening); // Draw each ripple layer
}
}
}
// Draw ripples with distortion using Perlin noise
drawOvalRipple(ovalWidth, ovalHeight) {
beginShape();
for (let angle = 0; angle < TWO_PI; angle += 0.1) {
let xoff = cos(angle) * 5; // X offset for Perlin noise
let yoff = sin(angle) * 5; // Y offset for Perlin noise
// Apply Perlin noise to distort the ripple shape
let distortion = map(noise(xoff + this.size * noiseScale, yoff + this.size * noiseScale), 0, 1, 0.95, 1.05);
// Calculate the X and Y coordinates for the ripple based on the oval's size and the distortion
let x = this.pos.x + (ovalWidth / 2 * cos(angle)) * distortion;
let y = this.pos.y + (ovalHeight / 2 * sin(angle)) * distortion;
vertex(x, y); // Add vertex to the shape
}
endShape(CLOSE);
}
// Check if the ripple is fully faded
isDone() {
return this.alpha <= 0;
}
}