Judy Li-Final Project

judyli: Final Project

//Judy Li
//Section A
//judyli@andrew.cmu.edu
//Final Project

var yA = 1; //y-Axis
var c1; //color 1
var c2; //color 2
var x = [];
var gravity = 0.3; //downward acceleration
var springy = 1; //how much velocity is retained after bounce
var drag = 0.0001; //drag causes particles to slow down
var np = 25; //how many particles
var paperbirds = [];

function soot() {
    background(204, 174, 98);
    noStroke();
    fill("pink");
    ellipse(30, 30, 10, 10);
    fill(186, 220, 88);
    ellipse(25, 25, 10, 10);
    fill(126, 214, 223);
    ellipse(25, 40, 10, 10);
    fill("coral");
    ellipse(30, 35, 10, 10);
    fill(224, 86, 253);
    ellipse(40, 30, 10, 10);
    fill("white");
    ellipse(40, 40, 10, 10);
    fill(0);
    for (var i = 0; i < np; i++) {
        //make a particle
        var p = makeParticle(200, 200, random(-50, 50), random(-50, 50));
    }
    frameRate(10);
    sootDraw();
}

function sootDraw() {
    if (mouseIsPressed) {
        var newp = makeParticle(mouseX, mouseY, random(-10, 10), random(-10, 0), random(0, 50));
        particles.push(newp);
    }
    newParticles = [];
    for (var i = 0; i < particles.length; i++) { // for each particle
        var p = particles[i];
        p.step();
        p.draw();
        if (p.age < 200) {
            newParticles.push(p);
        }
    }
    particles = newParticles;
}

function birds() {
    setGradient(0, 0, width, height, c1, c2, yA); 
    drawClouds();
    nBird();
    nPosition();
    nArray();
    for (var i = 0; i < paperbirds.length; i++) {
        paperbirds[i].display();
    }
    frameRate(10);
    paperbirds.push(drawBirds());
}

function nBird() {
    if (random(50, 50) < 50) {
        paperbirds.push(drawBirds());
    }
}

function nPosition() {
    for (var i = 0; i < paperbirds.length; i++) {
        paperbirds[i].move();
    }
}

function nArray() {
    var ogBird = [];
    for (var i = 0; i < paperbirds.length; i++) {
        if (paperbirds[i].x > 0) {
            ogBird.push(paperbirds[i]);
        }
    }
    paperbirds = ogBird;
}

function moveBird() {
    this.x -= this.speed;
}

function seeBird() {
    stroke(225, 255, 255, 200);
    strokeWeight(random(1, 5));
    point(this.x, this.y);
    point(this.x + 2.5, this.y);
}

function drawBirds() {
    var paperbirds = {x: width,
        pdist: 100,
        speed: 5,
        birdsize: round(random(0, 5)),
        y: round(random(0, height)),
        move: moveBird,
        display: seeBird
        }
    return paperbirds;
}

function drawClouds() {
    noStroke();
    //cloud1
    fill(255, 255, 255, 200);
    ellipse(75, 75, 80, 50);
    ellipse(185, 75, 100, 60);
    ellipse(135, 75, 115, 75);
    //cloud2
    ellipse(240, 200, 70, 50);
    ellipse(380, 200, 100, 55);
    ellipse(420, 200, 75, 30);
    ellipse(300, 200, 120, 75);
    //cloud3
    ellipse(120, 360, 100, 40);
    ellipse(240, 360, 80, 50);
    ellipse(300, 360, 75, 30);
    ellipse(180, 360, 120, 75);
}

function particleStep() {
    this.age++;
    this.x += this.dx;
    this.y += this.dy;
    if (this.x > width) { // bounce off right wall
        this.x = width - (this.x - width);
        this.dx = -this.dx * springy;
    } else if (this.x < 0) { // bounce off left wall
        this.x = this.x;
        this.dx = -this.dx * springy;
    }
    if (this.y > height) { // bounce off bottom
        this.y = height - (this.y - height);
        this.dy = -this.dy * springy;
    } else if (this.y < 0) { // bounce off top
        this.y = -this.y;
        this.dy = -this.dy * springy;
    }
    this.dy = this.dy + gravity; // force of gravity
    // drag is proportional to velocity squared
    // which is the sum of the squares of dy and dy
    var vs = Math.pow(this.dx, 2) + Math.pow(this.dy, 2);
    // d is the ratio of old velocty to new velocity
    var d = vs * drag;
    // d goes up with velocity squared but can never be
    // so high that the velocity reverses, so limit d to 1
    d = min(d, 1);
    // scale dx and dy to include drag effect
    this.dx *= (1 - d);
    this.dy *= (1 - d);
    var rpx = width;
    var rpy = height;
    var f;
    var d;
    var rpc = 10;
    var x = this.x;
    var y = this.y;
    var dirx = (x - rpx) / d;
    var diry = (y - rpy) / d;
    d = dist(x, y, rpx, rpy);
    f = rpc / (Math.pow(d, 2));
    this.dx += dirx * f;
    this.dy += diry * f;
    point(rpx, rpy);
}

function particleDraw() {
    noStroke();
    fill(0);
    ellipse(this.x, this.y, this.size, this.size);
}

function setSize() {
    return random(5, 25);
}

function makeParticle(px, py, pdx, pdy, size) {
    p = {x: px, y: py,
         dx: pdx, dy: pdy,
         size: setSize(),
         age: 0,
         step: particleStep,
         draw: particleDraw
        }
    return p;
}

var particles = [];

function setup() {
    createCanvas(480, 480);
    //colors
    c1 = color(129, 236, 236);
    c2 = color(255, 234, 167);
}

function draw() {
    setGradient(0, 0, width, height, c1, c2, yA);
    placeForeground();
    if (mouseX < (width / 2) & mouseY < height) {
        soot();
    }
    if (mouseX > (width / 2) & mouseY < height) {
        birds();
    }
}

function placeForeground() {
    noStroke();
    //chim
    fill(150);
    quad(20, height, 30, 100, 50, 100, 60, height);
    fill(0);
    rect(30, 90, 20, 10);
    //big red
    fill(255, 82, 82);
    rect(90, 145, 300, 250);
    //grey
    fill(175);
    rect(80, 160, 80, 45);
    rect(100, 250, 60, 45);
    rect(315, 200, 90, 50);
    //top red
    fill(225, 82, 82);
    rect(110, 60, 260, 40);
    //mini rooms
    fill(205);
    rect(85, 170, 70, 30);
    rect(105, 260, 50, 30);
    rect(320, 210, 80, 35);
    rect(95, 105, 290, 40);
    //green
    fill(120, 180, 143);
    quad(75, 165, 85, 155, 155, 155, 165, 165);
    quad(95, 255, 105, 245, 155, 245, 165, 255);
    quad(310, 205, 320, 195, 400, 195, 410, 205);
    quad(80, 110, 100, 100, 380, 100, 400, 110);
    quad(90, 65, 200, 15, 280, 15, 390, 65);
    //bottom brown
    fill(139, 69, 19);
    rect(190, 280, 100, 12.5);
    rect(75, 205, 90, 7.5);
    rect(95, 295, 70, 7.5);
    rect(310, 250, 100, 7.5);
    //top brown
    fill(250, 211, 144);
    rect(200, 200, 80, 80);
    //outer red
    fill(200, 57, 57);
    rect(60, 330, 130, 100);
    rect(290, 330, 130, 100);
    //main entrance
    fill(250, 211, 144);
    rect(190, 325, 100, 50);
    //teal
    fill(120, 200, 143);
    quad(180, 325, 200, 315, 280, 315, 300, 325);
    quad(180, 210, 210, 180, 270, 180, 300, 210);
    //sign
    fill(255, 240, 195);
    ellipse(240, 180, 40, 20);
    ellipse(240, 15, 50, 25);
    ellipse(240, 315, 60, 10);
    //noStroke();
    fill(204, 174, 98);
    stroke(204, 174, 98);
    quad(0, width, width / 3, 360, 2 * (width / 3), 360, width, height);
    stroke(204, 142, 25);
    line(width / 3, 450, (2 * (width / 3)) + 140, 450);
    line((width / 3) - 140, 465, 2 * (width / 3), 465);
    stroke(179, 57, 57);
    strokeWeight(1);
    fill(179, 57, 57);
    triangle(0, height, 0, height - 45, 120, 369);
    triangle(width, height, width, height - 45, 360, 369);
    beginShape();
    curveVertex(0, height);
    curveVertex(0, height);
    curveVertex(35, 430);
    curveVertex(72.5, 395);
    curveVertex(115, 370);
    curveVertex(width / 3, 360);
    curveVertex(width / 3, 360);
    endShape();
    beginShape();
    curveVertex(2 * (width / 3), 360);
    curveVertex(2 * (width / 3), 360);
    curveVertex(365, 370);
    curveVertex(407.5, 395);
    curveVertex(445, 430);
    curveVertex(width, height);
    curveVertex(width, height);
    endShape();
}

function setGradient(x, y, w, h, c1, c2, axis) {
    noFill();
    if (axis == yA) {//top > bottom gradient
        for (var i = y; i <= y + h; i++) {
            var inter = map(i, y, y + h, 0, 1);
            var c = lerpColor(c1, c2, inter);
            stroke(c);
            line(x, i, x + w, i);
        }
    }
}

For the final project, I wanted to recreate three of my favorite scenes in the movie, Spirited Away. The first scene shows bridge and the exterior of the bath house. Since this building is famous in the movie, I wanted to start my project out with this first background image. When you move you mouse in the left hand side within the bounding box, it moves onto a new background/scene. This scene is the part when Chihiro is interacting with the soot creatures. She throws candy onto a corner of the floor so that the soot would get away from her. To go back to the original/first scene, you would just move your mouse down and out of the bounding box. And for the third scene, I remade the part that shows the flying paper birds through a simple animation. I really enjoyed that scene because it was really aesthetically filmed/made in the movie and I wanted to incorporate that.

Yingying Yan – Final Project

In architecture, we often have to use brushes in Photoshop. A good brush often makes a drawing very successful. Thus for this project, I decided to render a brush with cubes rotating at different angles with a change in gradient depending on the number of cubes that are drawn. Since WebGL does not support text, I could not explain the direction on the canvas. But ways the users can interact with the brush are: “h” = erase the canvas, “j” = turn off the randomness in size, after pressing j, the user can press “l” to make the cubes bigger, or “k” to make the cubes smaller. The user can also press a to increase the speed of rotation.

sketch

/*
Yingying Yan
Final Project_ Cube Brush
Section E
*/

