Catherine Coyle – Final Project – Garden Game

Garden Game

// Catherine Coyle
// Final Project
// Section C
// ccoyle@andrew.cmu.edu

var flowers = [];

// number of the tool determines which tool the mouse is
var tool = 0;
var seedType = 0;
var SEEDTYPES = ['daisy', 'sunflower', 'tulip', 'violet'];
// 0 = seed pack
// 1 = watering can
// 2 = shovel

var filenames = [];
var images = [];
var menu = false;
var points = 0;
var flowerCount = 0;

// will be used for animation
var frames = 0;

// loading in all my image assets
function preload() {
	filenames[0] = 'https://i.imgur.com/WFbRW0R.png' // grown daisy
	filenames[1] = 'https://i.imgur.com/KfHyjYc.png' // grown sunflower
	filenames[2] = 'https://i.imgur.com/f5Naph6.png' // tulip grown
	filenames[3] = 'https://i.imgur.com/RjLTKmz.png' // violet grown
	filenames[4] = 'https://i.imgur.com/v4QTgQ2.png' // watering can
	filenames[5] = 'https://i.imgur.com/Rj3iuaG.png' // watering can pouring
	filenames[6] = 'https://i.imgur.com/1emAAfx.png' // daisy seed
	filenames[7] = 'https://i.imgur.com/Sjj5ezu.png' // sunflower seed
	filenames[8] = 'https://i.imgur.com/1HzYXus.png' // tulip seed
	filenames[9] = 'https://i.imgur.com/cKFWiib.png' // violet seed
	filenames[10] = 'https://i.imgur.com/z2DQqJT.png' // seeds plant
	filenames[11] = 'https://i.imgur.com/NBEkiuR.png' // daisy sapling
	filenames[12] = 'https://i.imgur.com/FVmfFxU.png' // sunflower sapling
	filenames[13] = 'https://i.imgur.com/9tXiQKK.png' // tulip sapling
	filenames[14] = 'https://i.imgur.com/irNCdQr.png' // violet sapling
	filenames[15] = 'https://i.imgur.com/pvEMQE2.png' // shovel up
	filenames[16] = 'https://i.imgur.com/WJ2MWlw.png' // shovel down

	for (var i = 0; i < filenames.length; i++) {
		images[i] = loadImage(filenames[i]);
	}
}

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

function draw() {
	background(173, 214, 156);

	// flowerCount is used to calculate points
	flowerCount = 0

	for (var i = 0; i < flowers.length; i++) {

		// flowers stop being watered after about 10 seconds
		if ((frames - flowers[i].startingF > 600) & (flowers[i].watered)){
			flowers[i].watered = false;
			flowers[i].startingF = frames;
		}

		// if they are not watered for 10 seconds, they wilt
		else if ((frames - flowers[i].startingF > 600) & 
				(flowers[i].watered == false)) {
			flowers[i].wilted = true;
		}

		// these if statements are just delegating how long it takes a flower to grow
		if ((flowers[i].status == 'seed') & 
			(frames - flowers[i].statusF - flowers[i].wiltedFrames > 700) &&
			 (flowers[i].wilted == false)) {
			flowers[i].status = 'sapling';
			flowers[i].statusF = frames;
		}
		else if ((flowers[i].status == 'sapling') & 
			(frames - flowers[i].statusF - flowers[i].wiltedFrames > 1200) && 
			(flowers[i].wilted == false)) {
			flowers[i].status = 'grown';
			flowers[i].statusF = frames;
		}

		// only non-wilted flowers are considered for points
		if (flowers[i].wilted == false) {
			flowerCount++;
		}
		flowers[i].draw();
	}

	// points increase every half-second
	if (frames % 30 == 0) {
		points += flowerCount;
	}

	// menu and points display
	fill(87, 77, 221);
	rect(0, 0, 200, 60);
	fill(255);
	textSize(30);
	text('POINTS: ' + str(points), 0, 30);
	textSize(10);
	text('Press m to display the menu', 0, 50);
	fill(0);
	noStroke();

	// different images are shown on the mouse based on the different tools
	if (tool == 0) {
		image(images[6 + seedType], mouseX, mouseY - 40);
	}
	else if (tool == 1) {
		if (mouseIsPressed){
			image(images[5], mouseX, mouseY - 40);
		}
		else {
			image(images[4], mouseX, mouseY - 40);
		}
	}
	else if (tool == 2) {
		if (mouseIsPressed){
			image(images[16], mouseX, mouseY - 40);
		}
		else {
			image(images[15], mouseX, mouseY - 40);
		}
	}

	// menu text
	if (menu) {
		fill(87, 77, 221);
		rect(20, 20, 440, 440);
		fill(255);
		textSize(12);
		text('-Grow a cute garden and gain points! \n \n \
			-Use the left and right arrows to cycle through tools \n \n \
			-The up and down arrows cycle through different types of flowers! \n \n \
			-Blue circles mean that your plant is currently watered \n \n \
			-Brown circles mean that it has wilted and you need to water it again! \n \n \
			-Points only increase for non-wilted flowers \n \n \
			-Press m again to go back to the game!', 30, 130);
	}

	// the continuous counter increases every time draw is called, time events are based on this
	frames++;
}

function keyPressed() {

	// right and left arrow commands switch between tools
	if (keyCode == RIGHT_ARROW) {
		tool++;
		tool = tool % 3;
	}
	else if ((keyCode == LEFT_ARROW) & (tool > 0)) {
		tool--;
		tool = Math.abs(tool);
		tool = tool % 3;
	}
	else if ((keyCode == LEFT_ARROW) & (tool == 0)) {
		tool = 2;
	}

	// up and down arrows switch between flower types
	// this only occurs if the user is currently using the seed tool
	if ((tool == 0) & (keyCode == UP_ARROW)) {
		seedType++;
		seedType = seedType % SEEDTYPES.length;
	}
	else if ((tool ==0) & (keyCode == DOWN_ARROW) && (seedType > 0)) {
		seedType--;
		seedType = seedType % SEEDTYPES.length;
	}
	else if ((tool ==0) & (keyCode == DOWN_ARROW) && (seedType == 0)) {
		seedType = 3;
	}
	if ((key == 'm') & (menu == false)) {
		menu = true;
	}

	//pressing m opens the menu
	else if ((key == 'm') & (menu)) {
		menu = false;
	}
}

function mousePressed() {

	// clicking with the seed tool will plant a seed
	if (tool == 0) {
		newFlower = makeFlower(SEEDTYPES[seedType], mouseX, mouseY, seedType);
		flowers.push(newFlower);
	}

	// clicking with the watering can waters the flower
	if (tool == 1) {
		for(var i = 0; i < flowers.length; i++) {
			if ((dist(mouseX, mouseY, flowers[i].x, flowers[i].y) < 20) & 
				(flowers[i].wilted)) {
				flowers[i].wilted = false;
				flowers[i].wiltedFrames = 0;
				flowers[i].startingF = frames;
			}
			else if ((dist(mouseX, mouseY, flowers[i].x, flowers[i].y) < 20)) {
				flowers[i].watered = true;
				flowers[i].startingF = frames;
			}
		}
	}

	// clicking with the shovel digs up and removes the flower
	if (tool == 2) {
		for (var i = 0; i < flowers.length; i++) {
			if (dist(mouseX, mouseY, flowers[i].x, flowers[i].y) < 20) {
				flowers.splice(i, 1);
			}
		}
	}
}

