Bubbles – OOP assignment

Ideation

For this assignment, I wanted to create something that was colorful and dynamic. My immediate thoughts went to something that would grow on the screen and somehow interact with other objects.

First iteration – without OOP

First, I just wanted to draw a circle on the screen at a fixed position and have it grow in size.
Once I finished this, I worked on creating an object for the circles so that I can have multiple of them on the screen using an array.

Second Iteration – OOP

I also wanted to add some randomness to the way the bubbles change, so I used random for creating a different starting position, radius, color, and growth rate. I removed the stroke because it looks neater.

Bubbles pop!

To make the bubbles pop, I did something similar to a coin flip but with tighter constraints so that they pop slower.

Pop them yourself

Click on the bubbles to pop them.

Find the code here and below:

let bubbles = [];

function setup() {
  createCanvas(800, 800);

  for (let i = 0; i < 100; i++) {
    let colorVals = color(
      random(255),
      random(255),
      random(255),
      random(100, 150)
    );
    let growth = random(1.5);
    let diameter = random(5);
    let timer = random(20);
    let x = random(diameter, height - diameter);
    let y = random(diameter, width - diameter);
    bubbles.push(new Bubble(x, y, diameter, timer, growth, colorVals));
  }
}

function draw() {
  background(220);

  for (let i = 0; i < bubbles.length; i++) {
    bubbles[i].run();
  }
}

function mousePressed() {
  for (let i = bubbles.length - 1; i >= 0; i--) {
    let popped = bubbles[i].pop();
    if (popped) {
      bubbles.splice(i, 1);
      break;
    }
  }
}

class Bubble {
  constructor(posX, posY, diameter, timer, growth, colorValues) {
    this.color = color(colorValues);
    this.size = diameter;
    this.timer = timer;
    this.growth = growth;
    this.x = posX;
    this.y = posY;
    this.radius = this.size / 2;
  }

  run() {
    this.draw();
    this.update();
  }

  draw() {
    noStroke();
    fill(this.color);
    circle(this.x, this.y, this.size);
  }

  update() {
    this.size += this.growth;
    this.radius = this.size / 2;
  }

  pop() {
    let d = dist(mouseX, mouseY, this.x, this.y);
    if (d < this.radius) {
      return true;
    }
  }
}

 

Breathing Cubes – Assignment 2

Breathing Cubes

My inspiration for this week’s assignment came from this image below called Boxes: This is taken from the book, Computer Graphics and Art Vol. 2, No. 3 which can be found here.

I thought it looked really cool how the blocks were falling apart in the middle and the rotations were getting less and less chaotic towards the end.

I wanted to achieve a similar effect of rotating cubes but with some more interaction (it is interactive media after all!).  To begin, I just laid out cubes on a canvas of size 600 x 600 using the for loop that we learned in class.

This was fairly simple to achieve but the real trouble began after this. How do I make it rotate? This was the hardest challenge of the assignment since I wanted the rotation to somehow be associated with the movement of the mouse so that the user can interact with it. At first, it was chaotic as everything was just being thrown around.

But I was able to fix this using the translate function and with a  couple of iterations, I was able to get the rotation around the center of the rectangles. I tracked the distance between the mouseX and mouseY to the rectangle to determine the angle to rotation and things were looking good.

I wanted to another concept we learned in class, Perlin noise. So I decided to use the frameCount and mouseX and mouseY to add some movement to the cubes and the color even without any input from the user. This leads to a slight movement in the cubes making them look alive.

The final result is down below and I hope you like it!

You can find the code down below or in this GitHub repo:

const rectWidth = 50;

function setup() {
  createCanvas(600, 600);
}

function draw() {
  background(255);
  rectMode(CENTER);
  // for consistent color output
  noiseSeed(4)

  // laying out the squares
  for (let rectY = rectWidth / 2; rectY < height; rectY += rectWidth) {
    for (let rectX = rectWidth / 2; rectX < width; rectX += rectWidth) {
      // noise factors for color and angles
      let frameFactor = noise(frameCount * 0.005);
      let mouseXFactor = noise(mouseX * 0.001);
      let mouseYFactor = noise(mouseY * 0.001);

      // push and pop for translation and rotation
      push();
      let colorValue =
        255 - (abs(mouseX - rectX) + abs(mouseY - rectY)) * frameFactor;

      fill(colorValue, mouseXFactor * colorValue, mouseYFactor * colorValue);

      translate(rectX, rectY);

      // changing this will change the intensity of the rotation
      let rotationFactor = 800
      let angle =
        ((abs(mouseX - rectX) + abs(mouseY - rectY)) /
          (rotationFactor + frameFactor * 1000)) *
        TWO_PI;

      rotate(angle);

      rect(0, 0, rectWidth);
      pop();
    }
  }
}

 

 