var cube = []; // the array that stores all the cubes;
var count = 1; // keeps track of the number of cubes
var rr; //color 1
var bb; //color 2

//parameters that are controlled by the keys
var angle = 0; // the rotation of the cubes
var cSize; // the size of the cubes
var bigger = 10; // using key to make the size bigger
var turn = 0.01;
var randomm = true;// use key to turn off randomness of the size


function setup() {
    createCanvas(400,400, WEBGL);
    rr = color(204, 102, 0);
    bb = color(0, 102, 153);
}

function draw() {
    background(220);
    //the orgin for WEBGL is center, move it back to the p5js orgin
    translate(-width / 2, -height / 2);
    //space between the cubes
    var f = frameCount % 2 == 0
    //the size of each cube
    if (randomm) {
        cSize = random(5, 20);
    } else {
        cSize = bigger;
    }
    
    for (var i = 0; i < cube.length; i++) {
         cube[i].draw()

    } 
    //users drawing the cubes
    if (mouseIsPressed) {
        if (f) {
        var ccube = makeCube( cSize, cSize, cSize, mouseX, mouseY, turn);
        count += 1;
        cube.push(ccube);
        }
    }
}

//how the users can interact with the brush by pressing different keys

function keyPressed() {
    //erasing everything
    if (key == "h") {
        cube = [];
        count = 0;
        randomm == true;
        turn = 0.01;
    }

    //turn off randomness in sizes
    if (key == "j") {
        randomm = !randomm;
    }

    //make the cubes bigger after turning off the randomness
    if (key == "l") {
        bigger += 10;
    }

    //make the cubes smaller after turning off the randomness
    if (key == "k") {
        bigger -= 5;
    }
    //make the cubes spin faster
    if (key == "a") {
        turn += 0.1
    }
}


function makeCube (x, y, d, px, py, turn) {
    //use a color gradient depending on the number of cubes that are drawn
    var r = lerpColor(rr, bb ,sin(count / 30));
    //make the color more transparent
    var color_trans = (color(red(r), green(r), blue(r),120));

    return{ x: x,
            y: y,
            d: d,
            px: px,
            py:py,
            ang: random(0,90),
            tturn:turn,
            c: color_trans,
            draw: drawCube
        }
}


function drawCube() {
    //rotate around the corner
    rectMode(CORNER);
    noStroke();
    fill (this.c);
    //drawing the cube with rotation
    push();
    translate(this.px, this.py)
    rotateX(this.ang);
    rotateY(this.ang * 0.2);
    rotateZ(this.ang* 1.5);
    box(this.x, this.y, this.d);
    this.ang += this.tturn;
    pop();

}

Jenni Lee — Final Project

sketch

/* Jenni Lee
Section E
jennife5@andrew.cmu.edu
Final Project
*/

var tapirImage = [];
var cloudImage = [];
var clouds = [];
var plantImage = [];
var plants = [];

var numMovingFrame = 2;

function preload() {

  var filenames = [];
  // image location for tapir
  filenames[0] = "https://i.imgur.com/DW5kRkh.png";
  filenames[1] = "https://i.imgur.com/4KccJ7e.png";

  // image location for plants
  filenames[2] = "https://i.imgur.com/CICxu5P.png";
  filenames[3] = "https://i.imgur.com/KObxJ71.png";
  filenames[4] = "https://i.imgur.com/IYuCsVt.png";

  // image location for clouds
  filenames[5] = "https://i.imgur.com/w9ND0YA.png";
  filenames[6] = "https://i.imgur.com/6Ovkd5e.png";
  filenames[7] = "https://i.imgur.com/JH0DqMf.png";


  // PUT CODE HERE TO LOAD THE IMAGES INTO THE frames ARRAY,
  // USING THE FILENAMES STORED IN THE filenames ARRAY.

  for (var i = 0; i < numMovingFrame; i++) {
    tapirImage[i] = loadImage(filenames[i]);
  }

  for (i = 0; i < 3; i++) {
    plantImage[i] = loadImage(filenames[i + 2]);
  }

  for (i = 0; i < 3; i++) {
    cloudImage[i] = loadImage(filenames[i + 5]);
  } 
}

var ibuffer = 120; // buffer space (minimum distance) between two plants for jumping
function setup() {
  createCanvas(1000, 300);
  initiate();
  frameRate(30);
  textFont('Helvetica');
}

var currentTapirImageIndex = 0; // rotating tapir images to simulate tapir movement
var tapirLocationX = 80;
var tapirLocationY = 80;
var upperYJump = 200,
  lowerYJump = 80;
var speed = 3; // jump speed per frame
var jumpSpeed = 3;
var tapirMinHeight = 120;
var jumpStatus = false; // use this to tell if tapir is jumping or not
var tapirInPlantRangeCurr = []; // to record if tapir is in the plant range or not, the current state
var tapirInPlantRangePrev = []; // to record if tapir is in the plant range or not, the previous state
var numPlantsJumped = 0; // count total # of plants tapir jumps over
var isGameOver = false;

function initiate() {

  // create an initial collection of clouds
  for (var i = 0; i < 10; i++) {
    var rx = random(width); // randomly generate clouds at random locations to start with
    clouds[i] = makeCloud(rx);
  }
  // create an initial collection of plants
  for (i = 0; i < 6; i++) { // fixed location for plants, for jumping practice
    plants[i] = makePlant(230 + i * 180);
  }

  tapirLocationY = lowerYJump; // back to original position
  jumpSpeed = 3; // for tapir's jump speed
  jumpStatus = false; // to keep track if tapir is in jumping state or not
  isGameOver = false;
  numPlantsJumped = 0;
  currentTapirImageIndex = 0;
  for (i = 0; i < 10; i++) {
    tapirInPlantRangePrev[i] = false;
    tapirInPlantRangeCurr[i] = false;
  }
}

function draw() {
  background(229, 233, 137);

  noStroke();
  fill(70, 83, 130);
  rect(0, 0, width - 1, height - 51);

  // handling cloud display, the bottom layer of objects
  updateAndDisplayClouds();
  removeCloudsThatHaveSlippedOutOfView();
  addNewCloudsWithSomeRandomProbability();

  // draw terrain, next layer of object
  drawTerrain();

  // handling plants display, next layer of objects
  updateAndDisplayPlants();
  removePlantsThatHaveSlippedOutOfView();
  addNewPlantsWithSomeRandomProbability();

  // check the jumping status and display tapir
  updateTapirStatus();
  checkTapirOverPlant();
  
  // display the status such as # of total plants jumped, score
  displayStatusString();
}

function checkTapirOverPlant() {
  // check if tapir is inside any plant range
  for (var i = 0; i < plants.length; i++) {
    if (plants[i].x <= tapirLocationX + tapirImage[0].width) {
      if (plants[i].x + plantImage[plants[i].nPlantType].width >= tapirLocationX + tapirImage[currentTapirImageIndex].width) {
        tapirInPlantRangePrev[i] = tapirInPlantRangeCurr[i];
        tapirInPlantRangeCurr[i] = true;
        if (tapirLocationY < tapirMinHeight) {
          noStroke();
          fill(0, 0, 0);
          textSize(20);
          text("Game Over. Touch screen, click mouse, or press 'r' to restart.", width / 2 - 230, height / 2);
          isGameOver = true;
          noLoop();
        }
      } else {
        tapirInPlantRangePrev[i] = tapirInPlantRangeCurr[i];
        tapirInPlantRangeCurr[i] = false;
      }
    }
    if (tapirInPlantRangePrev[i] == true & tapirInPlantRangeCurr[i] == false) {
      numPlantsJumped++;
    }
  }
}

function updateTapirStatus() {
  if (jumpStatus == true) {
    tapirLocationY += jumpSpeed;
    if (tapirLocationY >= upperYJump) { // tapir hit top jupming point, change direction
      tapirLocationY = upperYJump;
      jumpSpeed = -1 * speed;
    } else if (tapirLocationY < lowerYJump) {
      tapirLocationY = lowerYJump;
      jumpSpeed = speed;
      jumpStatus = false;
    }
  }
  image(tapirImage[currentTapirImageIndex], tapirLocationX, height - tapirLocationY);

  if (jumpStatus == false) {
    currentTapirImageIndex++;
  }
  currentTapirImageIndex = currentTapirImageIndex % numMovingFrame; // rotating tapir images

}

function keyTyped() {
  if (key == "a") {
    jumpStatus = true;
  } else {
    jumpStatus = false;
  }
  if (key == "r") {
    if (isGameOver == true) {
      initiate();
      loop();
    }
  }
}

function touchStarted() {
  if (isGameOver == true) {
    initiate();
    loop();
  }
  else {
    jumpStatus = true;
  }
}

// define object for plant
function makePlant(birthLocationX) {
  var plant = {
    x: birthLocationX,
    y: height - 40,
    speed: -2.1,
    nPlantType: round(random(0, 2)),
    move: plantMove,
    display: plantDisplay
  }
  return plant;
}

function plantMove() {
  this.x += this.speed;
}

function plantDisplay() {
  imageMode(CORNERS);
  image(plantImage[this.nPlantType], this.x, this.y,
    this.x + plantImage[this.nPlantType].width, this.y - plantImage[this.nPlantType].height);
  imageMode(CORNER);

}

function updateAndDisplayPlants() {
  // Update the building's positions, and display them.
  for (var i = 0; i < plants.length; i++) {
    plants[i].move();
    plants[i].display();
  }
}

function removePlantsThatHaveSlippedOutOfView() {
  var plantsToKeep = [];
  for (var i = 0; i < plants.length; i++) {
    if (plants[i].x + plantImage[plants[i].nPlantType].width > 0) {
      plantsToKeep.push(plants[i]);
    }
  }
  plants = plantsToKeep; // remember the surviving plants
}

function addNewPlantsWithSomeRandomProbability() {
  var newPlantLikelihood = 0.05;
  var toAddPlant = true;
  if (random(0, 1) < newPlantLikelihood) {
    var i = plants.length - 1;
    // make sure there is at least ibuffer distance from previous plant before adding a new one from right
    if (plants[i].x + plantImage[plants[i].nPlantType].width + ibuffer < width) {
      plants.push(makePlant(width));
    }
  }
}

// define object for cloud
function makeCloud(birthLocationX) {
  var cld = {
    x: birthLocationX,
    y: round(random(25, 50)),
    speed: -0.6,
    nCloudType: round(random(0, 2)),
    move: cloudMove,
    display: cloudDisplay
  }
  return cld;
}