// flower class
function makeFlower(type, x, y, typeNum) {
	flower = {
		type: type,
		x: x,
		y: y,
		status: 'seed',
		wilted: false,
		draw: drawFlower,
		watered: false,
		imageNum: typeNum,
		startingF: frames,
		statusF: frames,
		wiltedFrames: 0,
	}
	return flower
}


function drawFlower() {
	fill(255);

	// blue circle indicates flower has been watered
	// circle size decreases as time watered runs out
	if (this.watered) {
		stroke('blue');
		strokeWeight(.25);
		noFill();
		ellipse(this.x - 20, this.y - 20, 10, 10);
		var waterTime = map(frames - this.startingF, 600, 0, 0, 10);
		fill('blue');
		noStroke();
		ellipse(this.x - 20, this.y - 20, waterTime, waterTime);
	}

	// brown circles indicate a wilted flower
	if (this.wilted) {
		fill('brown')
		ellipse(this.x - 20, this.y - 20, 10, 10);
		this.wiltedFrames++;
	}

	// below if statements delegate which image to be drawn
	if (this.status == 'seed') {
		image(images[10], this.x - 20, this.y - 20);
	}
	else if (this.status == 'sapling') {
		image(images[11 + this.imageNum], this.x - 20, this.y - 20);
	}
	else if (this.status == 'grown') {
		image(images[this.imageNum], this.x - 20, this.y - 20);
	}
}

I had so much fun with this!!!!!!

The instructions are all viewable in-game by going to the menu. It basically involves clicking and selecting tools with the arrow keys.

I really like idyllic and peaceful kind of games so I thought making a gardening game would be fun! I had originally wanted to have random interactions with animals but it turned out to be too much to do in the time frame (maybe I’ll do it on my own).

The graphics are not the best as I didn’t really realize how many I would have to draw going into the project but I think at the least they get the point across.

I was really happy with my time-based animations for this project as I feel like we didn’t do too much with those this semester. Additionally I took advantage of objects to make all my flowers.

I hope you like the game!

Romi Jin – Project-12-Final Project

sketch

/*
Romi Jin
Section B
rsjin@andrew.cmu.edu
Project-12
*/

var pic = {};
pic.bunny = "BUN.gif"; //bunny gif
pic.cloud = "cloud.png"; //cloud ground and movable
pic.carrot = "carrot.png"; //carrots to collect

var posX = 50; //start position
var posY = 50;
var speed = 4;
var jump_height = 15;
var jump = 38;
var left = 37;
var right = 39;
var moveinterval;
var gravityinterval;
var constant = 1;
var bound = 8;
var size = 5000;
var keysDown = [];
var stage;
var bunny;
var carrotnumber;
var above = 1;
var toleft = 3;
var onground = false;
var canjump = true;
var timer = 500;
var BOUNCE_FACTOR = 2;
var movingclouds = [];
var carrots = [];
var objects = [];
var start = 0;
var moveleft = 0;
var moveright = 1;
var movex = moveright;
var objectnumber;

function move(){
  //move bunny and define key pressed functions
  for (key in keysDown){
    switch (keysDown[key]){
      case right:
        posX += speed;
        if (stage.scrollLeft < size)
          stage.scrollLeft = bunny.offsetLeft-(stage.offsetWidth/2)+(bunny.offsetWidth/2);
        if (onground)
          bunny.src = pic.bunny;
        movex = moveright;
        break;
      case jump:
        if (onground & canjump){
          canjump = false;
          setTimeout(function(){canjump=true;},timer);
          constant = -jump_height;
          posY -= jump_height;
          onground = false;
          bunny.src = (movex==moveright) ? pic.bunny : pic.bunny;
        }
        break;
      case left:
        if (onground)
          bunny.src = pic.bunny;
        posX -= speed;
        stage.scrollLeft = bunny.offsetLeft-(stage.offsetWidth/2)+(bunny.offsetWidth/2);
        movex = moveleft;
        break;
      default:
    }
  }
  
  start++;
  //how clouds move up and down
  for (i in movingclouds){
    movingclouds[i].style.top = 150+50*Math.sin(start/50)+"px";
  }
  //when bunny stops in front of objects
   bunnystop();
  //render bunny
  render();
}

function collect(x){
  //collects carrots
  if (carrots.indexOf(x) > -1){
    remove(carrots,x);
    remove(objects, x);
    stage.removeChild(x);
    takeCarrot();
    return true;
  }
  return false;
}

function bunnyjump(a, b, c, d){
  if (c >= b) {
    d();
    return;
  }
  a.style.top = a.offsetTop - c + "px";
  setTimeout(function(){bunnyjump(a, b, c+1, d)}, 50);
}

function takeCarrot(){
  //adds to number of carrots in upper left corner -- keeps count / score
  carrotnumber.innerHTML = parseInt(carrotnumber.innerHTML)+1;  
}

function bunnystop(){
  //when bunny stops moving
  if (posX < stage.offsetLeft) posX = 5;
  if (posX+bunny.offsetWidth>size) posX = size - bunny.offsetWidth;
  
  onground = false;
  objectnumber = 0;
  
  for (c in objects){
      switch (bunnybounds(objects[c])){
        case above:
          if (collect(objects[c])) break;
          posY = objects[c].offsetTop-bunny.offsetHeight;
          onground = true;
          if ((objects[c])) break;
          speed = speed;
        case toleft:
          if (collect(objects[c])) break;
          posX = objects[c].offsetLeft-bunny.offsetWidth;
          if (!canjump)
            speed = 1;
          break;
      }
  }
}

function bunnybounds(x){
  //keep bunny outside objects
  if (posY+bunny.offsetHeight>x.offsetTop & 
    (posX + (bunny.offsetWidth/2)) > x.offsetLeft &&
    (posX + (bunny.offsetWidth/2)) < (x.offsetLeft+x.offsetWidth) &&
    posY < x.offsetTop &&
    posY+bunny.offsetHeight<(x.offsetTop+x.offsetHeight))
    return above;
  if (posX+bunny.offsetWidth>x.offsetLeft & 
    (posY + (bunny.offsetHeight/2)) < (x.offsetTop+x.offsetHeight) && 
    posX < x.offsetLeft && 
    (posY + (bunny.offsetHeight/2)) > x.offsetTop)
    return toleft;
  return 0;
}

function render(){
  //render bunny start position
  bunny.style.left = posX + "px";
  bunny.style.top = posY + "px";
}