Self Portrait – Assignment 1

Brainstorming

For this first assignment in Intro to Interactive Media, I had to create a self-portrait. This task seemed very daunting at first because I have never used p5js and I know that my design skills are not the best. However, this did not impede my motivation and I began by first looking for a good picture to try and replicate in a cartoonish manner with simple shapes. I settled on the picture below to use as my inspiration.

Inspiration portrait

To give me an idea for the basic shapes, I drew a simple sketch after which I began coding.

Sketch

Coding

I separated the different features into different functions (mouth, ears, eyes,  etc) and called them in the face function. All the sizes were relative and this helped me later in creating a magnify button that would allow you to zoom in to the image. This is what the final portrait looked like when I finished.

From this assignment, I learned to use some of the more advanced shapes like Bezier curves and also to use the mousePressed function to create some interactivity.

The code for the assignment can be found here on GitHub as well as below.

function setup() {
  createCanvas(640, 480);
}

let size = 2;
function draw() {
  background(63, 83, 212);
  let centerX = width / 2;
  let centerY = height / 2;
  face(centerX, centerY, size);
}

function face(centerX, centerY, size) {
  magnify();
  neck(centerX, centerY, size);
  ears(centerX, centerY, size);
  fill(203, 130, 98);
  ellipse(centerX, centerY, size * 110, size * 145); // face shape
  mouth(centerX, centerY, size);
  nose(centerX, centerY, size);
  eyes(centerX, centerY, size);
  hair(centerX, centerY, size);
  beard(centerX, centerY, size, 3);
  mole(centerX, centerY, size);
}

function magnify() {
  fill(0);
  strokeWeight(10);
  line(50, 40, 70, 70);
  strokeWeight(1);
  fill(225);
  circle(50, 40, 40);
}

function mousePressed() {
  if (mouseX > 30 && mouseX < 70 && mouseY < 60 && mouseY > 20) {
    if (size === 1) {
      size = 2;
    } else {
      size = 1;
    }
  }
}

function mole(centerX, centerY, size) {
  circle(centerX + size * 13, centerY - size * 6, size * 1);
}

function neck(centerX, centerY, size) {
  //neck
  fill(203, 130, 98);
  quad(
    centerX - size * 20,
    centerY + size * 40,
    centerX + size * 20,
    centerY + size * 40,
    centerX + size * 40,
    centerY + size * 90,
    centerX - size * 40,
    centerY + size * 90
  );
}

function mouth(centerX, centerY, size) {
  // mouth
  let controlAx = centerX - size * 30;
  let controlAy = centerY - size * 20;

  let controlBx = centerX + size * 30;
  let controlBy = centerY - size * 20;

  let startAx = centerX - size * 20;
  let startAy = centerY + size * 40;

  let startBx = centerX + size * 20;
  let startBy = centerY + size * 40;

  fill(167, 76, 78);
  curve(
    controlAx,
    controlAy,
    startAx,
    startAy,
    startBx,
    startBy,
    controlBx,
    controlBy
  );
  line(startAx, startAy, startBx, startBy);
}

function nose(centerX, centerY, size) {
  // nose
  line(
    centerX - size * 10,
    centerY + size * 20,
    centerX + size * 10,
    centerY + size * 20
  );
  curve(
    centerX - size * 20,
    centerY + size * 20,
    centerX - size * 10,
    centerY + size * 20,
    centerX - size * 6,
    centerY + size * 2,
    centerX - size * 20,
    centerY + size * 2
  );

  curve(
    centerX + size * 20,
    centerY + size * 2,
    centerX + size * 6,
    centerY + size * 2,
    centerX + size * 10,
    centerY + size * 20,
    centerX + size * 20,
    centerY + size * 20
  );
}

function eyes(centerX, centerY, size) {
  // eyes
  fill(220);
  ellipse(centerX - size * 25, centerY - size * 20, size * 25, size * 20);
  ellipse(centerX + size * 25, centerY - size * 20, size * 25, size * 20);
  fill(0);
  ellipse(centerX - size * 25, centerY - size * 18, size * 12, size * 12);
  ellipse(centerX + size * 25, centerY - size * 18, size * 12, size * 12);
  fill(255);
  ellipse(centerX - size * 25, centerY - size * 18, size * 3, size * 3);
  ellipse(centerX + size * 25, centerY - size * 18, size * 3, size * 3);

  //eyebrows
  rectMode(CENTER);
  fill(43, 43, 38);
  rect(
    centerX - size * 25,
    centerY - size * 36,
    size * 28,
    size * 8,
    size * 10
  );
  rect(
    centerX + size * 25,
    centerY - size * 36,
    size * 28,
    size * 8,
    size * 10
  );
}