function cloudMove() {
  this.x += this.speed;
}

function cloudDisplay() {
  image(cloudImage[this.nCloudType], this.x, this.y);
}

function updateAndDisplayClouds() {
  // Update the cloud's positions, and display them.
  for (var i = 0; i < clouds.length; i++) {
    clouds[i].move();
    clouds[i].display();
  }
}


function removeCloudsThatHaveSlippedOutOfView() {
  var cloudsToKeep = [];
  for (var i = 0; i < clouds.length; i++) {
    if (clouds[i].x + cloudImage[clouds[i].nCloudType].width > 0) {
      cloudsToKeep.push(clouds[i]);
    }
  }
  clouds = cloudsToKeep; // remember the surviving clouds
}

function addNewCloudsWithSomeRandomProbability() {
  var newCloudLikelihood = 0.004;
  if (random(0, 1) < newCloudLikelihood) {
    clouds.push(makeCloud(width)); // push the new cloud to the clouds array (to the end)
  }
}


function displayStatusString() {
  noStroke();
  fill(0, 200, 0);
  textSize(14);
  text("Touch screen, click mouse, or press 'a' to jump", 5, 20);
  textSize(40);
//  var statusString = "# Plants jumped over = " + numPlantsJumped;
  var statusString = numPlantsJumped;
  text(statusString, width/2, height/2 - 25);
}

function drawTerrain() {
  noFill();
  beginShape();
  var terrainSpeed = 0.00012;
  var terrainDetail = 0.005;

  for (var x = 0; x < width; x++) {
    var t = (x * terrainDetail) + (millis() * terrainSpeed);
    var y = map(noise(t), 0, 1, 0, height - 40);
    stroke(216, 158, 172);
    line(x, y, x, height - 50);
  }
  endShape();
}

For this project, I wanted to create a game of a tapir that jumps over flowers. Tapirs are my favorite animal, so I wanted to use that. I drew all pictures, clouds, tapir, and plants, on Adobe Illustrator to load them at preLoad time for various effects, and use image() function to display them all at specified locations when they are inside canvas range. I drew 3 types of clouds, and design/define a cloud object to record and keep track of the cloud type/shape (randomly selected), location (x and y), and movement speed. Mountain/terrain: I used noise() function to draw vertical line from a variable y location to the ground to simulate mountain. I drew two frames of tapir to simulate its running. When loading different frames at consecutive frames, it would seem tapir is running. Overall, this project was really fun.

Alexandra Kaplan – Final Project

Instructions:

To operate the television, click the power button and use the up and down buttons to cycle through the channels. Come back at a different time of the day to see what else is on! Make sure your webcam access is allowed as well.

Turn on the TV!



var power = false; // power starts off

var h; // hour

var gCLickCount; // track mouse clicks
var channelIsCurrently = 0; // what index of the array is at
var channel = []; // array to store current videos

var myCaptureDevice; // laptop camera

var chanDistUp; // distance to channel up
var chanDistDown; // distance to channel down
var powDist; // distance to power button

var videos;

var buttonsPositionX = 485;

var powerbutton = {x: buttonsPositionX, y: 230, d: 60, render:drawPowerButton, 
                   strokecol:'burlywood', col:'lightyellow', 
                   labelcol:'burlywood'};
var channelUp = {x: buttonsPositionX, y:390 , w:60 , h:60 , render:drawChannelUp, 
                strokecol:'burlywood', col:'lightyellow'};
var channelDown = {x: buttonsPositionX, y:450 , w:60 , h:60 , render:drawChannelDown, 
                   strokecol:'burlywood', col:'lightyellow'};
                   
function setup() {
    createCanvas(550, 600);


    frameRate(30);
    myCaptureDevice = createCapture(VIDEO);
    myCaptureDevice.size(350, 308); // attempt to size the camera. 
    myCaptureDevice.hide(); // this hides unnecessary extra view.

    h = hour(); // what time is it?

    //load videos, assign each video a variable
    var mVid1 = createVideo('https://i.imgur.com/6OBMn2v.mp4');
    var mVid2 = createVideo('https://i.imgur.com/X73HsOP.mp4');
    var mVid3 = createVideo('https://i.imgur.com/AHmztFm.mp4');
    var aVid1 = createVideo('https://i.imgur.com/wNWUrAi.mp4');
    var aVid2 = createVideo('https://i.imgur.com/5nEKwzC.mp4');
    var aVid3 = createVideo('https://i.imgur.com/FbpKnv0.mp4');
    var eVid1 = createVideo('https://i.imgur.com/ziaEsYx.mp4');
    var eVid2 = createVideo('https://i.imgur.com/4kGyLnf.mp4');
    var eVid3 = createVideo('https://i.imgur.com/arD9T0D.mp4');
    var nVid1 = createVideo('https://i.imgur.com/5IfBxXm.mp4');
    var nVid2 = createVideo('https://i.imgur.com/ziyI0g4.mp4');
    var nVid3 = createVideo('https://i.imgur.com/fPyKK17.mp4');

    videos = [mVid1, mVid2, mVid3, aVid1, aVid2, aVid3, eVid1, 
              eVid2, eVid3, nVid1, nVid2, nVid3]; // array of video variables

    for (var i = 0; i < videos.length; i++){
        videos[i].hide(); //hide off canvas videos
        videos[i].loop(); // play videos on loop
    }
    // Which videos are on the different channels
    // if the hour is before 6 am
    if(h <= 6){ 
        channel = [mVid1, mVid2, mVid3];
    // if hour is between 6am and 12 pm
    }else if (h > 6 & h <= 12){ 
        channel = [aVid1,aVid2, aVid3];
    // if hour is between 12apm and 6pm
    }else if(h > 12 & h <= 18){
        channel = [eVid1, eVid2, eVid3];
    // if hour is after 6pm
    }else{
        channel = [nVid1,nVid2, nVid3];
    } 

}

function draw() {
     scale(0.8, 0.8)
    // distance between mouse click and the different buttons
    chanDistUp = dist(mouseX, mouseY, channelUp.x * 0.8, channelUp.y * 0.8); 
    chanDistDown = dist(mouseX, mouseY, channelDown.x * 0.8, channelDown.y * 0.8);
    powDist = dist(mouseX, mouseY, powerbutton.x * 0.8, powerbutton.y *0.8);

    television(0, 40);

    // if the tv is on, show the video on the current channel
    if(power === true){
        image(channel[channelIsCurrently % channel.length], 
            buttonsPositionX - 444, 192, buttonsPositionX - 138, 305);
    }

    //if tv is off, you see your reflection on the screen
    if(power === false){
        myCaptureDevice.loadPixels(); // this must be done on each frame.
        push();
        tint(100, 50); // Display at half opacity
        image(myCaptureDevice, buttonsPositionX - 440, 190); // draw the camera
        pop();
    } 

    //random tv noise, higher mouseY and mouseX is more noise
    if(power === true){
        for (var i = 0; i < mouseY + mouseX * 2; i++) {
            var r = random(0, 255);
            var g = random(0, 255);
            var b = random(0, 255);
            stroke(r, g, b);
            point(random(buttonsPositionX - 445, 388), 
                random(buttonsPositionX - 298, 497));
        }
    }
}

function mousePressed(){

    //click the channel up/down buttons when the power is on, 
    //the video will change
    if(chanDistUp < channelUp.w / 2 & power === true) {
        channelIsCurrently += 1;
    }
    if(chanDistDown < channelDown.w / 2 & power === true){
        channelIsCurrently -= 1;
        if(channelIsCurrently < 0){ // channels cycle, never goes above 2
            channelIsCurrently = 2;
        }
    }

    // if you click the power button, the tv will turn on
    if(powDist < 30 & power === false){
        power = true;
    } else if (powDist < 30) {
        power = false;
    }
}

function drawPowerButton() {
    ellipseMode(CENTER);
    strokeWeight(10);
    stroke(powerbutton.strokecol);
    fill(powerbutton.col);
    ellipse(powerbutton.x, powerbutton.y, powerbutton.d, powerbutton.d);
   
    // power symbol
    strokeWeight(3);

    // hovering over the symbol changes its color
    if(powDist < 30){
        stroke(150);
    }else{
        stroke(powerbutton.labelcol);
    }

    // power symbol
    noFill();
    arc(buttonsPositionX, 232, 25, 25, PI + 2.5, PI + 7);
    line(buttonsPositionX, 220, buttonsPositionX, 232);
}

function drawChannelUp() {
    rectMode(CENTER);
    strokeWeight(10);
    stroke(channelUp.strokecol);
    fill(channelUp.col);
    rect(channelUp.x, channelUp.y, channelUp.w, channelUp.h, 5, 5);
    strokeWeight(0);
    // hovering over the symbol changes its color
    if(chanDistUp < 30){
        fill(150);
    }else{
        fill(channelUp.strokecol)
    }
    textAlign(CENTER);
    textSize(40);
    text('+', channelUp.x, channelUp.y + 10);
}

function drawChannelDown(){
    rectMode(CENTER);
    strokeWeight(10);
    stroke(channelDown.strokecol);
    fill(channelDown.col);
    rect(channelDown.x, channelDown.y, channelDown.w, channelDown.h, 
        5, 5);
    strokeWeight(0);
    // hovering over the symbol changes its color
    if(chanDistDown < 30){
        fill(150);
    }else{
        fill(channelDown.strokecol);
    }
    textAlign(CENTER);
    textSize(40);
    text('-', channelDown.x, channelDown.y + 10);
}

function television(x, y){
    rectMode(CORNER);

    //tv body
    stroke(63, 44, 35);
    strokeWeight(5);
    fill(63,44,35); 
    rect(0, y + 65, width, y + 440, 30, 30); 

    //tv body
    fill('lightyellow');
    rect(x + 10, y + 80, x + 425, y + 410, 10, 10); 

    // screen
    fill(131, 123, 105);
    stroke(63, 44, 35);
    rect(x + 40, 190, 350, 308); 

    // place for tv knobs
    fill(101,69,56);
    strokeWeight(15);
    rect(x + 425, y + 85, x + 115, y + 400); 
    strokeWeight(10);
    stroke(63, 44, 35);
    line(x + 320, 5, x + 390, 105);
    line(x + 420, 5, x + 400, 105);

    drawPowerButton(); // power button
    drawChannelUp(); // channel up
    drawChannelDown(); // channel down 
}

Statement:

For my final project, I wanted to create a television that had different “programs” on at different times of the day. I was able to create this with a set of 12 different videos, three each for four different times of day (12am-6am, 6am-12pm, 12pm-6pm, 6pm-12am). I also had the buttons on the tv be mouse responsive: when hovering over the buttons they change a different color. As stated in my proposal, I was able to add a webcam component for when the tv is ‘off’ as if you were reflected in the screen like a glass tv. I added some noise on top of the videos controlled by mouse x and mouse y positions.

I feel like this project solidified a lot of the concepts we have learned throughout this semester. I definitely have a better grasp on how I can use p5.js in the future on my own projects as well as the core concepts behind computer programming.

Austin Treu – Final Project

atreu-final_project

How to run: download and unzip the folder, then open the index.html file in your browser of choice, mine being Firefox.

For my final project, I worked utilizing turtle graphics to create a game and drawing software. I used the turtles like a snake from the game of the same name. Thus, I decided on the name Snakle for my game. The main game is a two player competitive game in which each player is trying to make their snakle the longest by outlasting the other player. Player one is blue and player two is red. The game keeps track of score and displays the winner after each round, so the players can continue playing to a certain score. The drawing feature is based off of a similar concept to that of the game, where you control a single snakle in four directions with a color palette. It works very similarly to an Etch-A-Sketch, but you can click to move the snakle elsewhere.

Start screen:

Help Screen:

Game:

Etch-A-Sketch:

 

Dani Delgado and Elena Deng – Final Project

Click to make music!

sketch

/*
Elena Deng and Dani Delgado
Section E
edeng1 and ddelgad1
Final Project
*/

//variables to load sounds into

var ellipseSound;
var arcSound;
var squareSound;
var triSound;
var bgs;
//create the slider to control bg noise pan
var sliderPan;
//variables to inciment the bg
var volInc;
var pitchInc;
//stores the amount of mouse clicks
var mouseClick = 0;
//variables for the bg graphic based on amplitude
var amp;
var volhistory = [];

var objects = []; //sets the array for objects

var bright = 1; //sets the brightness of the screen+background

var xe = []; //sets the x pos array for the centroid
var ye = []; //sets the y pos array for the centroid


function preload() {
    //load all of the sounds into the file
    ellipseSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/ellipseDrip.mp3");

    squareSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/bloopSquare.mp3");

    arcSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/bong.mp3");

    triSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/ding.mp3");

    bgs = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/whiteNoise.mp3");
}

function setup() {
    createCanvas(640, 480);
    frameRate(14);
    angleMode(DEGREES);
    //play bg sound
    bgs.loop();
    bgs.setVolume(1.5);
    //get amplitude
    amp = new p5.Amplitude();
    //create pan slider
    sliderPan = createSlider(-1, 1, 0, 0.01);
    sliderPan.size(640, AUTO);

    for (var i = 0; i < 7; i++) {  //sets the centroid points
        var t = map(i, 0, 7, 0, TWO_PI);
        xe.push(width / 2 + 75 * cos(t));
        ye.push(height / 2 + 75 * sin(t));
    }
}

function draw() {
    background(10, 10, bright); //everytime the mouse is pressed, background brightness increases/decreases
    bright = bright - 5;
    if (mouseIsPressed) {
        bright = 110;
    }
    //pan slider
    bgs.pan(sliderPan.value());
    //get bgs amplitude and apply it the the graphic
    //the graphic is made from a "begin and end shape" method
    //and mapping of amps is made in a forloop
    var vol = amp.getLevel();
    volhistory.push(vol);
    push();
    frameRate(40);
    translate(width / 2, height / 2);
    //create the outer circle
    beginShape();
    strokeWeight(5);
    stroke(20, 20, -bright, 80);
    noFill();
    for (var i = 0; i < 360; i++) {
        var r = (map (volhistory[i], 0, 1, 10, 100)) * 18;
        var x = r * cos(i);
        var y = r * sin(i);
        vertex(x, y);
    }
    endShape();
    //create the inner circle
    beginShape();
    strokeWeight(0.5);
    stroke(80, 80, -bright);
    noFill();
    for (var i = 0; i < 360; i++) {
        var r = (map(volhistory[i], 0, 1, 10, 100)) * 17;
        var x = r * cos(i);
        var y = r * sin(i);
        vertex(x, y);
    }
    endShape();

    if (volhistory.length > 360) {
        volhistory.splice(0, 1);
    }
    pop();

    for (var i = 0; i < objects.length; i++) { //sets the order of the objects
        if (objects[i].type == "circle") {
            drawCir(objects[i]);
        }
        if (objects[i].type == "rect") {
            drawRect(objects[i]);
        }
        if (objects[i].type == "tri") {
            var change = random(0, 2)
            drawTri(objects[i].x, objects[i].y, objects[i].s + change);
        }
        if (objects[i].type == "centroid") {
            drawCentroid();

        }
    }
}

function mousePressed() {
    //variables for sounds made to easily reset the mouse clicks
    var firstSound = mouseClick < 10;
    var secondSound = mouseClick >= 10 & mouseClick <= 20;
    var thirdSound = mouseClick > 20 & mouseClick <= 30;
    var fourthSound = mouseClick > 30 & mouseClick <= 40;
    //images and sounds are based on mouse clicks
    if (firstSound) {
        //this code is to play the sounds
        //only allows a sound effect to be triggered if it's not playing
        //that way theres no overlap of sounds
        if(!ellipseSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 5, 0.09);
            pitchInc = map(mouseX, 0, 640, 0.25, 1.25);
            ellipseSound.play();
            ellipseSound.setVolume(volInc);
            ellipseSound.rate(pitchInc);
        }
        //pan the sounds based on mouse click
        //you'll hear it in every other ear every other click
        if (mouseClick % 2) {
            ellipseSound.pan(-1.0);
        } else {
            ellipseSound.pan(1.0);
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        objects.push(createCir(mouseX, mouseY)); //creates the circle for the first ten mouse clicks
    }

    if (secondSound) {
        if(!squareSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 8, 1.5);
            pitchInc = map(mouseX, 0, 640, 0.25, 1.75);
            squareSound.play();
            squareSound.setVolume(volInc);
            squareSound.rate(pitchInc);
            // if (mouseClick % 2){
            //     squareSound.pan(-1.0);
            // } else {
            //     sqaureSound.pan(1.0);
            // }
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        objects.push(createRect(mouseX, mouseY)); //creates the square/rect for the next ten mouse clicks
    }

    if (thirdSound) {
        if(!triSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 7, 0.5);
            pitchInc = map(mouseX, 0, 640, 0.5, 1.75);
            triSound.play();
            triSound.setVolume(volInc);
            triSound.rate(pitchInc);
        }
        if (mouseClick % 2) {
            triSound.pan(-1.0);
        } else {
            triSound.pan(1.0);
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        objects.push(createTri(mouseX, mouseY, random(1, 2))); //creates the diamond for the next ten mouse clicks
    }

    if (fourthSound) {
        if(!arcSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 8, 0.5);
            pitchInc = map(mouseX, 0, 640, 0.25, 1.25);
            arcSound.play();
            arcSound.setVolume(volInc);
            arcSound.rate(pitchInc);
        }
        if (mouseClick % 2) {
            arcSound.pan(-1.0);
        } else {
            arcSound.pan(1.0);
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        xe.push(mouseX);
        ye.push(mouseY);
        objects.push(createCentroid()); //creates the centroid for the next ten mouse clicks
    }
    if (mouseClick > 40) {
        mouseClick = firstSound; //mouseClicks resets the cycle
    }
    //increment the mouse clicks
    mouseClick ++;
}

function createCir(bx,by) { //creates the circle
    return {x:bx, y:by, type: "circle", oDiam: 0};
}

function drawCir(cir) { //draws the circle
    for (var i = 0; i < 10; i++) {
        var diam = cir.oDiam - 70 * i; //adjusts the drip spacing effect
        if (diam > 0) {
            var fade = map(diam, 0, width / 2, 100, 255); //sets the color
            strokeWeight(map(diam, 0, width, 12, 1)); //stroke weight decreases as circle gets larger
            stroke(fade, fade / 1.3, fade / 2, 85);
            noFill();
            ellipse(cir.x, cir.y, diam / 2); //draws ellipse
        }
    }
    cir.oDiam = cir.oDiam + 2; //increases size of the circle
    if (cir.oDiam > height / 2) { //once circle is larger than height/2 then the circle enlargement speed decreases
        cir.oDiam -= 1.25;
    }
}

function createRect(bx,by,bs) {
    return {x:bx, y:by, s:bs, type: "rect", oRect: 210}
}

function drawRect(square) {
    noStroke();
    rectMode(CENTER);

    for (var i = 0; i < 6; i++) {
        var recta = square.oRect - 100 * i; //sets the frequency/size of squares
        if (recta < 0) {
            var fade = map(recta, 0, width / 2, 255, 180); //maps the color
            strokeWeight(10)
            stroke(fade, fade / 1.3, fade / 2); //sets the color fade
            noFill();
            rect(square.x, square.y, recta / 2, recta / 2); //draws the square
        }
    }
    square.oRect = square.oRect - random(-2, -4); //shrinks square at random rates
}

function createTri(bx, by, bs) { //creates the diamond
    return {x:bx, y:by, s:bs, type: "tri"}
}

function drawTri(bx, by, bs) { //draws the diamond
    var smashorpass = random(-1, 10); //sets the random rate at which the shapes twinkle
    var smashthenpass = random(-1, 5);
    noStroke();
    //draws the first diamond
    fill(map(by, 0, height, 200, 255), map(by, 0, height, 120, 225), map(by, 0, height, 40, 85));
    quad(bx - 10 + bs - smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by - 30 + bs - smashthenpass, bx + 10 + smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by + 30 + bs + smashthenpass);

    strokeWeight(2); //draws the second diamond outline
    stroke(255, 230, 215, 70);
    noFill();
    quad(bx - 15 + bs - smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by - 35 + bs - smashthenpass, bx + 15 + smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by + 35 + bs + smashthenpass);

}

function createCentroid() { //creates the centroid
    return {type: "centroid"};
}