function renderWorld(){
  //create all objects and defines elements of each
  stage = document.getElementById('stage');
  bunny = document.getElementById('bunny');
  carrotnumber = document.getElementById('carrotnumber');
  
  var clouds = [];
  for (var i = 0; i < 24; i++){
    clouds.push(cloudsurface(null, pic.cloud, i*40, stage.offsetHeight-35));
    objects.push(clouds[i]);
  }
  
  setTimeout(function(){
    var a = cloudsurface(clouds[9], pic.cloud);
    var b = cloudsurface(clouds[8], pic.cloud, -10, -100);
    objects.push(b);
    carrots.push(b);
    
    for (var i = 0; i<3; i++){
      var x = cloudsurface(clouds[6], pic.cloud, i*20, -40);
      objects.push(x);
      objects.push(x);

    }
    for (var i = 0; i<3; i++){
      var x = cloudsurface(clouds[4], pic.cloud, i*20, -40);
      objects.push(x);
      objects.push(x);
    }

    var c = cloudsurface(clouds[10], pic.cloud);
    var d = cloudsurface(clouds[20], pic.cloud);
    movingclouds.push(c);
    movingclouds.push(d);
    
    for (var i = 0; i<3; i++){
      var x = cloudsurface(clouds[7], pic.carrot, i*30, -10);
      objects.push(x);
      carrots.push(x);
    }
    for (var i = 0; i<4; i++){
      var x = cloudsurface(clouds[6], pic.carrot, i*30+5, -100-i*30);
      objects.push(x);
      carrots.push(x);
    }
    for (var i = 0; i<3; i++){
      var x = cloudsurface(clouds[10], pic.carrot, i*30, -230);
      objects.push(x);
      carrots.push(x);
    }
    
    for (var i = 1; i<4; i++){
      var x = cloudsurface(clouds[15], pic.cloud, i*20, -60);
      objects.push(x);
      objects.push(x);
      
      var x = cloudsurface(f, pic.carrot, 12, -i*30-140);
      objects.push(x);
      carrots.push(x);
    }
    
    for (var j = 0; j < 9; j++){
      for (var i = 0; i<11; i++){
        if (i <= j) continue;
        var x = cloudsurface(clouds[20], pic.cloud, i*20, -j*20);
        objects.push(x);
      }
    }
    
    var e = cloudsurface(clouds[10], pic.cloud);
    objects.push(e);
    var f = cloudsurface(clouds[20], pic.cloud);
    objects.push(a);
    objects.push(b);
    objects.push(c);
    objects.push(d);
    objects.push(f);

  },1000);
}

function cloudsurface(surface, pic, left, y){
  //cloud ground positioning
    var cloud = document.createElement("img");
    cloud.src = pic;
    stage.appendChild(cloud);
    cloud.style.position = "absolute";
    cloud.style.top = ((surface != null) ? (surface.offsetTop-cloud.offsetHeight + (y||0)) : y) + "px";
    cloud.style.left = ((surface != null) ? surface.offsetLeft + (left||0) : left) + "px";
    return cloud;
}

function gravity(){
  //bunny positioning in terms of gravity
  if (!onground)
    posY += constant;
  constant++;
  if (constant > bound) constant = bound;
}

function remove(x, y){
  //removes the carrots
  if (x.indexOf(y) > -1)
    x.splice(x.indexOf(y),1);
}

function onkeyDown(i){
  //defines key down pressed
  var down = window.event || i;
  var keypress = i.charCode || i.keyCode;
  if (down.preventDefault)
    down.preventDefault();
  else{
    down.returnValue = false;
  }
  if (keysDown.indexOf(keypress) > -1) return;
  keysDown.push(keypress);
  return false;
}

function onKeyUp(i){
  //allows bunny to move backwards
  var down = window.event || i;
  var keypress = i.charCode || i.keyCode;
  remove(keysDown, keypress);
}

function loadPics(load){
  //load all images and gifs
    for (i in pic){
      var img = new Image();
      img.src = pic[i];
      img.onload = (function(h,i){
          return function(){
            i = h;
          }
        })(img.src, pic[i]);

    }
    load();
}

$(document).ready(function(){
  loadPics(function(){
    renderWorld();
    stage.scrollLeft = 0;
  });
  setTimeout(function(){
    moveinterval = setInterval(function(){move();},15);
    gravityinterval = setInterval(function(){gravity();},30);
    $(this).keydown(onkeyDown);
    $(this).keyup(onKeyUp);
  },500);
});
    

For my final project, I initially tried to create like mario run, but it ended up being a lot more complicated than I had expected, so I made the game a lot more simpler than what I had imagined it would be. The bunny can move left and right to collect carrots while running and jumping on clouds (some move, some don’t), and the goal is to collect all of the carrots. I have a separate js file and text in the html file, so I am not sure how to upload them all and make the file show up on WordPress, so I have attached a screenshot of what the final product looks like on my screen:

Mimi Jiao and Sophia Kim – Final Project

Wait a few seconds… it’s loading! 🙂
Click to start! (Click mouse to see next visual)

sketch

//variables to load sound 
var sound1;
var sound2;
var sound3;
var sound4;
var sound5;
var sound6;
//variable to switch between shapes and songs
var toggle = 0;
//variable for drawing astroid (toggle 2 shape)
var power = 33;
var r = 255; 

function setup() {
    createCanvas(500, 500, WEBGL);
    amplitude = new p5.Amplitude();
    frameRate(40);
}

