Object-oriented programming – Week 3

Reflection: Floating Bubbles

This artwork is inspired by the simple joy of blowing soap bubbles we used to do as kids. Just like real bubbles, the circles appear wherever you click, float around randomly, and slowly fade away or pop. I wanted each click to feel like blowing a new batch of bubbles, watching them drift and disappear. The way they change color and move in different directions makes them feel alive, conveying the playful nature of real soap bubbles.

Structure

The Circle class manages each individual bubble’s movement, opacity, and lifespan, ensuring that they appear and disappear naturally over time. Functions like setup(), draw(), and mousePressed() organize different parts of the code, keeping it easy to understand and modify.

Challenges

One issue was finding the right balance between movement and fading, so that that bubbles did not disappear too quickly while still feeling transient. Another challenge was making the interaction feel engaging, which I solved by adjusting the number of bubbles created per click and giving them different speeds and directions. Additionally, I had to optimize performance to prevent the sketch from slowing down over time, so circles are now removed once their lifespan ends.

Overall, I appreciate how this piece captures the lighthearted  beauty of soap bubbles in a digital form. To make it more realistic, I’d try to make the direction that bubbles take more random and add the effect of abrupt popping.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Array to store circles
let circles = [];
let circleSize = 50;
let numCirclesPerClick = 5; // Number of circles generated per mouse click
function setup() {
createCanvas(windowWidth, windowHeight);
noFill(); // No fill for circles, only stroke
}
function draw() {
background(20, 20, 30, 50);
// Loop through circles in reverse order
for (let i = circles.length - 1; i >= 0; i--) {
circles[i].update();
circles[i].display();
// Remove circle when its lifespan reaches zero
if (circles[i].lifespan <= 0) {
circles.splice(i, 1);
}
}
}
// Circle class (individual moving and fading circles)
class Circle {
constructor(x, y, size) {
this.x = x;
this.y = y;
this.vx = random(-2, 2); // Assign random speed in x direction
this.vy = random(-2, 2); // Assign random speed in y direction
this.baseSize = size;
this.size = size;
this.opacity = random(100, 200);
this.growthSpeed = random(0.5, 2);
this.color = color(random(255), random(255), random(255));
this.lifespan = 200; // Circle disappears after a set time
}
// Update circle properties (position, size, opacity, lifespan)
update() {
this.x += this.vx;
this.y += this.vy;
this.size = this.baseSize + sin(frameCount * 0.05) * 10; // Oscillating size effect
this.opacity -= 2;
this.lifespan -= 2;
}
// Display the objects
display() {
stroke(this.color);
strokeWeight(2);
fill(this.color.levels[0], this.color.levels[1], this.color.levels[2], this.opacity); // fading effect
ellipse(this.x, this.y, this.size, this.size);
}
}
// generates multiple circles at the mouse click location
function mousePressed() {
for (let i = 0; i < numCirclesPerClick; i++) {
circles.push(new Circle(mouseX, mouseY, circleSize));
}
}
// Array to store circles let circles = []; let circleSize = 50; let numCirclesPerClick = 5; // Number of circles generated per mouse click function setup() { createCanvas(windowWidth, windowHeight); noFill(); // No fill for circles, only stroke } function draw() { background(20, 20, 30, 50); // Loop through circles in reverse order for (let i = circles.length - 1; i >= 0; i--) { circles[i].update(); circles[i].display(); // Remove circle when its lifespan reaches zero if (circles[i].lifespan <= 0) { circles.splice(i, 1); } } } // Circle class (individual moving and fading circles) class Circle { constructor(x, y, size) { this.x = x; this.y = y; this.vx = random(-2, 2); // Assign random speed in x direction this.vy = random(-2, 2); // Assign random speed in y direction this.baseSize = size; this.size = size; this.opacity = random(100, 200); this.growthSpeed = random(0.5, 2); this.color = color(random(255), random(255), random(255)); this.lifespan = 200; // Circle disappears after a set time } // Update circle properties (position, size, opacity, lifespan) update() { this.x += this.vx; this.y += this.vy; this.size = this.baseSize + sin(frameCount * 0.05) * 10; // Oscillating size effect this.opacity -= 2; this.lifespan -= 2; } // Display the objects display() { stroke(this.color); strokeWeight(2); fill(this.color.levels[0], this.color.levels[1], this.color.levels[2], this.opacity); // fading effect ellipse(this.x, this.y, this.size, this.size); } } // generates multiple circles at the mouse click location function mousePressed() { for (let i = 0; i < numCirclesPerClick; i++) { circles.push(new Circle(mouseX, mouseY, circleSize)); } }
// Array to store circles
let circles = [];
let circleSize = 50;
let numCirclesPerClick = 5; // Number of circles generated per mouse click

function setup() {
  createCanvas(windowWidth, windowHeight);
  noFill(); // No fill for circles, only stroke
}

function draw() {
  background(20, 20, 30, 50); 
  
  // Loop through circles in reverse order 
  for (let i = circles.length - 1; i >= 0; i--) {
    circles[i].update(); 
    circles[i].display(); 
    
    // Remove circle when its lifespan reaches zero
    if (circles[i].lifespan <= 0) {
      circles.splice(i, 1);
    }
  }
}

// Circle class (individual moving and fading circles)
class Circle {
  constructor(x, y, size) {
    this.x = x;
    this.y = y;
    this.vx = random(-2, 2); // Assign random speed in x direction
    this.vy = random(-2, 2); // Assign random speed in y direction
    this.baseSize = size;
    this.size = size;
    this.opacity = random(100, 200); 
    this.growthSpeed = random(0.5, 2); 
    this.color = color(random(255), random(255), random(255)); 
    this.lifespan = 200; // Circle disappears after a set time
  }

  // Update circle properties (position, size, opacity, lifespan)
  update() {
    this.x += this.vx; 
    this.y += this.vy; 
    this.size = this.baseSize + sin(frameCount * 0.05) * 10; // Oscillating size effect
    this.opacity -= 2; 
    this.lifespan -= 2; 
  }

  // Display the objects
  display() {
    stroke(this.color);
    strokeWeight(2);
    fill(this.color.levels[0], this.color.levels[1], this.color.levels[2], this.opacity); // fading effect
    ellipse(this.x, this.y, this.size, this.size);
  }
}

// generates multiple circles at the mouse click location
function mousePressed() {
  for (let i = 0; i < numCirclesPerClick; i++) {
    circles.push(new Circle(mouseX, mouseY, circleSize));
  }
}

 

Leave a Reply