function drawCentroid() { //draws the centroid
    noStroke();
    fill(map(ye, 0, height, 200, 255), map(ye, 0, height, 120, 225), map(ye, 0, height, 40, 85));

    // moving the components of the centroid
    var nPoints = xe.length;
    for (var i = 0; i < nPoints; i++) {
        xe[i] += (noise(i * 1 + millis() / 500.0) - .5) * 10;
        ye[i] += (noise(i * 2 + millis() / 500.0) - .5) * 10;
        ellipse(xe[i], ye[i], 30, 30);
    }
    // draw the dots on the outside
    for (var i = 0; i < nPoints; i++) {
        ellipse(xe[i], ye[i], 1, 1);
    }
    // finding the average of the dots (x,y)
    var xAverage = 0;
    var yAverage = 0;
    for (var i = 0; i < nPoints; i++) {
        xAverage += xe[i];
        yAverage += ye[i];
    }
    xAverage /= nPoints;
    yAverage /= nPoints;
    // draws line from center to the points
    strokeWeight(4);
    stroke(255, 255, 255, 10);
    for (var i = 0; i < nPoints; i++) {
        line(xe[i], ye[i], xAverage, yAverage);
    }
    // Draw the centroid
    stroke(0);
    strokeWeight(2);
    ellipse(xAverage, yAverage, 10, 10);
}

For our final project, we wanted to create a “digital instrument” which synthesizes user interaction, sound, and generative visuals. We decided to start with a simple background which not only contains a graphic that reacts to the amplitude of the played music, but also flashes brighter when the user clicks in. From there, we added different graphics and corresponding sound effects to increase visual and audio interest. These graphics all have unique movements and correlate to the sound, while the sound effects change based on the mouseX and mouse Y position. As the user clicks, they’ll explore a range of different sounds and shapes that are placed on a loop which resets after every 40 clicks. Also, as they click, the sounds’s panning will change with every other click (e.x. click once, sound effect will play in one ear and click again, it’ll play in the other).

Here are some screenshots of possible screens you would get by interacting with this project!

shape 1: ripples
shape 2: squares
shape 3: diamonds
shape 4: centroid

We really enjoyed working on this project and exploring how different sounds and visuals interact and affect one another! We had difficulty at the beginning decided on exactly what we wished to do, but once we got the ball rolling things started to fall into place!

Since this was a partner project, we divided up the work to make it manageable and easier to code (as two people working on one computer would be slow and painful on our friendship). So we split the work up into such parts:
Elena Deng created the objects and visuals.
Dani Delgado edited the sound effects and created the background graphic.
Together we worked on debugging the code and adding the intended effects.

We hope you click around and have fun!

Katherine Hua and Min Lee – Final Project

sketch

/*
Katherine Hua, Min Lee
Section A
khua@andrew.cmu.edu, mslee@andrew.cmu.edu
Final Project
*/

var characters = []; // images of the characters are loaded into this array
var mushroom; // image of mushroom that represents # of lives left is loaded into this variable
var cloud; // image of cloud is loaded into this variable
var cloudsX = []; //cloud's randomized x positions will be loaded into this array
var cloudsY = []; //cloud's randomized y positions will be loaded into this array 
var cloudsSpeed = []; // cloud's randomized speed will be loaded into this array

var gameMode = 0; // determines which screen you see; title screen = 0, game = 1, game over = 2, instructions = 3
var lives = 3; // you start out with 3 lives 
var score = 0; // you begin with a score of 0

var characterIndex; //assigns a number value to a character 
var pipeNumber; // //assigns each pipe a number value
var characterX; //keeps track of the character's X values
var characterY = 180; //keeps track of the character's Y values
var characterSpeed = -3; // //keeps track of the character's speed
var pipesOccupied; //the pipe number that's occupied by a character
var newIndex; //new number value assigned to character

function preload() {
    //links of character images 
    var characterImages = [];
    mushroom = loadImage("https://i.imgur.com/V1vjvug.png"); //mushroom that is meant to represent # of lives
    cloud = loadImage("https://i.imgur.com/7PCTEzk.png"); //clouds that will be floating by in the background
    characterImages[0] = "https://i.imgur.com/Bf9U7OE.png"; //mario
    characterImages[1] = "https://i.imgur.com/s7o5h2m.png"; //peach
    characterImages[2] = "https://i.imgur.com/xQqZiZb.png"; //toad
    characterImages[3] = "https://i.imgur.com/0bcsmDZ.png"; //bowser
    characterImages[4] = "https://i.imgur.com/Wv9Dkzj.png"; //wario
    characterImages[5] = "https://i.imgur.com/AkWIiIw.png"; //boo

    //initial cloud positions
    for (var i = 0; i < 4; i++) {
        //setting the clouds to random initial positions
        cloudsX[i] = width + i * 50;
        cloudsY[i] = random(0, 130);
        cloudsSpeed[i] = random(0.25, 1); // moving the clouds at a randomized speed between 0.25 and 1
    };

    //load images of characters into characters array
    //allows for object to change characters
    characters[0] = loadImage(characterImages[0]);
    characters[1] = loadImage(characterImages[1]);
    characters[2] = loadImage(characterImages[2]);
    characters[3] = loadImage(characterImages[3]);
    characters[4] = loadImage(characterImages[4]);
    characters[5] = loadImage(characterImages[5]);

}

function setup() {
    createCanvas(600, 400);
    //random positions of character
    pipeNumber = round(random(0, 5)); //randomly chooses which pipe the character will appear at
    pipesOccupied = pipeNumber; //corresponding pipe number
    characterX = width / 7 * (pipeNumber + 1) + 60; //character's x position that will determine their corresponding pipe
    characterIndex = round(random(0, 5)); //randomly chooses which character will appear
}

function draw() {
    background(21, 30, 99); // setting background to the blue
    //creating the clouds; just loading the image onto the canvas; they do not move here yet
    for (var i = 0; i < 4; i++) {
        image(cloud, cloudsX[i], cloudsY[i]);
    };

    displayHill(); // creating the hill landscape moving in the background

    //part of the Title Screen
    //images of characters spread out across title screen
    if (gameMode === 0) {
        for (var x = 0; x < 6; x++) {
            image(characters[x], (width/7 * (x+1)) - (width / 7 / 2) + 10, 110);
        }
    }

    gameScreen(); // this is the actual game 
    displayChutes(); // creates the green chutes/pipes 
    displayGround(); // creates the criss-crossed red brick ground 
    titleScreen(); // this is the starting, default screen
    drawScoreTally(); // keeps track of the score in gameScreen and gameOverScreen
    instructionsScreen(); // instructions screen
    displayButtons(); // creates the buttons in the actual game part
    gameOverScreen(); // the game over screen after you lose all your lices

    //clouds are made to move here at randomized speeds
    for (var i = 0; i < cloudsX.length; i++) {
        cloudsX[i] -= cloudsSpeed[i];
        if (cloudsX[i] < -60) {
            cloudsX[i] = width;
        };
    };
}


function drawScoreTally() {
    if (gameMode === 1) { // we only want this visual element to appear in the gameScreen 
        push();
        //making the yellow rectangle where the score will be kept
        fill(181, 141, 38);
        strokeWeight(2);
        stroke(255, 229, 163);
        rectMode(CENTER);
        rect(width / 2, 35, 70, 20, 3);
        noStroke();
        //adding the actual text on top of the rectangle 
        fill(255,229, 163);
        textAlign(CENTER);
        text("Score:" + " " + score, width / 2, 40)
        //text saying that if user wishes to restart the game at any point, the user can just press the key 'x' to restart the game
        text("Press 'x' to restart game", width/2, 60);
        pop();
    };
}

//creating the generative hill landscape in the background of the game
function displayHill() {
    var hill = 0.006 
    var hillSec = 0.0007;
    push();
    stroke(25, 83, 19);
    beginShape();
    for (i = 0; i < width; i ++) {
        var h = (millis() * hillSec) + (i * hill);
        var y = map(noise(h), 0, 1, 200, 100);
        line(i, y, i, height);
    }
    endShape();
    pop();
}
// creating the brick ground 
function displayGround() {
    push();
    strokeWeight(2);
    stroke(211, 71, 71);
    fill(181, 38, 38);
    rectMode(CORNER);
    rect(0, 260, 600, 400-260);
    for (var k = 0; k < 60; k ++) {
        line(k * 10, 260, k * 10, 400);
        line(0, 260 + k * 10, 600, 260 + k * 10);
    }
    pop();
}
//creating the green chutes/pipes
function displayChutes() {
    if (gameMode === 0 || gameMode === 1 || gameMode === 3) { //we want the chutes/pipes to appear in all screens except the game over screen
        push();
        //creating 6 chutes/pipes
        for (var j = 1; j < 7; j++) {
            rectMode(CENTER); //drawing rectangles from the center rather than the corner
            fill(43, 130, 58);
            strokeWeight(3);
            stroke(81, 163, 95);
            rect((width/7) * j, 220, 65, 80, 2); //body of the chute
            rect((width/7) * j, 200, 75, 40, 2); //head of the chute
            strokeWeight(7);
            //giving the pipes the highlight on their left side
            line(55 + (width/7 * (j-1)), 186, 55 + (width/7 * (j-1)), 215);
            line(60 + (width/7 * (j-1)), 225, 60 + (width/7 * (j-1)), 255);

        }    
        pop();
    }
}

function titleScreen() {
    push();
    if (gameMode === 0 || gameMode === 3) { // we want the title screen to appear in title screen and instructions screen
        //creating title of the game: "Pipe it Up"
        stroke(155, 115, 0); 
        strokeWeight(8);
        fill(255, 203, 57);
        textAlign(CENTER);
        textSize(70);
        textFont('arial')
        text("PIPE IT UP", width / 2, (height / 3 * 2) + 60);
        push();
        //creating the two yellow buttons on bottom of screen
        fill(155, 115, 0);
        strokeWeight(2);
        stroke(255, 230, 57);
        rect(150, 350, 125, 35, 4); //left button
        rect(325, 350, 125, 35, 4); // right button
        textSize(15);
        //creating the text on top of buttons
        textFont('Arial');
        strokeWeight(1);
        stroke(255, 203, 57);
        fill(255, 203, 57);
        text("START GAME", 213, 373);
        text("INSTRUCTIONS", 388, 373);
        pop();
    }
    pop();

    //changes cursor to hand when hovering over start button and instructions button 
    if (mouseX > 150 & mouseX < 275 && mouseY < 385 && mouseY > 350) {
        cursor(HAND);
        if (mouseIsPressed) {
            gameMode = 1;
        };
    } else if (mouseX > 325 & mouseX < 450 && mouseY > 350 && mouseY < 385) {
        cursor(HAND);
        if (mouseIsPressed) {
            gameMode = 3;
        };
    } else {
        cursor(ARROW);
    }
}