function hair(centerX, centerY, size) {
  fill(16, 23, 38);
  // sideburns
  let x1 = centerX - size * 40;
  let y1 = centerY - size * 60;
  let x2 = centerX - size * 33;
  let y2 = centerY - size * 50;
  let x3 = centerX - size * 53;
  let y3 = centerY - size * 20;
  triangle(x1, y1, x2, y2, x3, y3);
  
  let x21 = centerX + size * 40;
  let y21 = centerY - size * 60;
  let x22 = centerX + size * 33;
  let y22 = centerY - size * 50;
  let x23 = centerX + size * 53;
  let y23 = centerY - size * 20;
  triangle(x21, y21, x22, y22, x23, y23);

  //hair
  let controlAx = centerX - size * 44;
  let controlAy = centerY - size * 45;

  let controlBx = centerX + size * 44;
  let controlBy = centerY - size * 45;

  let anchorAx = centerX - size * 50;
  let anchorAy = centerY - size * 85;

  let anchorBx = centerX + size * 50;
  let anchorBy = centerY - size * 85;

  bezier(
    controlAx,
    controlAy,
    anchorAx,
    anchorAy,
    anchorBx,
    anchorBy,
    controlBx,
    controlBy
  );
}

function ears(centerX, centerY, size) {
  //ears
  fill(206, 128, 80);
  arc(
    centerX - size * 50,
    centerY - size * 15,
    size * 25,
    size * 25,
    HALF_PI,
    PI + HALF_PI
  );
  arc(
    centerX + size * 50,
    centerY - size * 15,
    size * 25,
    size * 25,
    PI + HALF_PI,
    HALF_PI
  );
}

function beard(centerX, centerY, size, weight) {
  let beardStart = centerY + size * 25;

  strokeWeight(weight);
  // moustache
  for (let i = centerX - size * 25; i < centerX + size * 25; i += 3) {
    line(i, beardStart, i + 3, beardStart + size * 14);
  }
  for (let i = centerX - size * 25; i < centerX + size * 25; i += 3) {
    line(i, beardStart, i + 2, beardStart + size * 14);
  }

  // goatee
  for (let i = centerX - size * 30; i < centerX + size * 30; i += 3) {
    line(i, beardStart + size * 22, i + 3, beardStart + size * 40);
  }
  for (let i = centerX - size * 30; i < centerX + size * 30; i += 3) {
    line(i, beardStart + size * 25, i + 2, beardStart + size * 45);
  }
  for (let i = centerX - size * 20; i < centerX + size * 20; i += 3) {
    line(i, beardStart + size * 35, i + 3, beardStart + size * 50);
  }

  //sides
  for (let i = centerX - size * 43; i < centerX - size * 20; i += 3) {
    line(i, beardStart + size * 15, i + 3, beardStart + size * 30);
  }
  for (let i = centerX - size * 38; i < centerX - size * 18; i += 3) {
    line(i, beardStart + size * 15, i + 2, beardStart + size * 35);
  }

  for (let i = centerX + size * 20; i < centerX + size * 43; i += 3) {
    line(i, beardStart + size * 15, i + 3, beardStart + size * 30);
  }
  for (let i = centerX + size * 18; i < centerX + size * 38; i += 3) {
    line(i, beardStart + size * 15, i + 2, beardStart + size * 35);
  }

  //connectors
  for (let i = centerX - size * 30; i < centerX - size * 20; i += 3) {
    line(i, beardStart + size * 5, i + 3, beardStart + size * 20);
  }

  for (let i = centerX + size * 20; i < centerX + size * 30; i += 3) {
    line(i, beardStart + size * 5, i + 3, beardStart + size * 20);
  }

 // side burns
  for (let i = centerX - size * 50; i < centerX - size * 40; i += 3) {
    line(i, beardStart + size * 1, i + 2, beardStart + size * 20);
  }
  for (let i = centerX - size * 55; i < centerX - size * 48; i += 3) {
    line(i, beardStart - size * 10, i + 2, beardStart + size * 5);
  }

  for (let i = centerX + size * 40; i < centerX + size * 50; i += 3) {
    line(i + 2, beardStart + size * 1, i, beardStart + size * 20);
  }
  for (let i = centerX + size * 48; i < centerX + size * 55; i += 3) {
    line(i + 2, beardStart - size * 10, i, beardStart + size * 5);
  }
}