function preload() {
    sound1 = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/york.mp3");
    sound1.setVolume(1);

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

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

    sound4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/pizza.m4a");
    sound4.setVolume(1);

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

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

function draw() {
    background(0);
    noFill();
    stroke(255, 0 ,0);
    //retrieves amplitude of song playing 
    var level = amplitude.getLevel();
    //maps the amplitudes across values for use in shape later on
    var twist = map(level, 0, .6, 0, .3);
    var twist2 = twist * 15000;
    //adjusts the size of the astroids 
    var twistSize = map(level, 0, .3, 75, 300);

    //sophia's twists 
    var twisty1 = map(level, 0, 1, 0, .3);
    var twisty2 = twisty1 * 5;
    var twisty3 = twisty1 * 4;

    //MIMI JIAO'S CODE
    //first shape - Mimi's code
    if (toggle === 1) {
        rotateY(frameCount * twist / 100);
        rotateX(frameCount * twist / 100);
        rotateZ(frameCount * twist / 100);
        for (var i = 0; i < twist2; i++) {
            fill(i * sin(i), i * cos(i), 255);
            beginShape();
            vertex(i * cos(i), i, i - 1000);
            vertex(i * .01, i * 0.1, i * .01);
            vertex(i * sin(i), i * cos(i), i);
            endShape(CLOSE);
        }
    }

    //second shape (astroid) - Mimi's code 
    if (toggle === 2) {
        rotateX(twist);
        rotateY(twist);
        rotateZ(twist);
        //randomizes value so astroid will randomly be bright
        var randomBright;
        randomBright = random(255);
        //first astroid
        beginShape();
        noFill();
        for(var i = 0; i <  twist2; i++) {
            if (randomBright > 250) {
                stroke(255, 0, 0);
            } else {
            stroke(twist * 900 * sin(i), twist * 300, sin(i) * twist * 900);
            }
            vertex(twistSize * (cos(i) ** power), 
                   twistSize * (sin(i) ** power));
        }
        endShape();

        //second astroid 
        push();
        rotateZ(5);
        rotateX(3);
        rotateY(4);
        beginShape();
        noFill();
        for(var i = 0; i < twist2; i++) {
            stroke(twist * 300, twist * 900 * sin(i), sin(i) * twist * 900);
            vertex(twistSize * (cos(i) ** power), 
                 twistSize * (sin(i) ** power));
        }
        endShape();
        pop();

        //third astroid
        push();
        rotateZ(3);
        rotateX(4);
        rotateY(5);
        beginShape();
        noFill();
        for(var i = 0; i <  twist2; i++) {
            if (randomBright > 250) {
                stroke(255, 0, 0);
            } else {
            stroke(twist * 900 * sin(i), twist * 300, sin(i) * twist * 900);
            }
            vertex(twistSize * (cos(i) ** power), 
                   twistSize * (sin(i) ** power));
        }
        endShape();
        pop();

        //fourth astroid
        push();
        rotateZ(4);
        rotateX(3);
        rotateY(5);
        beginShape();
        noFill();
        for(var i = 0; i <  twist2; i++) {
            if (randomBright > 250) {
                stroke(255, 0, 0);
            } else {
            stroke(twist * 900 * sin(i), twist * 300, sin(i) * twist * 900);
            }
            vertex(twistSize * (cos(i) ** power), 
                   twistSize * (sin(i) ** power));
        }
        endShape();
        pop();

        //fifth astroid
        push();
        rotateZ(4);
        rotateX(3);
        rotateY(5);
        beginShape();
        noFill();
        for (var i = 0; i < 250 * TWO_PI; i++) {
            vertex(300 * (cos(i) ** power), 
                 300 * (sin(i) ** power));   
        }
        endShape();
        pop();
    }

    //third shape - Mimi's code 
    if (toggle === 3) {
        beginShape();
        noFill();

        //x and y coordinates
        var x;
        var y;
        var t = TWO_PI;
        var a = map(twist2, 0, width, 2, 10);
        var n = map(twist2, 0, height, QUARTER_PI, HALF_PI);
        var ma = map(a, 0, 200, 0, QUARTER_PI);

        //shape1
        push();
        beginShape();
        for(var i = 0; i < twist2; i++) {
            noStroke();
            fill(cos(twist2) * 100, cos(twist2) * 100, sin(twist2) * 100);
            x = a * sin(ma) * ((n - 1) * cos(t) + cos((n - 1) * t)) / n;
            y = a * sin(ma) * ((n - 1) * sin(t) - sin((n - 1) * t)) / n;
            vertex(-i * sin(i), i * cos(i), i);
            vertex(x, y);
            t += QUARTER_PI;
        }
        endShape();
        pop();

        //shape2
        push();
        beginShape();
        for(var i = 0; i < twist2; i++) {
            noStroke();
            fill(sin(twist2) * 100, cos(twist2) * 100, sin(twist2) * 100);
            x = a * sin(ma) * ((n - 1) * cos(t) + cos((n - 1) * t)) / n;
            rotateZ(-4);
            y = a * sin(ma) * ((n - 1) * sin(t) - sin((n - 1) * t)) / n;
            vertex(x, y);
            vertex(i * sin(i) , i * cos(i), i);
            t += HALF_PI;
        }
        endShape();
        pop();

        //accent shape3
        push();
        rotateX(frameCount * .003);
        rotateY(frameCount * .004);
        rotateZ(frameCount * .005);
        beginShape();
        for(var i = 0; i < twist2; i++) {
            noStroke();
            fill(sin(twist2) * 255, cos(twist2) * 255, sin(twist2) * 255);
            x = a * sin(ma) * ((n - 1) * cos(t) + cos((n - 1) * t)) / n;
            rotateZ(-4);
            y = a * sin(ma) * ((n - 1) * sin(t) - sin((n - 1) * t)) / n;
            vertex(x, y);
            vertex(i * sin(i) , i * cos(i), i);
            t += QUARTER_PI;
        }
        endShape();
        pop();
    }

    //SOPHIA KIM's code below
    // first "slide" for Sophia's Code - sphere 
    push();
    if (toggle === 4) {
        var radiusSphere1 = twisty2 * 200;
        fill(232, 0, 0);
        noStroke();
        rotateY(frameCount * twisty2 / 1000);
        rotateX(frameCount * twisty2 / 1000);        
        rotateZ(frameCount * twisty2 / 1000);
        sphere(radiusSphere1);

        var constrainR = constrain(mouseX, radiusSphere1, radiusSphere1);
        fill('yellow');
        noStroke();
        rotateY(frameCount * twisty2 / 500);
        rotateX(frameCount * twisty2 / 500);        
        rotateZ(frameCount * twisty2 / 500);
        sphere(constrainR);
    }
    pop(); 

    //first "slide" - lines behind the sphere
    push();
    if (toggle === 4) {
        for (var i = 0; i < twisty2 * 1000; i++) {
            stroke('red');
            beginShape();
            vertex(i * cos(i), i, i - 2000);
            vertex(i * .01, i * 0.09, i * .1);
            vertex(i * sin(i) , i * cos(i), i / 100);
            endShape(CLOSE);

            stroke('orange');
            beginShape();
            vertex(i * cos(i), i, i - 2000);
            vertex(i * .01, i * 0.05, i * .1);
            vertex(i * sin(i), i * cos(i), i / 500);
            endShape(CLOSE);
        }    
    }
    pop();

    //2nd "slide" for Sophia's code - lines 
    push();
    if (toggle === 5) {
        var Rfor2 = random(twisty2 * 140, 255);
        var Gfor2 = random(twisty2 * 140, 255);
        for (var i = 0; i < twisty2 * 3000; i++) {
            stroke(Rfor2, Gfor2, 230);
            strokeWeight(.4);
            beginShape();
            vertex(i * sin(i / 10), tan(sin(i / 20)) * 10); 
            vertex(i * sin(i / 20), sin(i / 100) * 20, cos(i / 50)); 
            vertex(tan(i / 10), cos(i / 100), cos(i * 100));
            vertex(sin(i / 20), tan(i / 50) * 40, sin(i * 5) / 20);
            endShape(CLOSE);
        }
    }
    pop();

    //3rd "slide" for Sophia's code - 
    //multiple circles moving around 
    push();
    if (toggle === 6) {
        for(var j = 0; j < 4; j++){
            var Rfor3 = random(twisty3 * 200, 255);
            stroke(Rfor3, 100, 240);
            for(var i = 0; i < twisty3 * 3000; i++){
                translate(sin(twisty3 * 0.4 + j) * 20, 
                          sin(twisty3 * 0.1 + j) * 20, i * 3);
                rotateX(frameCount * .3 / 5000 / twisty3);
                rotateY(frameCount * .2 / twisty3 / 100);
                rotateZ(frameCount * .5 / twisty3 / 300);
                push();
                sphere(14, 7, 5); 
                pop();
            }
        }
    }
    pop();
}

function mousePressed() {
    //reset to first shape/song after 6th song
    if (toggle < 6) {
        toggle ++;
    } else {
        toggle = 1;
    }

    //play songs based on mouse click sequence    
    if (toggle === 1) {
        sound1.play();
        sound6.stop();
    }

    if (toggle === 2) {
        sound2.play();
        sound1.stop();
    }

    if (toggle === 3) {
        sound3.play();
        sound2.stop();
    }

    if (toggle === 4) {
        sound4.play();
        sound3.stop();
    }

    if (toggle === 5) {
        sound5.play();
        sound4.stop();
    }

    if (toggle === 6) {
        sound6.play();
        sound5.stop();
    }
}

 

For the final project, we created various types of visuals that respond to different songs’ amplitude levels. We were interested in exploring how sound can be translated visually and wanted to challenge ourselves and try something new. So instead of using 2D, we decided to explore the basics of 3D with WEBGL.
We wanted to further explore sound and graphics as one, so we wanted to directly tie the image of the graphics to the amplitude of the music playing. We used shapes like spheres, and beginShape/endShape to create the visuals and played around with implementing trigonometric functions to create curves and other shapes. We wanted to create something that the viewer could flip through, so we made this click-through visual presentation. By clicking on the mouse, the user is able to see different visuals each with its own song.
Have fun and we hope you enjoy it 🙂






Sara Frankel – Final Project

sketch

// Sara Frankel
// Final Project
// sfrankel
// Section A

var liftYourself;
var shostyTen;
var liftArray;
var fft;
var greatestWave;
var isPlaying;
var greatestOverall = 0;
var isLiftYourself;

function preload() {
    shostyTen = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/shostakovich-symphony-no-10-mvt-2-gianandrea-noseda-london-symphony-orchestra.mp3");
    liftYourself = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/Lift-Yourself.mp3"); 
}

function setup(){
    var cnv = createCanvas(400, 400);
    cnv.mouseClicked(togglePlay); //plays the canvas when clicked
    fft = new p5.FFT();
    liftYourself.amp(0.2);
    shostyTen.amp(1);
    isPlaying = false;
    isLiftYourself = true;
}

function draw(){
    background(0);
    var spectrum = fft.analyze(); //uses FFT to use the "spectrum" of sound (i.e. the eyebrows)
    var waveform = fft.waveform(); //uses FFT to use the waveform of the sound (i.e. the squiggled hair)
    noStroke();
    
    //draw variable to keep track of the greatest wave to give the "pulse" effect
    greatestWave = 0;
    for (i = 0; i < waveform.length; i++) {
        if(waveform[i] > greatestWave) {
            greatestWave = waveform[i];
        }   
    }
    //takes greatest overal wave value and stores it as greatest wave
    if(greatestWave > greatestOverall){
        greatestOverall = greatestWave;
    }

  
    //uses map use the value of the greatest wave of the sound and put it on a scale for color
    fill(map(greatestWave, 0, greatestOverall, 255, 0), map(greatestWave, 0, greatestOverall, 0, 255), map(greatestWave, 0, greatestOverall, 0, 0));
    

    //draws the "hair" of the eyebrow when turned on
    //left eyebrow
    for (var i = 0; i < spectrum.length; i++){
        var x = map(i, 0, spectrum.length, 0, width / 3); //maps i on the length of the spectrum variable
        var h = -height + map(spectrum[i], 0, 255, height, 0); //maps position in the spectrum array to allow height
        rect(x + width * 0.75 - 50, height / 4 + 35, width / spectrum.length, h / 4);
    }
    //right eyebrow
    for (var i = 0; i < spectrum.length; i++){
        var x = map(i, 0, spectrum.length, width / 3, 0);
        var h = -height + map(spectrum[i], 0, 255, height, 0);
        rect(x + 15, height / 4 + 20, width / spectrum.length, h / 4);
    }

    //draws base of eyebrows
    stroke(255);
    line(width / 4, height / 4 + 20, width / 4 + 50, height / 4 + 20);
    line(width * 0.75 - 50, height / 4 + 35, width * 0.75, height / 4 + 35);

    noFill();
    //draw eyeballs
    var y = map(greatestWave, -1, 1, 0, height); //allows for the eyes and head to pulse
    ellipse(width / 4 + 20, height / 4 + 60, y / 3, y / 3);
    ellipse(width * 0.75 - 20, height * 0.25 + 60, y / 6, y / 6);
    //draws head
    ellipse(width / 2, height / 2, y * 1.5, y * 1.5); 

    //calls that if the audio is playing, the color of hair and eyes change to the music
    if(isPlaying) {
        fill(map(greatestWave, 0, greatestOverall, 0, 255), map(greatestWave, 0, greatestOverall, 255, 0), map(greatestWave, 0, greatestOverall, 255, 0));
        stroke(map(greatestWave, 0, greatestOverall, 0, 255), map(greatestWave, 0, greatestOverall, 255, 0), map(greatestWave, 0, greatestOverall, 255, 0));
    } else {
        noFill();
        stroke(255);
    }

    //uses drawHairAtAngle function to draw the hair on the head that follows the pulse of the head (stays in spot with music)
    drawHairAtAngle(-14 * PI / 18, y * 0.75, waveform);
    drawHairAtAngle(-12 * PI / 18, y * 0.75, waveform);
    drawHairAtAngle(-10 * PI / 18, y * 0.75, waveform);
    drawHairAtAngle(-8 * PI / 18, y * 0.75, waveform);
    drawHairAtAngle(-6 * PI / 18, y * 0.75, waveform);
    drawHairAtAngle(-4 * PI / 18, y * 0.75, waveform);

    //allows eyes to follow mouse, drawing eyeballs
    var eX = map(mouseX, 0, y, -1, 1); 
    var eY = map(mouseY, 0, y, -1, 1);
    ellipse(eX + width / 4 + 20, eY + height / 4 + 60, 40, 40);
    ellipse(eX / 2 + width * 0.75 - 20, eY / 2 + height * 0.25 + 60, 20, 20);

    //states that if playing, the color of the mouth and eyebrows change color
    if(isPlaying) {
        stroke(map(greatestWave, 0, greatestOverall, 255, 0), map(greatestWave, 0, greatestOverall, 0, 255), map(greatestWave, 0, greatestOverall, 0, 0));
    } else {
        stroke(255);
    }

    //draws mouth
    for (var i = 0; i < waveform.length; i++){
        var x = map(i, 0, waveform.length, width/4, width * 0.75);
        var y = map(waveform[i], -1, 1, 0, height);
        line(width / 2, y + 50, x, height / 2 + 50);
    }

    //displays instructions of the canvas and which song is playing
    stroke(255);
    noFill();
    text('Click to play or pause - Press space to change song', 60, 15);
    if(isLiftYourself) {
        text("Kanye West - Lift Yourself", width - 150, height - 10);
    } else {
        text('Dmitri Shostakovich - Symphony No. 10 Second Movement', width - 360, height - 10);
    }
}


// fade liftYourself if mouse is over canvas
function togglePlay() {
    //if statement that allows for each song to play and not overlap another and still alows for the click to play/stop to work
    if(isLiftYourself){
        if (liftYourself.isPlaying()) {
        liftYourself.pause();
        isPlaying = false;
        } else {
            shostyTen.pause();
            liftYourself.loop();
            isPlaying = true;
        }
    } else {
        if (shostyTen.isPlaying()) {
            shostyTen.pause();
            isPlaying = false;
        } else {
            liftYourself.pause();
            shostyTen.loop();
            isPlaying = true;
        }
    }
}

//object that helps to draw the hair along the head
function drawHairAtAngle(angle, rad, waveform) {
    beginShape();
    for (var i = 0; i < waveform.length; i++) {
        //uses map to place the hairs along the radius of the circle evenly spaced
        var hairY = map(i, 0, waveform.length, sin(angle) * rad + height / 2, sin(angle) * (rad) + height / 2 - 25);
        var hairX = map(waveform[i], -0.5, 0.5, cos(angle) * (rad - 25) + width / 2, cos(angle) * (rad + 25) + width / 2); 
        vertex(hairX, hairY);
    }
    endShape();
}

//function to switch songs if space bar is clicked
function keyTyped() {
    if(key === ' ') {
        isLiftYourself = !isLiftYourself;
        togglePlay();
    }
 }


For this project, I decided to visualize music. My first vision at this project was something more abstract, but as I was creating the project I felt it to be more fun to have a face. This face visualizes music in the sense that all aspects of it “dance” to the music. The eyebrows raise, the hair squiggles, and the mouth draws lines to give the effect of singing. What I wanted to prove in this project is that not only is Kanye West “boppable” to, but so can classical music. The image posted below is a screen shot taken from the Shostakovich.

The instructions for this project are:
To play click the canvas
To change the song click space
To dance along (with the eyes) move the mouse!

Hope you enjoy!

if code does not work correctly, here is the zip.file for it!
https://drive.google.com/file/d/1O-X48r1iUjrtR_PWghS4f_l9hLtnG8Vf/view?usp=sharing

Curran Zhang / Jonathon Liang – Final Project

PRESS ENTER
sketch

/* Name : Jonathon Liang / Curran Zhang
   AndrewID : Jliang2 / Curranz
   Section : Section A 
   Final Project
*/

var terrainSpeed1 = 0.0002;
var terrainDetail1 = 0.015;
var terrainSpeed2 = 0.0004;
var terrainDetail2 = 0.008;
var clouds = []; 
var star = [];
var frames = []; 
var HeadX = 260;
var HeadY = 325; 
var ReflectionY =385
var step= 6;
var machox = 480;
var machoy = 300;
var girlx = 480;
var girly = 340;
var nekx = 480;
var neky = 240;
var towelx = 480;
var towely = 200;
var birdiex = 480;
var birdiey = 300;

function setup() {
  createCanvas(480, 480);
  //Iniate Clouds
  for (var i = 0; i <5; i++) {
      var r = random(width);
      clouds[i] = makeClouds(r);
  }
  //Head Image Position 
    imageMode(CENTER);
    frameRate(15);
}
function preload(){
 //Cats
	cat1 = loadImage("https://i.imgur.com/7hCkrYr.png");
	cat2 = loadImage("https://i.imgur.com/TWXWeM0.png");
	cat3 = loadImage("https://i.imgur.com/kRxHYt0.png");
	cat4 = loadImage("https://i.imgur.com/kkpAzvD.png");
	cat5 = loadImage("https://i.imgur.com/Hf9rTYl.png");
	birdie = loadImage("https://i.imgur.com/RdcS35J.png");

 //Head
    var filenames = [];
    filenames[0] = "https://i.imgur.com/leN6UXu.png";
	filenames[1] = "https://i.imgur.com/dydccNf.png";
	filenames[2] = "https://i.imgur.com/dcoiGqR.png";
	filenames[3] = "https://i.imgur.com/wez5P2S.png";
	filenames[4] = "https://i.imgur.com/9etlno8.png";
	filenames[5] = "https://i.imgur.com/yrjv4XT.png";
	filenames[6] = "https://i.imgur.com/hW3gKH6.png";
	filenames[7] = "https://i.imgur.com/Jg0yJck.png";
	filenames[8] = "https://i.imgur.com/dU1rruI.png";
    for (var i = 0; i < filenames.length; i++) {
        frames.push(loadImage(filenames[i]));
    }  
}

function draw() {
  //Gradient Background
    var from = color(250,0,0);
    var to = color(270);
    gradient(0,width,from,to);
    rect(0,0,480,480);
	  makeMountain1();
	  makeMoon();
	  makeStar();
	  makeMountain1();
	  makeMountain2();
	  makeReflection();
	  updateClouds();
	  removeClouds();
	  addClouds();
	strokeWeight(.5);
	stroke(255);
	text("early head gets the bird", 10, 15);
	text("touch a cat, you'll be sad", 10, 30);
	text("fly too high, and you'll die", 10, 45);
	  makeHead();
	  makeCat();
}

function gradient(y,w,from,to){
  for (var i = y; i <= height; i++) {
    var inter = map(i,y,y+w,0,1);
    var col = lerpColor(from,to,inter);
    stroke(col);
    strokeWeight(2);
    line(y,i,y+w,i);
  }
}

function makeStar(){
    fill(270);
    for (var i = 0; i < 100; i++) {
      var starX = random(width);
      var starY = random(height);
      ellipse(starX,starY,1,1);
    }
}

function makeMountain1(){
  noStroke();
  fill(180,0,0); 
  beginShape(); 
  for (var x = 0; x < width; x++) {
    var t = (x * terrainDetail1) + (millis() * terrainSpeed1);
    var y = map(noise(t), 0,1.8, height/8, height);
    vertex(x, y); 
  }
  vertex(width,height);
  vertex(0,height);
  endShape();
}

function makeMountain2(){
  fill(139,0,0); 
    noStroke();
    beginShape(); 
      for (var x = 0; x < width; x++) {
            var t = (x * terrainDetail2) + (millis() * terrainSpeed2);
            var y = map(noise(t), 0,2, height/2, height);
            vertex(x, y); 
      }
      vertex(width,height);
      vertex(0,height);
    endShape();
}

function makeReflection(){
  fill(220,50,50);
    rect(0, 375, width, 105);

  fill(255,60,60); 
    noStroke();
    beginShape(); 
      for (var x = 0; x < width; x++) {
            var t = (x * terrainDetail2) + (millis() * terrainSpeed2);
            var y = map(noise(t), 0,2, height, height*.5);
            vertex(x, y); 
      }
      vertex(width,height);
      vertex(0,height);
    endShape();
}

function makeMoon(){
    noStroke();
    fill(255,20);
    ellipse(2*width/3,height/4,170,170);
    ellipse(2*width/3,height/4,160,160);
    ellipse(2*width/3,height/4,150,150);
    ellipse(2*width/3,height/4,140,140);
    fill(255,200);
    ellipse(2*width/3,height/4,120,120);
}
function updateClouds(){
  for (var i = 0; i < clouds.length; i++) {
    clouds[i].move();
    clouds[i].display();
  }
}

function removeClouds(){
  var keepClouds = [];
  for (var i = 0; i < clouds.length; i++) {
      if (clouds[i].x + clouds[i].breadth > 0) {
        keepClouds.push(clouds[i]);
      }
  }
  clouds= keepClouds;
}

function addClouds(){
  var newCloud = .007;
  if (random(0,1)<newCloud) {
     clouds.push(makeClouds(width))
  }
}

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

function displayClouds(){
  fill(255,50);
  noStroke();
  ellipse(this.x,this.y,this.width,this.height);
  ellipse(this.x +10,this.y +10,this.width-10,this.height-10);
  ellipse(this.x +20,this.y -10,this.width/2,this.height/2);
  ellipse(this.x -20,this.y ,this.width-20,this.height-10);
}

function makeClouds(cloudy){
  var cloud= {x: cloudy,
              y:random(100, height/2),
              speed: random(-.2,-.7),
              width: random(50,100), 
              height:random(20,0),
              breadth:50,
              move:cloudMove,
              display:displayClouds
            }
  return cloud;          
}

function makeHead(){
  //Main Head
    push();
      translate(HeadX,HeadY);
      scale(.2,.2);
      image(frames[frameCount % 8], 0, 0);
    pop();    
  //Reflection
    push();
      translate(HeadX,ReflectionY);
      scale(.2,-.2);
      tint(255,127);
      image(frames[frameCount % 8], 0, 0);
    pop(); 
	if (keyIsDown(ENTER)){
	        HeadY -= step; 
	        ReflectionY += step;
	} else { HeadY += step;
	         HeadY = min(HeadY, 350);
	         ReflectionY -= step;
	         ReflectionY = max(ReflectionY,405);
	        }
	if (HeadY <= 100) {gameOver()};
}

function makeCat(){
	//MachoCat
		push();
			translate(machox,machoy);
			scale(.2,.2);
			image(cat1, 0,0);
			machox-=1.25;
			if (machox < 0) {lmachox = 480};
		pop();
		if (HeadX + 30 > machox & HeadX-30 < machox && machoy > HeadY  && HeadY > machoy - 30) {
			gameOver()};
	//MachoCat Reflection
		push();
			translate(machox,419);
			scale(.2,-.2);
			tint(265,160);
			image(cat1, 0,0);
			machox-=1.25;
			if (machox < 0) {machox = 480};
		pop();
	//School Girl
		push();
			translate(girlx,girly);
			scale(.18,.18);
			image(cat3, 0,0);
			girlx-=.8;
			if (girlx < 0) {girlx = 480};
		pop();
		if (HeadX + 30 > girlx & HeadX-30 < girlx && girly > HeadY  && HeadY > girly - 30) {
			gameOver();}
	//School Girl Reflection
		push();
			translate(girlx,409);
			scale(.18,-.18);
			tint(265,160);
			image(cat3, 0,0);
			girlx-=.8;
			if (girlx < 0) {girlx = 480};
		pop();
	//Neka
		push();
			translate(nekx,neky);
			scale(.6,.6);
			image(cat4, 0,0);
			nekx-=.5;
			if (nekx < 0) {nekx= 480};
		pop();
			if (HeadX + 30 > nekx & HeadX-30 < nekx && neky + 40 > HeadY  && HeadY > neky - 10) {
				gameOver()};
	//Neka Reflection
		push();
			translate(nekx,509);
			scale(.6,-.6);
			tint(265,160);
			image(cat4, 0,0);
			nekx-=.5;
			if (nekx < 0) {nekx = 480};
		pop();
	//Towel
		push();
			translate(towelx,towely);
			scale(.15,.15);
			image(cat5, 0,0);
			towelx-=5.05;
			if (towelx < 0) {towelx = 480};
		pop();
			if (HeadX + 30 > towelx & HeadX-30 < towelx && towely > HeadY  && HeadY > towely - 30) {
				gameOver()};
	//Birdie 
		push();
			translate(birdiex,birdiey);
			scale(-.15,.15);
			image(birdie, 0,0);
			birdiex-=5.05;
			if (birdiex < 0) {birdiex = 480};
			if (birdiey+30 > HeadY & HeadY> birdiey-30 && HeadX+30 > birdiex && HeadX-30 < birdiex)  {
				birdiex=480};
		pop();
}

function gameOver() {
	fill(0);
	textSize(75);
	textAlign(CENTER);
	textStyle(BOLD);
	text("GAME OVER", 240, 240);
	noLoop();
}

For the final project, me and Jonathon decided to base our project off of the game Battle Cat. Our original idea was to do a health system for the floating head and have the cats slowly chip off the health. However, that was not doable within our available time. Therefore, we toned down and the goal of the game is to bypass the white cats and try to collect the red bird as much as possible. Flying to high into the sky would also be an instant game over. Over the course of this project, we tried to incorporate as much as we can into it. Ranging from images, array, moving terrain, and objects.

Jonathan Liang – Curran Zhang – Final Project

sketch

/* Name : Jonathon Liang / Curran Zhang
   AndrewID : Jliang2 / Curranz
   Section : Section A 
   Final Project
*/

var terrainSpeed1 = 0.0002;
var terrainDetail1 = 0.015;
var terrainSpeed2 = 0.0004;
var terrainDetail2 = 0.008;
var clouds = []; 
var star = [];
var frames = []; 
var HeadX = 260;
var HeadY = 325; 
var ReflectionY =385
var step= 6;
var machox = 480;
var machoy = 300;
var girlx = 480;
var girly = 340;
var nekx = 480;
var neky = 240;
var towelx = 480;
var towely = 200;
var birdiex = 480;
var birdiey = 300;

function setup() {
  createCanvas(480, 480);
  //Iniate Clouds
  for (var i = 0; i <5; i++) {
      var r = random(width);
      clouds[i] = makeClouds(r);
  }
  //Head Image Position 
    imageMode(CENTER);
    frameRate(15);
}
function preload(){
 //Cats
	cat1 = loadImage("https://i.imgur.com/7hCkrYr.png");
	cat2 = loadImage("https://i.imgur.com/TWXWeM0.png");
	cat3 = loadImage("https://i.imgur.com/kRxHYt0.png");
	cat4 = loadImage("https://i.imgur.com/kkpAzvD.png");
	cat5 = loadImage("https://i.imgur.com/Hf9rTYl.png");
	birdie = loadImage("https://i.imgur.com/RdcS35J.png");

 //Head
    var filenames = [];
    filenames[0] = "https://i.imgur.com/leN6UXu.png";
	filenames[1] = "https://i.imgur.com/dydccNf.png";
	filenames[2] = "https://i.imgur.com/dcoiGqR.png";
	filenames[3] = "https://i.imgur.com/wez5P2S.png";
	filenames[4] = "https://i.imgur.com/9etlno8.png";
	filenames[5] = "https://i.imgur.com/yrjv4XT.png";
	filenames[6] = "https://i.imgur.com/hW3gKH6.png";
	filenames[7] = "https://i.imgur.com/Jg0yJck.png";
	filenames[8] = "https://i.imgur.com/dU1rruI.png";
    for (var i = 0; i < filenames.length; i++) {
        frames.push(loadImage(filenames[i]));
    }  
}

function draw() {
  //Gradient Background
    var from = color(250,0,0);
    var to = color(270);
    gradient(0,width,from,to);
    rect(0,0,480,480);
	  makeMountain1();
	  makeMoon();
	  makeStar();
	  makeMountain1();
	  makeMountain2();
	  makeReflection();
	  updateClouds();
	  removeClouds();
	  addClouds();
	strokeWeight(.5);
	stroke(255);
	text("early head gets the bird", 10, 15);
	text("touch a cat, you'll be sad", 10, 30);
	text("fly too high, and you'll die", 10, 45);
	  makeHead();
	  makeCat();
}

function gradient(y,w,from,to){
  for (var i = y; i <= height; i++) {
    var inter = map(i,y,y+w,0,1);
    var col = lerpColor(from,to,inter);
    stroke(col);
    strokeWeight(2);
    line(y,i,y+w,i);
  }
}

function makeStar(){
    fill(270);
    for (var i = 0; i < 100; i++) {
      var starX = random(width);
      var starY = random(height);
      ellipse(starX,starY,1,1);
    }
}

function makeMountain1(){
  noStroke();
  fill(180,0,0); 
  beginShape(); 
  for (var x = 0; x < width; x++) {
    var t = (x * terrainDetail1) + (millis() * terrainSpeed1);
    var y = map(noise(t), 0,1.8, height/8, height);
    vertex(x, y); 
  }
  vertex(width,height);
  vertex(0,height);
  endShape();
}

function makeMountain2(){
  fill(139,0,0); 
    noStroke();
    beginShape(); 
      for (var x = 0; x < width; x++) {
            var t = (x * terrainDetail2) + (millis() * terrainSpeed2);
            var y = map(noise(t), 0,2, height/2, height);
            vertex(x, y); 
      }
      vertex(width,height);
      vertex(0,height);
    endShape();
}

function makeReflection(){
  fill(220,50,50);
    rect(0, 375, width, 105);

  fill(255,60,60); 
    noStroke();
    beginShape(); 
      for (var x = 0; x < width; x++) {
            var t = (x * terrainDetail2) + (millis() * terrainSpeed2);
            var y = map(noise(t), 0,2, height, height*.5);
            vertex(x, y); 
      }
      vertex(width,height);
      vertex(0,height);
    endShape();
}

function makeMoon(){
    noStroke();
    fill(255,20);
    ellipse(2*width/3,height/4,170,170);
    ellipse(2*width/3,height/4,160,160);
    ellipse(2*width/3,height/4,150,150);
    ellipse(2*width/3,height/4,140,140);
    fill(255,200);
    ellipse(2*width/3,height/4,120,120);
}
function updateClouds(){
  for (var i = 0; i < clouds.length; i++) {
    clouds[i].move();
    clouds[i].display();
  }
}

function removeClouds(){
  var keepClouds = [];
  for (var i = 0; i < clouds.length; i++) {
      if (clouds[i].x + clouds[i].breadth > 0) {
        keepClouds.push(clouds[i]);
      }
  }
  clouds= keepClouds;
}

function addClouds(){
  var newCloud = .007;
  if (random(0,1)<newCloud) {
     clouds.push(makeClouds(width))
  }
}

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

function displayClouds(){
  fill(255,50);
  noStroke();
  ellipse(this.x,this.y,this.width,this.height);
  ellipse(this.x +10,this.y +10,this.width-10,this.height-10);
  ellipse(this.x +20,this.y -10,this.width/2,this.height/2);
  ellipse(this.x -20,this.y ,this.width-20,this.height-10);
}

function makeClouds(cloudy){
  var cloud= {x: cloudy,
              y:random(100, height/2),
              speed: random(-.2,-.7),
              width: random(50,100), 
              height:random(20,0),
              breadth:50,
              move:cloudMove,
              display:displayClouds
            }
  return cloud;          
}

function makeHead(){
  //Main Head
    push();
      translate(HeadX,HeadY);
      scale(.2,.2);
      image(frames[frameCount % 8], 0, 0);
    pop();    
  //Reflection
    push();
      translate(HeadX,ReflectionY);
      scale(.2,-.2);
      tint(255,127);
      image(frames[frameCount % 8], 0, 0);
    pop(); 
	if (keyIsDown(ENTER)){
	        HeadY -= step; 
	        ReflectionY += step;
	} else { HeadY += step;
	         HeadY = min(HeadY, 350);
	         ReflectionY -= step;
	         ReflectionY = max(ReflectionY,405);
	        }
	if (HeadY <= 100) {gameOver()};
}

function makeCat(){
	//MachoCat
		push();
			translate(machox,machoy);
			scale(.2,.2);
			image(cat1, 0,0);
			machox-=1.25;
			if (machox < 0) {lmachox = 480};
		pop();
		if (HeadX + 30 > machox & HeadX-30 < machox && machoy > HeadY  && HeadY > machoy - 30) {
			gameOver()};
	//MachoCat Reflection
		push();
			translate(machox,419);
			scale(.2,-.2);
			tint(265,160);
			image(cat1, 0,0);
			machox-=1.25;
			if (machox < 0) {machox = 480};
		pop();
	//School Girl
		push();
			translate(girlx,girly);
			scale(.18,.18);
			image(cat3, 0,0);
			girlx-=.8;
			if (girlx < 0) {girlx = 480};
		pop();
		if (HeadX + 30 > girlx & HeadX-30 < girlx && girly > HeadY  && HeadY > girly - 30) {
			gameOver();}
	//School Girl Reflection
		push();
			translate(girlx,409);
			scale(.18,-.18);
			tint(265,160);
			image(cat3, 0,0);
			girlx-=.8;
			if (girlx < 0) {girlx = 480};
		pop();
	//Neka
		push();
			translate(nekx,neky);
			scale(.6,.6);
			image(cat4, 0,0);
			nekx-=.5;
			if (nekx < 0) {nekx= 480};
		pop();
			if (HeadX + 30 > nekx & HeadX-30 < nekx && neky + 40 > HeadY  && HeadY > neky - 10) {
				gameOver()};
	//Neka Reflection
		push();
			translate(nekx,509);
			scale(.6,-.6);
			tint(265,160);
			image(cat4, 0,0);
			nekx-=.5;
			if (nekx < 0) {nekx = 480};
		pop();
	//Towel
		push();
			translate(towelx,towely);
			scale(.15,.15);
			image(cat5, 0,0);
			towelx-=5.05;
			if (towelx < 0) {towelx = 480};
		pop();
			if (HeadX + 30 > towelx & HeadX-30 < towelx && towely > HeadY  && HeadY > towely - 30) {
				gameOver()};
	//Birdie 
		push();
			translate(birdiex,birdiey);
			scale(-.15,.15);
			image(birdie, 0,0);
			birdiex-=5.05;
			if (birdiex < 0) {birdiex = 480};
			if (birdiey+30 > HeadY & HeadY> birdiey-30 && HeadX+30 > birdiex && HeadX-30 < birdiex)  {
				birdiex=480};
		pop();
}

function gameOver() {
	fill(0);
	textSize(75);
	textAlign(CENTER);
	textStyle(BOLD);
	text("GAME OVER", 240, 240);
	noLoop();
}

It all starts with an idea, but you can never tell where an idea can end up. Because ideas spread, they change, they grow, they connect us with the world. And in a fast-moving world, where good news moves at the speed of time and bad news isn’t always what is seems. Because when push comes to shove, we all deserve a second chance, to score.

For our Final Project Curran and I wanted to create a game that closely resembled our favorite mobile app game Battle Cats. But in our game we made it so that our protagonist cannot touch any of the white cats and has to try to eat the red chicken. The instructions are as followed: eat the chicken, avoid the white cats, and don’t fly too high; otherwise the game is over. Press enter to make the face move up.

Hope y’all enjoy.

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.