function instructionsScreen() {
    if (gameMode === 3) {  //we only want the instructions screen to occur during instructions Screen time
        push();
        //creating an lowered opacity blanket of black across the title screen
        fill(0, 0, 0, 200); 
        rect(0,0,600,400); 
        //title of the instructions screen: "Instructions"
        textSize(30);
        strokeWeight(1);
        stroke(255, 188, 0);
        fill(255, 188, 0);
        textAlign(CENTER);
        text("INSTRUCTIONS", width/2, 80);
        //purpose of the game
        fill(255);
        strokeWeight(1);
        stroke(255);
        textSize(18);
        text("Keep the Mushroom Kingdom safe!", width/2, 125);
        //instructions of the game
        textSize(15);
        noStroke();
        textAlign(LEFT);
        text("There are 6 pipes leading into the kingdom, each one assigned to a button \n on your keyboard : S, D, F, J, K, L. \n \n It is your job as royal guard to delegate who enters and who does not. \n Unfortunately, some baddies will try to infiltrate the kingdom \n and make you lose your job. But luckily, with the tap of a button, \n you can immediately prevent them from entering. \n But be careful! Reject a civilian and you'll get a demerit. \n Three demerits is a disadulation.", 50, 160);
        textAlign(CENTER);
        strokeWeight(1);
        stroke(255);
        text("Press 'x' to return to Start page", width/2, 350);
        pop();
    }
}

function gameScreen() {
    if (gameMode === 1) {
    //----------------------------- get random character to pop up at different location -------

        //places character down
        image(characters[characterIndex], characterX, characterY);
        //if character reaches peak, move in opposite direction
        if (characterY < 100) {
            characterSpeed = characterSpeed * -1
        //if character reaches bottom of the pipe, changes character randomly and goes to new pipe
        } else if (characterY > 200) {
            characterSpeed = characterSpeed * -1
            characterIndex = round(random(0, 5))
            pipesOccupied = round(random(0, 5))
            characterX = width / 7 * (pipesOccupied) + 60
        };
        characterY += characterSpeed;

    //----------------------------- correct answer / wrong answer ------------------------------
        //draws lives as mushrooms
        for (var i = 0; i < lives; i++) {
            image(mushroom, 60 + (40 * i), 20)
        };
        //once lives reaches 0, game ends
        if (lives === 0) {
            gameMode = 2
        };
    }
}

function displayButtons() {
    //draws each of the buttons 
    var txt = ["S", "D", "F", "J", "K", "L"];
    if (gameMode === 1) {
        push();
        stroke(137, 144, 200);
        strokeWeight(5);
        //changing color of button if respective key is pressed
        //if 's' key is pressed
        if (keyIsPressed) {
            if (key === 's') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width/7), height - height/7, 40, 40);
        // if 'd' key is pressed
        if (keyIsPressed) {
            if (key === 'd') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 2, height - (height / 7), 40, 40);
        // if 'f' key is pressed
        if (keyIsPressed) {
            if (key === 'f') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 3, height - (height / 7), 40, 40);
        // if 'j' key is pressed
        if (keyIsPressed) {
            if (key === 'j') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 4, height - (height / 7), 40, 40);
        // if 'k' key is pressed
        if (keyIsPressed) {
            if (key === 'k') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 5, height - (height / 7), 40, 40);
        // if 'l' key is pressed
        if (keyIsPressed) {
            if (key === 'l') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 6, height - (height / 7), 40, 40);
        // adding the text on top of the button
        pop();
        for (var j = 1; j < 7; j++) {
            push();
            fill(200, 184, 220);
            noStroke();
            textAlign(CENTER);
            textSize(19);
            text(txt[j - 1], (width / 7) * j , height - (height / 7) + 5);
            pop();
        }
    }
}

function gameOverScreen() {
    //press 'r' to restart
    if (gameMode === 2) {
        //title of the gameOverScreen: "game over"
        push();
        fill(11, 16, 90, 200);
        rect(0, 0, 600, 400);
        textSize(50);
        fill(239, 0, 42);
        strokeWeight(5);
        stroke(145, 0, 26);
        textAlign(CENTER);
        text("GAME OVER", width/2, height/2 - 20);
        //displays your score
        textSize(30);
        strokeWeight(2);
        text("Score:" + " " + score, width/2, height/2 + 20);
        //tells you how you can play again and restart the game
        textSize(20);
        strokeWeight(1);
        fill(239, 0, 42);
        text("Press 'r' to restart game", width/2, height/2 + 70);
        pop();
    };
} 

function keyPressed() {
    //if game hasn't started yet, press S to start
    //if game started, press X to go to home screen
    //if game over, press r to restart 
    if (gameMode === 1) {
        if (key === 'x' || key === 'X') {
            gameMode = 0;
            level = 1;
            score = 0;
    // if character is bad guy, add point for pressing; else subtract life 
    //if character is good guy, subtract life for pressing and add point for not pressing
        } else {
            for (var i = 0; i < characters.length; i++) {
                var keys = ["s", "d", "f", "j", "k", "l"]
                if (pipesOccupied === i) {
                    //if good guy, 
                    if (characterIndex === 0 || characterIndex === 1 || characterIndex === 2) {
                        if (key === keys[i]) {
                            lives -= 1
                        }
                    } else if (characterIndex === 3 || characterIndex === 4 || characterIndex === 5 & key === keys[i]) {
                        score += 1
                    } else if (characterIndex === 3 || characterIndex === 4 || characterIndex === 5 && key != keys[i]) {
                        lives -= 1
                    }
                };
            };
        }
    //GAMEOVER - press R to restart the game 
    } else if (gameMode === 2) {
        if (key === 'r' || key === 'R') {
            gameMode = 0;
            level = 1;
            score = 0;
            lives = 3;
        };
    //INSTRUCTIONS - press X to go to title screen
    } else if (gameMode === 3) {
        if (key === 'x' || key === 'X') {
            gameMode = 0;
        };
    };

} 

Instructions:

Keep the Mushroom Kingdom safe! There are 6 pipes leading into the Mushroom Kingdom and each one is assigned to a respective button on your keyboard : S, D, F, J, K, L. It is your job as a royal guard of the kingdom to delegate who is able to enter and who is not. Unfortunately, some villains will try to infiltrate the kingdom and make you lose your job. Luckily, with the tap of a button, you can immediately prevent them from entering. But be careful! Reject a civilian and you’ll lose a demerit (life). “Three demerits is a disadulation” – Jim  Halpert from The Office. haha

Statements:

What we have produced for our final project is a completely different direction than what we had proposed to do in our Proposal. After lots of thought, we decided to change the topic of our final project because we believed this was something that could best reflect our creativity and have a more set goal (and also in celebration of Nintendo’s release of Super Smash Bros Ultimate today).

In regards to the distribution of work, Min and I worked in person together throughout the whole process. In the beginning, we would just sit next to each other, create a visual element, and then come together to merge whatever the two of us came up with. After the visual aspects were basically all done and we had to get to the interactive component of the game, that is when things started to get a little more difficult. We had to communicate a lot and constantly merge our codes to make sure that we are using the same variables, going towards the same direction, and following the same general train of thought. In the end, I focused more on the game design and structure while Min focused more on gameplay and functionality.

In the beginning, we had wanted characters to be coming out of all six chutes randomly, but at all times. But, we couldn’t figure out how to prevent characters from appearing in pipes that another character already occupies. So, we shifted our goals to stick to one pipe. We also could not figure out how to debug our code so that if no key is pressed to capture a “bad” character, a life is lost, or vice versa, if no key is pressed to let a “good character remain free, points are added to the score. However other than those two problems, the rest of the game came out quite successfully.

Sarah Yae – Final Project

sketch

// Sarah Yae
// smyae@andrew.cmu.edu
// Section B
// Final Project - "EDM and Jam!"

// Declare sound variables globally

// "Rumors" by R3HAB
var r1;
var r2;
var r3;
var r4;
var r5;
var r6;
// "Lullaby" by R3HAB
var l1;
var l2;
var l3;
var l4;
var l5;
var l6;
var l7;
var l8;
var l9;
var l10;
// Drum Sounds
var d1;
var d2;
var d3;
var d4;
// Random Sounds
var rn1;
var rn2;
var rn3;
var rn4;
var rn5;
var rn6;
//Other Variables 
var x1 = 170;
var x2 = 230;
var y1 = 170;
var y2 = 230;
var rad = 60; 
var startpx = 10; 
var startox = 10;
var startix = 10; 
var ldia = 100;
var kdia = 100;
var jdia = 100;
var xb1 = 200;
var yb1 = 200;
var xb2 = 200;
var yb2 = 200; 
var uparc_x;
var uparc_y;
var arc_w = 100;
var arc_h = 50; 

// Load all sounds
function preload() {
    r1 = loadSound("rumor1.wav");
    r1.setVolume(0.5);

    r2 = loadSound("rumor2.wav");
    r2.setVolume(0.5); 

    r3 = loadSound("etc1.wav");
    r3.setVolume(0.5); 

    r4 = loadSound("rumor4.wav");
    r4.setVolume(0.5); 

    r5 = loadSound("rumor5.wav");
    r5.setVolume(0.5); 

    r6 = loadSound("rumor6.wav");
    r6.setVolume(0.5); 

    l1 = loadSound("lullaby1.wav");
    l1.setVolume(0.5); 

    l2 = loadSound("lullaby2.wav");
    l2.setVolume(0.5);

    l3 = loadSound("lullaby3.wav");
    l3.setVolume(0.5);

    l4 = loadSound("lullaby4.wav");
    l4.setVolume(0.5);

    l5 = loadSound("lullaby5.wav");
    l5.setVolume(0.5);

    l6 = loadSound("lullaby6.wav");
    l6.setVolume(0.5);

    l7 = loadSound("lullaby7.wav");
    l7.setVolume(0.5);

    l8 = loadSound("lullaby8.wav");
    l8.setVolume(0.5);

    l9 = loadSound("lullaby9.wav");
    l9.setVolume(0.5);

    l10 = loadSound("lullaby10.wav");
    l10.setVolume(0.5);

    d1 = loadSound("drum1.wav");
    d1.setVolume(0.5);

    d2 = loadSound("drum2.mp3");
    d2.setVolume(0.5);

    d3 = loadSound("drum3.wav");
    d3.setVolume(0.5);

    d4 = loadSound("drum4.wav");
    d4.setVolume(0.5);

    rn1 = loadSound("rand1.wav");
    rn1.setVolume(0.5);

    rn2 = loadSound("rand2.wav");
    rn2.setVolume(0.5);

    rn3 = loadSound("rand3.wav");
    rn3.setVolume(0.5);

    rn4 = loadSound("etc2.wav");
    rn4.setVolume(0.5);

    rn5 = loadSound("rand5.wav");
    rn5.setVolume(5.0);

    rn6 = loadSound("rand6.wav");
    rn6.setVolume(0.5);
}

//Setup Canvas
function setup() {
    createCanvas (400,400);
}

//Draw graphics and play corresponding sounds
function draw() {

    background (51);

    textSize(25);
    textAlign(CENTER);
    fill("Salmon");
    text("EDM AND JAM! press any key", width / 2, 50);

    if (keyIsPressed) {

        var slant = 30;

// Play "Rumors" = Key B, N , M, L, K, J

        if (key == 'm') { //pink slash lines
            r1.play();
            for (var i = 0; i < 40; i++) {
                strokeWeight(10);
                stroke(246, 203, 190);
                line(0, height - slant, slant, height);
                slant += 40; 
            }
        }         

        if (key == 'n') { //purple slash lines
            r2. play();
            for (var i = 0; i < 40; i++) {
                strokeWeight(10);
                stroke(203, 202, 231);
                line(0, height - slant, slant, height);
                slant += 40; 
            } 
        }

        if (key == 'b') { //half circles move
            r3.play();
            background (200);
            fill ('Salmon');

            arc(xb1, yb1, 100, 100, PI/2, PI*3/2);
            yb1 -= 10;
            if (yb1 < 0) {
                yb1 = 200; 
            }

            arc(xb2, yb2, 100, 100, PI*3/2, PI/2);
            yb2 += 10; 
            if (yb2 > height) {
                yb2 = 200; 
            }
        }
    
        if (key == 'l') { //yellow circle gets bigger
            r4.play();
            fill(204,255,0);
            noStroke();
            ellipse(width/2, height/2, ldia, ldia);
            ldia = ldia + 10;

            if (ldia > 150) {
                ldia = 30;
            }
        }

        if (key == 'k') { //blue circle gets bigger
            r5.play();
            fill(0, 204, 255);
            noStroke();
            ellipse(width/2, height/2, ldia, ldia);
            ldia = ldia + 10;

            if (ldia > 150) {
                ldia = 30;
            }
        } 

        if (key == 'j') { //pink circle gets bigger
            r6.play();
            fill(255, 0, 204);
            noStroke();
            ellipse(width/2, height/2, ldia, ldia);
            ldia = ldia + 10;

            if (ldia > 150) {
                ldia = 30;
            }
        }   

// Play Random Sounds = Key A, S, D, F, G, H

        if (key == 'a') { //yellow one dash
            rn1.play();
            strokeWeight(10);
            stroke(254, 226, 62);
            line(width/2 - 70, height/2, width/2 + 70, height/2)
        }

        if (key == 's') { //yellow two dashes
            rn2.play();
            strokeWeight(10);
            stroke(254, 254, 73);
            line(width/2 - 70, height/2 - 20, width/2 + 70, height/2 - 20);
            line(width/2 - 70, height/2 + 20, width/2 + 70, height/2 + 20);
        }

        if (key == 'd') { //yellow three dashes
            rn3.play();
            strokeWeight(10);
            stroke(255, 255, 146);
            line(width/2 - 70, height/2 - 30, width/2 + 70, height/2 - 30);
            line(width/2 - 70, height/2, width/2 + 70, height/2);
            line(width/2 - 70, height/2 + 30, width/2 + 70, height/2 + 30);
        }

        if (key == 'f') { //gradient orange
            rn4.play();
            loadPixels();
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {
                    var ind = (x + y * width) * 4;
                    pixels[ind+0] = 200;
                    pixels[ind+1] = 100; 
                    pixels[ind+2] = y;
                    pixels[ind+3] = 255;
                }
            }
            updatePixels();
        }

        if (key == 'g') { //gradient pink
            rn5.play();
            loadPixels();
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {
                    var ind = (x + y * height) * 4;
                    pixels[ind+0] = 100;
                    pixels[ind+1] = 50; 
                    pixels[ind+2] = y;
                    pixels[ind+3] = 255;
                }
            }
            updatePixels();
        }

        if (key == 'h') { //gradient blue 
            rn6.play();
            loadPixels();
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {
                    var ind = (x + y * width) * 4;
                    pixels[ind+0] = 100;
                    pixels[ind+1] = 150; 
                    pixels[ind+2] = y;
                    pixels[ind+3] = 255;
                }
            }
            updatePixels();
        }

// Play "Lullaby" = Key P, O, I , U, Y, T, R, E, W, Q

        if (key == 'p') { //one top star moving
            l1.play();
            background(17, 30, 108); 
            textSize(50); 
            fill('Yellow');
            text('*', startpx, 100);
            startpx += 10; 

            if (startpx > width) {
                startpx = 10; 
            }
        }

        if (key == 'o') { //one middle star moving
            l2.play();
            background(17, 30, 108); 
            textSize(50); 
            fill('Yellow');
            text('*', startox, 200);
            startox += 10;  

            if (startox > width) {
                startox = 10; 
            }       
        }

        if (key == 'i') { //one bottom star moving
            l3.play();
            background(17, 30, 108); 
            textSize(50); 
            fill('Yellow');
            text('*', startix, 300);
            startix += 10;  

            if (startix > width) {
                startix = 10; 
            }  
        }

        if (key == 'u') { //green springs wallpaper
            l4.play();
            background(255, 235, 205);
            for (var uparc_y = 50; uparc_y < 500; uparc_y += 100) {
                for (var uparc_x = 50; uparc_x < 500; uparc_x += 100) {
                noFill ();
                stroke (177,194,122);
                strokeWeight (3);
                arc(uparc_x, uparc_y, arc_w, arc_h, PI, TWO_PI);
                }
            }
        }

        if (key == 'y') { //blue springs wallpaper
            l5.play();
            background(255, 235, 205);
            for (var uparc_y = 50; uparc_y < 500; uparc_y += 100) {
                for (var uparc_x = 50; uparc_x < 500; uparc_x += 100) {
                noFill ();
                stroke (180,216,231);
                strokeWeight (3);
                arc(uparc_x, uparc_y, arc_w, arc_h, PI, TWO_PI);
                }
            }
        }

        if (key == 't') { //pink springs wallpaper 
            l6.play();
            background(255, 235, 205);
            for (var uparc_y = 50; uparc_y < 500; uparc_y += 100) {
                for (var uparc_x = 50; uparc_x < 500; uparc_x += 100) {
                noFill ();
                stroke (255,195,194);
                strokeWeight (3);
                arc(uparc_x, uparc_y, arc_w, arc_h, PI, TWO_PI);
                }
            }
        }

        if (key == 'r') { //four triangles
            l7.play();
            noFill();
            for (var i = 0; i < 4; i++) {
                strokeWeight(12 - 3 * i)
                var rr = 244
                var rg = 147
                var rb = 242
                stroke(rr - (50 * i), rg + (20 * i), rb);
                triangle(width/2, (height/4) + 40 * i, (width/4) + 35 * i, (height*3/4) - 20 * i, (width * 3/4) - 35 * i, (height*3/4) - 20 * i);
            }
        }

        if (key == 'e') { //three triangles
            l8.play();
            noFill();
            for (var i = 0; i < 3; i++) {
                strokeWeight(12 - 3 * i)
                var er = 244
                var eg = 147
                var eb = 242
                stroke(er - (50 * i), eg + (20 * i), eb);
                triangle(width/2, (height/4) + 40 * i, (width/4) + 35 * i, (height*3/4) - 20 * i, (width * 3/4) - 35 * i, (height*3/4) - 20 * i);
            }
        } 

        if (key == 'w') { //two triangles
            l9.play();
            noFill();
            for (var i = 0; i < 2; i++) {
                strokeWeight(12 - 3 * i)
                var wr = 244
                var wg = 147
                var wb = 242
                stroke(wr - (50 * i), wg + (20 * i), wb);
                triangle(width/2, (height/4) + 40 * i, (width/4) + 35 * i, (height*3/4) - 20 * i, (width * 3/4) - 35 * i, (height*3/4) - 20 * i);
            }
        }
        
        if (key == 'q') { //one triangle
            l10.play();
            strokeWeight(12);
            noFill();
            for (var i = 0; i < 1; i++) {
                var qr = 244
                var qg = 147
                var qb = 242
                stroke(qr - (50 * i), qg + (20 * i), qb);
                scale(1/(1+i));
                triangle(width/2, height/4, width/4, height * 3/4, width * 3/4, height * 3/4);
            }
        }

// Play Drum Sounds = Key V, C, X, Z

        if (key == 'c') { //two balls move horizontally
            d1.play();

            noStroke();
            fill(255, 228, 196);
            ellipse(x1, height/2, rad, rad);
            x1 -= 5;

            fill(230, 230, 250);
            ellipse(x2, height/2, rad, rad);
            x2 += 5;

            if (x1 < 0) {
                x1 = 170;
            }

            if (x2 > width) {
                x2 = 230;
            }
        }

        if (key == 'v') { //two balls move vertically
            d2.play();

            noStroke();
            fill(255, 228, 196);
            ellipse(width/2, y1, rad, rad);
            y1 -= 5;

            fill(230, 230, 250);
            ellipse(width/2, y2, rad, rad);
            y2 += 5;

            if (y1 < 0) {
                y1 = 170;
            }

            if (y2 > height) {
                y2 = 230;
            }  
        }   

        if (key == 'x') { //white thunder
            d3.play();
            noFill();
            stroke('White');
            strokeWeight(10);
            beginShape();
            vertex(width/2, height/4 - 20);
            vertex(width/3 + 10, height/2);
            vertex(width*2/3 - 10, height/2);
            vertex(width/2, height*3/4 + 20);
            endShape();
        }

        if (key == 'z') { //yellow thunder
            d4.play();
            noFill();
            stroke('Yellow');
            strokeWeight(20);
            beginShape();
            vertex(width/2, height/4 - 20);
            vertex(width/3 + 10, height/2);
            vertex(width*2/3 - 10, height/2);
            vertex(width/2, height*3/4 + 20);
            endShape();
        }
    }
}

“EDM AND JAM!”

INSTRUCTIONS: Press any alphabetical key on the keyboard to play a particular sound and see a corresponding graphic. You can even listen to your favorite music and add beats to it, simply by pressing a key!

HOW TO OPERATE FROM ZIP FILE: Because this program incorporated a lot of sounds (approximately 26 different sound files), it was best to upload as a zip file. First, download the zip file. Secondly, run a terminal locating the file and localhost:8000. Third, open up the program and play around with it! Download it right here: smyae-finalproject

SCREENSHOTS:

Background of “EDM AND JAM!”
Key “u” pressed, a sound from “Lullaby” plays
Key “m” pressed, a sound from “Rumor” plays

REFLECTION STATEMENT: After getting inspired by “Patatap,” I wanted to create something similar to it. My project, “EDM AND JAM!” focuses on EDM sounds with animations or graphics that reminds me of a particular corresponding sound. Although the code was pretty straightforward, cutting out individual sound from music files was tedious and challenging. It was cool to see the final project though! I had a fun time playing around with it, and even putting a background music while I run the program.

SONGS USED: “Lullaby” by R3HAB, “Rumors” by R3HAB (and other random sounds)

Xiaoying Meng -Final Project

sketch

//Xiaoying Meng
//Section B
//xiaoyinm@andrew.cmu.edu
//final project

var soulmate;//song
var fft;
var w;//width for fft visual
var play = false;
var amp;
var vol = [];

//load song
function preload(){
    soulmate = loadSound('https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/01-SoulMate-feat.-IU-online-audio-converter.com_.mp3');
}
function setup() {
    createCanvas(256,256);
    fft = new p5.FFT(0,64);
    w = width/64;//divide amp visual width
    amp = new p5.Amplitude();
}

function draw(){
    background(255,196,8);
    noStroke();
    //fft visual 
    var spectrum = fft.analyze();
    for (var i=0; i < spectrum.length; i++){
        var amp2 = spectrum[i];
        var y = map(amp2,0,256,height,0);//map fft to canvas height
        //draw rectangles for visual
        fill(255,255,255,200);
        rect(i*w,y-6,w-1,height - y);//rectangles showing different frequencies
        ellipse(random(0,260),y,2,2);//randomly placed dots for filter effect
    }

//amp visual
    push();
    var singlevol = amp. getLevel(); //add single volume to array
    vol.push(singlevol);
    stroke(255);
    noFill();
    for (var i=0; i < vol.length; i++){
        var m = map(vol[i],0,1,height,0);// map volume to canvas 
    }
    pop();
    if(vol.length > width-50){
        vol.splice(0,1);
    }
//d circle degree
    for(var d=0;d<=360; d+=2){

        x1=200+m*cos(d);
        y1=150+m*sin(d);
        x2=200+(m+40)*cos(d+50);
        y2=150+(m+40)*sin(d+50);
        x3=200+(m+80)*cos(d+10);
        y3=150+(m+80)*sin(d+10);            
        x4=200+(m+120)*cos(d+50);
        y4=150+(m+120)*sin(d+50);

        
        strokeWeight(0.3);
        stroke(255);
        //line between 1st and 2nd cimcle
        line(x2,y2,x1,y1);
        //line between 3rd and 1st, 2nd circle
        line(x2,y2,x3,y3);
        line(x1,y1,x3,y3); 

        //line between 4th circle and 1st, 2nd, 3rd circle
        line(x3,y3,x4,y4);
        line(x2,y2,x4,y4);
        line(x1,y1,x4,y4);        
    }
    //distinguish larger amplitude sounds with ellipse
    if (singlevol>0.1){
        ellipse(200,150,120,120);
        noFill();
        stroke(255);
        strokeWeight(2);
        ellipse(200,150,130,130);
    }
        drawButton(); //drawing button
}

function drawButton(){
    //changing between rectangle and triangle
    noStroke();
    fill(255);
    if (play === true){
        rect(10,height-26,20,20);
    }else{
        triangle(10,height-26,30,height-16,10,height-6);
    }
}

function mousePressed(){
    //playing and pausing 
    if(mouseX>10 & mouseX <30 && mouseY > height-26 && mouseY < height-6 ){
        if(play){
            soulmate.pause();
        }else{
            soulmate.play();
        }
        play =! play;
    }
}

I wanted to create sound visualization since we did not do much of this. My final project tries to connect music to visual and express a mood and atmosphere. I always feel cheerful when I listen to this song, Soulmate by Zico. Therefore I used yellow for the visuals. The visuals are created by analyzing the song’s frequency and amplitude. Simply click the play button to enjoy the music.

Julie Choi – Final Project

My final project requires the use of a camera (webcam), so it does not properly run on WordPress. Here is the link to the zip file:

Julie_Choi_Final_Project.zip

Instructions: Start with a white background for this project. Preferably wear a dark shade shirt and place your portrait on the center on the screen. An easier way to interact with this short game is to wait for all the balls to drop from the top of the screen, but this does not matter hugely. Start clicking the red balls to make them disappear. Once the screen has no red balls, an orange screen will pop up and tell you “good job!”

Since the program does not run on this page, here are some screenshots of the step by step process of the game.

This is how it looks when all the bubbles have stacked on top of each other.
This is how it looks when you click on the red bubbles to get rid of them on the screen.
This screen will appear once all the red bubbles disappear from the screen.

final project

/*Julie Choi
15-104 Section E
jjchoi@andrew.cmu.edu
Final Project
*/

var px = 20;
var py =  100;
var myCaptureDevice;
var brightnessThreshold = 50;
var darknessThreshold = 45
var circleCenter = [];
var x = 5;
var radius = 20;
var randomBalls = 2;
var initGeneration = true;
var initRandom = true;
let timer = 30;


function setup() {
    createCanvas(640, 480);
    myCaptureDevice = createCapture(VIDEO);
    myCaptureDevice.size(640, 480); // attempt to size the camera. 
    myCaptureDevice.hide(); // this hides an unnecessary extra view.
    frameRate(60);
    // generateCircleCenter function is called in setup
    generateCircleCenter();   	
}

function generateCircleCenter(){
	// sets the circles on the top of the circle by pushing makeCircleFall into the circle center
    while(x <= width - radius){
        circleCenter.push(makeCircleFall(x, 20, radius, true, false));
        x += radius;
    }
    x = 5;
    generateRandom(randomBalls);
}

function generateRandom(n){
	// generates more lines of circles to fall after the previous line
    if (n == 0){
        return;
    }
    var j = int(random(0, circleCenter.length));
    if (circleCenter[j].random != true){
        circleCenter[j].random = true;
        generateRandom(n-1);
    } else {
        generateRandom(n);
    }
}

function draw() {
    background(220);
    myCaptureDevice.loadPixels(); 
    // draw the camera at 1:1 resolution
    image(myCaptureDevice, 0, 0);  
    fill(255);
    // call all the objects in draw function
    for(var c = 0; c < circleCenter.length; c++){
        if (circleCenter[c].exist){
            circleCenter[c].render();
            circleCenter[c].update();
            if(circleCenter[c].py >= height){
                circleCenter[c].reset();
            }
        }
    }
    // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
    if (frameCount % 60 == 0 & timer > 0) { 
        timer --;
    }
    if (timer % 2 == 1 & initGeneration){
        initGeneration = false;
        generateCircleCenter();
    }
    if (timer % 2 == 0 & initGeneration != true){
        initGeneration = true;
    }

    // instruction text on the bottom
    fill(0);
    noStroke();
    fill(255);
    textFont('futura');
    textSize(10);
    text("use a white background", width / 2, height - 25);
    text("tip: wait for all the balls to fall and have fun playing with the balls :)", width / 2, height - 10);
    textAlign(CENTER, CENTER);
    textSize(30);
    text( "Pop the red bubbles!", width / 2, height - 50);

    // detect only the py of the yellow point exsisting on the screen
    var result = circleCenter.filter(obj => {
    return obj.py > 0 & obj.random;
    });
    // if the result of the value above is 0 then the timer stops
    if (result.length == 0){
        timer == 0;
        fill(249, 173, 129);
        rect(0, 0, width, height);
        noFill();
        stroke(255);
        strokeWeight(1);
        text("GOOD JOB!", width/2, height /2);
    }
}

function makeCircleFall(inputX, inputY, radius, exist, random) {
    return {px: inputX, py: inputY, radius: radius, exist: exist, random: random,
            update: Update,
            reset: Reset,
            render: Render
           };
}

function isColor(c) {
    return (c instanceof Array);
}

function Update() {
    // fetch the color of the pixel at the (px,py) location of the circleCenter
    var theColorAtPxPy = myCaptureDevice.get(this.px, this.py);
    // compute its brightness
    if(isColor(theColorAtPxPy)){
        var theBrightnessOfTheColorAtPxPy = brightness(theColorAtPxPy);
    }
    // if the circleCenter is in a bright area, move downwards.
    // else, if it's in a dark area, move up until we're in a light area
    if(theBrightnessOfTheColorAtPxPy > brightnessThreshold){
        this.py += 1;
    } else if(theBrightnessOfTheColorAtPxPy < darknessThreshold & this.py > 0){
        this.py -=1;
        theColorAtPxPy = myCaptureDevice.get(px, py);
    }
    // take the objects in the circleCenter array and filter them into the name obj
    // obj.px to keep track of each px in the circleCenter array
    // this makes each circle stack on top of each other regarding the distance of the diameter of each circle
    var result = circleCenter.filter(obj => {
        return obj.px == this.px & obj.py > this.py
    });
    for (var i = 0; i < result.length; i++) {
        if ((result[i].py - radius) < this.py){
            this.py --;
        }
    }
}

function Reset() {
	// reset py to stop at the bottom of the screen
    this.py = height;
}

function Render() {
	// choose 3 circles randomly from each line to fill with red
    if(this.random){
        fill("red");
        stroke(255);
        strokeWeight(2);
        if (initRandom){
            initRandom = false;
        }
    }
    // draw circle at points of px and py in a line across the top of the screen
    if (this.exist) {
        ellipse(this.px, this.py, this.radius, this.radius);
        fill(random(0, 255), random(0, 255), random(0, 150), 80);
        stroke(255);
        strokeWeight(2);
        initRandom = true;
    }
}

function mousePressed() {
	// circles stay on the screen if exist is true
	// when mouse is pressed, exist and random becomes false to pop and make the circle that was clicked disappear
    for (var i = 0; i < circleCenter.length; i++) {
        var c = circleCenter[i];
        if (c.exist & dist(c.px, c.py, mouseX, mouseY) < c.radius / 2) {
            c.exist = false;
            c.random = false;
            return;
        }
    }
}

Reflection: This project utilizes the concept of raining letter assignment that we did a few weeks back. Using what we have learned plus some outside research more about p5.js, I was able to execute a satisfying result. I would say though that that using the different existing functions of p5.js and applying my mathematical calculation for the timer and the balls stacked on top of each other was the most challenging part. Overall, I learned a lot of new operators in the program and enjoyed the process of controlling both the display and the function.