Jenny Hu — Final Project

For my final project, I created a simple step sequencer with 4 sounds and background music! You can add sounds at different points by toggling the squares and circles (the squares indicate a note switched off, and a circle indicates a note switched on), and change the speed the music player loops through the sequencer on the bpm toggle.

I really enjoyed making this because it became about the curation of the sounds and music,  letting anyone generate a soothing atmosphere.

Jenny’s sketch

//Jenny Hu
//Section E
//jjh1@andrew.cmu.edu
//Final Project

//This final project is a simple step sequencer.
//Sounds are loaded into each row,
//as the music player passes each note (switched on), it plays the sound
//squares indicate switched off notes, and circles indicate the ones switched on.

var playing = false;
var notesArray = []; //all notes are pushed into this array

//sizing variables
var totalC = 15; 
var canvasWidth = window.innerWidth; //sizing of everything should overall be parametric to this width.
var margin = 0.02 * canvasWidth; //space between notes and everything else
var noteW = (canvasWidth - (totalC + 1) * margin)/ totalC; //calculated width of each square/circle
var canvasHeight = 5 * margin + 4 * noteW + (noteW*4); 

//variables key to moving and playing components
var playButtonW = margin ; //big play/pause button
var baseLineX = margin; 
var baseLineY = (canvasHeight / 5) * 3.5;
var movingPlayBar = 20; 
var movingPlayBarW = 10; 
var playX; //moving x tracked against the array's x's. 

//variables to make bpm changeable
var bpmEdit = 2;
var bpm;
var bpmX;
var bpmToggleX;
var bpmToggleLength;

var backgroundMusicToggle = false;
var interval;
var volume = 1;

function preload() {
    // load sound files 
    bird = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/182507__swiftoid__bird-chirp.wav");
    bird.setVolume(volume);
    bell = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/173000__keykrusher__bicycle-bell-2.wav");
    bell.setVolume(volume / 3 * 2);
    cello = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/398494__anthousai__wind-chimes-single-01.wav");
    cello.setVolume(volume);
    shaker = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/368607__samsterbirdies__shake.wav");
    shaker.setVolume(volume);
    backgroundMusic = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/203099__lemoncreme__groove-music.wav");
    backgroundMusic.setVolume(volume);
}

function setup(){
	createCanvas(canvasWidth, canvasHeight);
	frameRate(1000);
	angleMode(DEGREES);

    bpmToggleLength = width / 8 * 5; 
	bpmX = bpmToggleLength + margin;
	//setting up rows with different sounds
    for (var c = 0; c < totalC; c++){
    	for (var r = 0; r < 4; r++){
    		var x = c * (noteW + margin) + margin;
    		var y = r * (noteW + margin) + margin; 
    		if ( r == 0){
    			snd = bird;
    		} else if (r == 1){
    			snd = bell;
    		} else if (r == 2){
    			snd = cello; 
    		} else {
    			snd = shaker;
    		}
    		var n = Note(x , y, snd, noteW);
            notesArray.push(n);
    	}
    }
}



function draw(){
	background(250, 230, 10);
	var wiggleRoom = 2;

	//intro text
	stroke(0, 0, 250);
	strokeWeight(1);
	fill(0, 0, 250);
	textSize(margin);
	textFont('Courier');
	text('press play to begin!', width / 2 - bpmToggleLength / 1.75, canvasHeight / 8 * 7); 

	//static line
	strokeWeight(5);
	line( baseLineX, baseLineY, canvasWidth - baseLineX, baseLineY);//playbar baseline

	//for loop rendering the array into notes
    for (var i = 0; i < notesArray.length; i++){
    	notesArray[i].render();

    	//play music when the play x and array of on notes collide
    	if (playX >= notesArray[i].x - wiggleRoom 
    		& playX <= notesArray[i].x + wiggleRoom 
    		&& notesArray[i].on == true){
    		notesArray[i].snd.play();
    	}
    }

	bpmToggle();
	playBackground();
	playButton();
    movePlayStream();
}

//function to move the bpm visual ui
function bpmToggle(){
	//shadow
	noStroke();
	fill(250, 250, 250, 150);
	rect( bpmToggleLength + margin, baseLineY + (margin * 2.5), width/5, noteW/5, 80); 
	//bpm text
	stroke(0, 0, 250, 250);
	fill(0, 0, 250);
	strokeWeight(1);
	text('bpm', bpmToggleLength + margin, canvasHeight / 8 * 7 + margin);
	//toggle
	fill(0, 0, 250);
	ellipse(bpmX, baseLineY + (margin * 2) + noteW / 3, noteW / 3, noteW / 3); 
}


//function to play background music
function playBackground(){
	if (backgroundMusicToggle == true){ //counter will be 1, or 2 (on rare occasion), immediate at play
		interval = 1250;
		if (counter  > 0 & counter < 3){
			backgroundMusic.play();
			playing = true;
		} else if ( counter % interval > 0 & counter % interval <= 2){ //interval is based on the timing of the background song
			playing = false;
			counter = 0; //reset counter if you've paused the music
		}
	 } 
}

//play/pause functionality + visuals
//playing is toggled in mousePressed
function playButton(){
	fill(0, 0, 250);

	if (playing == true) { 
		//pause button
		rect(width/2 - playButtonW, baseLineY + (margin * 2) , 
			playButtonW, playButtonW * 3);
		rect(width/2 + playButtonW, baseLineY + (margin * 2), 
			playButtonW, playButtonW * 3);
		//mapping of the bpm toggle to the speed of  playX
		bpmEdit = map(bpmX, 
				bpmToggleLength + noteW / 2, bpmToggleLength - noteW / 2 + width/5, 
				2, 4);
		bpm = bpmEdit; // the set BPM by the user
		backgroundMusicToggle = ! backgroundMusicToggle; //turning on the background music
		counter += 1;

	} else {
		//play button
		triangle ( width/2 - playButtonW, baseLineY + (margin * 2),
				  width/2 - playButtonW, baseLineY + (margin * 2) + noteW * .75 * 2,
				  width/2 - playButtonW + noteW * .75 * 2, baseLineY + (margin * 2) + noteW * .75 )
		bpm = 0; //stop the player if we've paused the switch
		counter = 0;
		backgroundMusic.stop();

	}
}

//draws the animated line
function movePlayStream(){
	playX = baseLineX + movingPlayBar - 20;
	stroke(0, 0, 250);
	fill(250);
	strokeWeight(4);
	//loops the line if the play button moves off the line
	if (playX > canvasWidth - baseLineX) {	
		movingPlayBar = baseLineX;
	} else {
		//the visual parts
		rect(playX, margin / 2, movingPlayBarW, canvasHeight / 5 * 3.5);
		ellipse( playX + movingPlayBarW / 2 , baseLineY, movingPlayBarW*2, movingPlayBarW*2);
	}
	//add whatever the bpm has been toggled to be
    movingPlayBar += bpm;
}



function mousePressed(){
	//turning on and off the individual notes by checking your mouse position
    for (var i = 0; i < notesArray.length; i++){
		if (mouseX > notesArray[i].x 
			& mouseX < notesArray[i].x + noteW 
			&& mouseY > notesArray[i].y
			&& mouseY < notesArray[i].y + noteW){
			var currentToggle = !notesArray[i].on;
			notesArray[i].on = currentToggle;
		}    	
    }
    //switch play/pause mode by clicking on the play/pause button
    if (mouseX > width / 2 - playButtonW 
    	& mouseX < width / 2 + margin + playButtonW 
    	&& mouseY > baseLineY + (margin * 2)
    	&& mouseY < baseLineY + (margin * 2) + playButtonW * 3){
    	playing = ! playing;
    }
}


function mouseDragged(){
	//dragging the bpm toggle
	if (mouseX > bpmToggleLength + margin
    	& mouseX < bpmToggleLength + width/5 + margin
    	&& mouseY > baseLineY + (margin * 2.5)
    	&& mouseY < baseLineY + (margin * 2.5) + noteW){
		bpmX = mouseX;
    }
}


//make the note real
function render(){
	fill(250);
	stroke(0, 0, 250);
	strokeWeight(5);
	//rendering cirlces if the note is on
	if (this.on){
		fill(250, 130, 180);
		noStroke();
		ellipse(this.x + noteW/2, this.y + noteW/2, this.w, this.w);
	} else { 
		//rendering squares if the notes is off
		rect(this.x, this.y, noteW, noteW); 
	}

	if(this.snd.isPlaying() & playX < this.x + noteW*1.5 && playX > this.x){
		var t = frameCount;
		this.w = noteW * sin(t*5);
	}else{
		this.w = noteW;
	}
}

//my note object maker function
function Note(x, y, snd, wide){
	var objNote = { //object literal format
		x : x,
		y : y,
		w: wide,
		snd : snd,
		on : false,
		playing: false
	}
	objNote.render = render;
	return objNote;
}


Vicky Zhou – Final Project

sketch

/*Vicky Zhou
vzhou@andrew.cmu.edu
Project 12 - Final
Section E*/

var particles; //number of particles in sphere system
var spacing; //spacing of particles
var waveRipple; //manipulates ripple in sphere system
var points; //array for compiling all sphere points
var speed; // speed variable for ripple sphere wave effect
var amplitude; //amplitude of wave

//variables for new toruses
var myx = [];
var myy = [];
var myz = [];

//variables for existing, old toruses
var total = 5;
var locations = new Array(total);
var bool = new Array(total);
var oldpart = [];
var oldpartsize = 12;

//to change displays
var changescene = true;


function setup() {
    createCanvas(600, 600, WEBGL);
    particles = 2000; 
    spacing = 200;
    points = [];
    speed = 0.01;
    amplitude = 0.8;
    wavecol = 0;
    
    if (changescene) {
    	//array of random points for wave of spheres
    	for (var i = 0; i < particles; i++) {
    		points[i] = createVector(random(-5, 5),
    								 random(-5, 5),
    								 random(-5, 5));
    	}
    } else {
    	//array for generated toruses
    	for (var i = 0; i < myx.length; i++) {
    		myx[i];
    		myy[i];
    		myz[i];
    	}

    	//array for already existing toruses
    	for (var i = 0; i < locations.length; i++) {
    		locations[i] = new Array(total);
    		bool[i] = new Array(total);
    		for (var j = 0; j < locations[i].length; j++) {
    			locations[i][j] = new Array(total);
    			bool[i][j] = new Array(total);
    			for (var k = 0; k < locations[i][j].length; k++) {
    				locations[i][j][k] = createVector(i * oldpartsize,
    												j * oldpartsize,
    												k * oldpartsize);
    				bool[i][j][k] = false;
    			}
    		}
    	}

    	var thres = 2; //threshold for state of Torus 
    	for (var i = 0; i < total; i++) {
    		for (var j = 0; j < total; j++) {
    			for (var k = 0; k < total; k++) {
    				stateofTorus = random(15); //random number for state 
    				if (stateofTorus <= thres) {
    					st = 1;
    					bool[i][j][k] = true;
    				} else {
    					st = 0;
    				}
    				oldpart.push(new myTorus(i * oldpartsize,
    										j * oldpartsize,
    										k * oldpartsize,
    										st));
    			}
    		}
    	}
    }
}


//create and push new coordinates for toruses when any key is pressed
function keyPressed() {
	myx.push(random(-10, 10));
	myy.push(random(-300, 300));
	myz.push(random(-300, 300));
}


function draw() {
	background(30, 30, 50);
	wavecol += 1;
	//light that is emiited
	directionalLight(wavecol/2, 200, 200, 50);
	ambientLight(80, wavecol/5, 170);
	//manipulates wave of spheres
	waveRipple = mouseX * speed;

	//center rotating cube
	push();
	rotateX(frameCount/100);
	rotateY(frameCount/100);
	noStroke();
	box(150);
	pop();

	if (changescene) {
		//array of random points to plot each sphere
		for (var i = 0; i < particles; i++) {
			var dot = points[i];
			doty = sin(dot.x + waveRipple) * amplitude;
			push();
			translate(dot.x * spacing, doty * spacing, dot.z * spacing);
			noStroke();
			sphere(10);
			pop();
		}
	} else {
		//array of existing toruses
		push();
		for (var i = 0; i < oldpart.length; i++) {
			oldpart[i].display();
		}
		pop();

		//create new toruses
		for (var i = 0; i < myx.length; i++) {
			rotateY(frameCount/500);
			push();
			if (keyIsPressed === true) {
				updatez = myz[i];
			} else {
				updatez = 100;
			}
			thenewy = cos(waveRipple) * amplitude + myy[i];
			thenewz = 0;
			directionalLight(wavecol/2, 200, 200, 50);
			translate(myx[i], thenewy, thenewz + updatez);
			var gradred = map(mouseX, 0, width, 0, 255);
			var gradgreen = map(mouseX, 0, width, 0, 200);
			fill(gradred, gradgreen, 200);
			strokeWeight(0.2);
			stroke("blue");
			torus(12, 5);
			pop();
		}
	}
}

//function to create existing toruses
function myTorus(x, y, z, st) {
	this.x = x;
	this.y = y;
	this.z = z;
	this.st = st;

	this.display = function() {
		if (this.st == 1) {
			rotateY(frameCount/350);
			push();
			directionalLight(wavecol/2, 200, 200, 250);
			translate(this.x, this.y, this.z * 3.5);
			strokeWeight(0.2);
			stroke("blue");
			torus(oldpartsize, 5);
			pop();
		}
	}
}

//click mouse to toggle between scenes
function mousePressed() {
	changescene =! (changescene);
	setup();
}

Instructions

Mouse Click: toggle between screens

Mouse move: manipulate wave; manipulate color of toruses

Press any key: add a new torus

Hold down any key: explode toruses

Statement

“Re:current” is a project utilizing 3D graphics from WEBGL in order to manipulate arrays and variables to create interactive cyclical experiences — 1. a “current” like nature of manipulating a wave of spheres using curves to mimic ocean-like wave that changes color over time and 2. a looping interaction of adding toruses which rotate around a 3. perennially rotating cube. My greatest struggle was working and adapting to the 3D landscape and nuances of WEBGL, and being able to translate the 2D elements we learned thus far onto my canvas. For my beginning prototypes, the biggest challenge I faced with creating an interactive project was being able to manipulate factors utilizing the mouse press and mouse pressed feature, because of how a mouse inherently creates an output of 2D, whereas my project would call for 3D. I resolved this issue to the best of my ability in this short term by opting to toggle between screens and making basic interactions using the mouse, and then for more detailed engagement I utilized the key pressed feature to generate random x, y, and z coordinates. For further exploration, I would love to explore with more dynamic ways of altering the canvas, ideally in ways to can imitate biomimicry, seeing that WEBGL is able to produce interestingly rendered outcomes with its different textures, lighting, and other attributes.

Screenshots
Some screenshots of my work!

wave manipulation (color change over time)
wave manipulation
initial torus scene
adding more toruses!

Christine Chen-Final Project

Christine Chen-Final-Project

/*
Christine Chen
Section E
cyc1@andrew.cmu.edu
Final Project
*/

var heartArray = [];
var heartCount = 0;

var carrotArray = [];
var carrotCount = 0;

var bombArray = [];

//location where the things that are collected disappear
var collect = 340;
    
//-------------------------------------

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

//-------------------------------------

function draw() {    
    background(255, 178, 220); //light pink background
    backgroundHeart();
    bunny();
    renderHeart();
    renderCarrot();
    renderBomb();
    pointDisplay();
    gameOver();
}

//-------------------------------------

//***** HEART *****
function makeHeart(x, y) {
    return {
        x: x,
        y: y,
        draw: drawHeart,
    }
} 

function drawHeart() { //draw shape of heart 
    strokeWeight(0.3);
    noStroke();

    //color of heart changes to give glittering effect
    fill(255 - random(0, width), 116, 208); 
    ellipse(this.x - 5, this.y, 11, 11);
    ellipse(this.x + 5, this.y, 11, 11);
    triangle(this.x - 10.5, this.y + 2, 
        this.x + 10.5, this.y + 2, 
        this.x, this.y + 13);
}

function renderHeart() {
    //creates new heart every 30 frames
    if (frameCount % 30 == 0) {
        var newHeart = makeHeart(random(10, width - 10), 0);
        heartArray.push(newHeart);
    }

    //updates heart's y location(make them fall)
    for (var i = 0; i < heartArray.length; i ++) {
        var heart = heartArray[i];
        heart.y += 1.5;

        //remove hearts that are gone (off of canvas)
        //saves space to prevent codes from running slow
        if(heart.y > height) {
            heartArray.splice(i, 1);
        }

        //remove hearts that are collected
        if(dist(mouseX, collect, heart.x, heart.y) < 20) {
            heartArray.splice(i, 1);
            heartCount++; //keeps track of heart points
        }

        heart.draw();
    }
}

//***** CARROT *****
function makeCarrot(x, y) {
    return {
        x: x,
        y: y,
        draw: drawCarrot
    }
} 

//draws shapes of carrot
function drawCarrot() {
    //carrot stem
    fill(17, 147, 8); //green
    ellipse(this.x, this.y - 5, 5, 15);
    ellipse(this.x - 3, this.y - 5, 5, 15);
    ellipse(this.x - 7, this.y - 5, 5, 15);
    ellipse(this.x + 3, this.y - 5, 5, 15);
    ellipse(this.x + 7, this.y - 5, 5, 15);

    //carrot body 
    fill(255, 117, 25); //orange
    triangle(this.x - 10, this.y, 
        this.x + 10, this.y, 
        this.x, this.y + 30);
}

function renderCarrot() {
    //creates new carrot every 600 frames
    if (frameCount % 600 == 0) {
        var newCarrot = makeCarrot(random(10, width - 10), 0);
        carrotArray.push(newCarrot);
    }

    //updates carrot location
    for (var i = 0; i < carrotArray.length; i ++) {
        var carrot = carrotArray[i];
        carrot.y += 5; //carrot falls quite fast

        //removes carrots that are gone(off of canvas)
        if(carrot.y > height) {
            carrotArray.splice(i, 1);
        }

        //removes carrots that are eaten
        if(dist(mouseX, collect, carrot.x, carrot.y) < 20) {
            carrotArray.splice(i, 1);
            carrotCount++; //keeps track of number of carrots collected
        }

        carrot.draw();
    }
}

//***** BOMB *****
function makeBomb(x, y) {
    return {
        x: x,
        y: y,
        draw: drawBomb,
    }
} 

//draws shape of bomb
function drawBomb() {
    //spark
    fill(255, 0, 0); //red
    ellipse(this.x + 20, this.y - 23, 10, 10);

    //bomb line
    stroke(0); //black 
    strokeWeight(2);
    line(this.x, this.y, this.x + 18, this.y - 20);

    //bomb body
    noStroke();
    fill(48, 47, 47); //dark gray
    ellipse(this.x, this.y, 30, 30);
}


function renderBomb() {
    //creates bomb every 100 frames
    if (frameCount % 100 == 0) {
        var newBomb = makeBomb(random(10, width - 10), 0);
        bombArray.push(newBomb);
    }

    //updates bomb location
    for (var i = 0; i < bombArray.length; i ++) {
        var bomb = bombArray[i];
        bomb.y += 6;

        //removes bomb that is gone (off of canvas)
        if(bomb.y > height) {
            bombArray.splice(i, 1);
        }

        //removes bomb that is collected
        if(dist(mouseX, collect, bomb.x, bomb.y) < 30) {
            bombArray.splice(i, 1);
            //heart point deducted by 10 points if bomb collected
            heartCount -= 10; 
            //carrot point deducted by 1 if bomb collected 
            carrotCount -= 1;
        }

        bomb.draw();
    }
}

//***** BUNNY *****
function bunny() {
    //constrain bunny location to inside canvas
    var control = constrain (mouseX, 15, width - 15);

    noStroke();
    fill(255); //white

    //body
    fill(255); //white
    ellipse(control, 370, 55, 50);

    //feet
    ellipse(control - 15, height - 5, 20, 10); //left 
    ellipse(control + 15, height - 5, 20, 10); //right 

    //hands
    ellipse(control - 27, height - 45, 20, 10); //left 
    ellipse(control + 27, height - 45, 20, 10); //right 

    //ears
    ellipse(control - 8, 300, 10, 30); //left 
    ellipse(control + 8, 300, 10, 30); //right 

    //face
    ellipse(control, 330, 70, 50);

    //eyes
    fill(0);
    ellipse(control - 5, 325, 5, 5); //left 
    ellipse(control + 5, 325, 5, 5); //right 

    //mouth
    fill(255, 122, 169); //pink
    ellipse(control, 338, 12, 10);

    //nose
    fill(0);
    ellipse(control, 331, 5, 4);

    //blush
    fill(252, 204, 204); //light red
    ellipse(control - 10, 331, 10, 7); //left
    ellipse(control + 10, 331, 10, 7); //red
}

//***** GAMEOVER *****
function gameOver() {
    //if carrot point is less than 0,
    //or if heart point is or less than -100,
    //game ends
    if (carrotCount < 0 || heartCount <= -100) {
        noLoop();
    
    //gameover sign background
    fill(167, 0, 47); //red
    rectMode(CENTER);
    rect(width/2 - 10, height/2 - 10, 260, 70);

    //gameover sign text
    fill(255);
    textSize(22);
    textAlign(CENTER);
    text("   G A M E O V E R", width/2 , height/2);

    //skull
    fill(255); //white
    ellipse(width/2 - 100 , height/2 - 10, 30, 22);
    rect(width/2 - 100 , height/2, 16, 10);

    //skull eyes
    fill(50);//gray
    ellipse(width/2 - 105 , height/2 - 10, 7, 7);
    ellipse(width/2 - 95 , height/2 - 10, 7, 7);
    }
}

//***** POINT DISPLAY *****
function pointDisplay() {
    stroke(0); //black
    strokeWeight(0.2); //light outline
    fill(250, 214, 226); //pink
    rect(10, 10, 180, 60);

    //heart
    noStroke();
    fill(108, 136, 255);
    ellipse(35, 35, 11, 11);
    ellipse(45, 35, 11, 11);
    triangle(29.5, 37, 
        50.5 , 37, 
        40, 48);

    //heart count text
    fill(30);
    textSize(20);
    text("= " + heartCount, 55, 45);

    //carrot
    fill(17, 147, 8); //green
    ellipse(120, 25 , 5, 15);
    ellipse(117, 25, 5, 15);
    ellipse(113, 25, 5, 15);
    ellipse(123, 25, 5, 15);
    ellipse(127, 25, 5, 15);

    fill(255, 117, 25); //orange
    triangle(110, 30, 
        130, 30, 
        120, 60);
    
    //carrot count text
    fill(30);
    textSize(20);
    text("= " + carrotCount, 140, 45);
}

//***** BACKGROUND HEART *****
function backgroundHeart() {
    noStroke();
    fill(253, 158, 209); //pink
    ellipse(180, 140, 260, 270);
    ellipse(420, 140, 260, 270);
    triangle(73, 220, 
        width - 73 , 220, 
        width/2, height - 5);
    ellipse(width/2, 220, 80, 80);
}

Heart
Carrot
Bomb

 

 

 

How to play:
– Move bunny left and right with mouse to control bunny’s position
– All things have to touch bunny’s mouth to be effective
– Collect hearts to gain points
– Collect carrots to store as lives
– Carrots save the bunny when bomb hits the bunny
– Bomb takes away bunny’s lives and deduct 10 heart points
– Bunny dies when heart point is -100 or when bomb hits bunny and there is no carrot to save bunny

Statement:
For my project, I decided to create a game that involves a bunny and heart rain. I wanted to create a simple, cute game that people can play with. Hearts are points and the carrots are lives. The bomb is what kills the bunny. The player should aim to gain as many heart points as possible. The stored carrots save the bunny from dying in the case that the bomb hits the bunny. I made the bomb fall fast on purpose so that it will be harder to escape the bomb, adding some excitement to the game. I also made the carrots, which rarely appears (to make the carrots more precious), fall fast. 10 heart points are deducted if the bunny hits the bomb. This is so that the player can’t keep using carrots to save the bunny while not collecting hearts. I made the background simple for this game as because of the “glittering effect” of the heart and the movement of the things falling, having more complicated background will confuse the player’s eyes too much. Initially, I made the hearts simply pink, but then I thought that was too boring and so I changed my codes so that they change colors randomly to create a glittering effect. The things have to touch the bunny’s mouth to be effective as my idea is that the bunny “eats” the things to collect them. For my codes, I used a lot of nested functions to make my codes clearer and easier to manipulate. I had a lot of fun creating this project as I have always wanted to create a cute game with movements of hearts that people can play with that cheers them up on bad days.

 

Collect hearts to gain points
Bomb kills the bunny

Emily Zhou –– Final Project

Hi there, my final project is 900 x 450 px but WordPress cuts it off at 600 px width so here is the zip file to see the full thing: moon-exp.zip

Instructions: Click the stars to traverse the timeline of humanity’s exploration of the moon.

Details: Each click should reveal a key event in moon exploration in chronological order. The representation of the moon should slowly fill as time passes. After revealing all 26 events, the stars should be connected as one single constellation.

final project

var starX = [245, 260, 295, 325, 325, 365, 410, 400, 380, 390, 360, 355, 335, 
             265, 240, 205, 185, 170, 85, 95, 50, 60, 55, 65, 100, 120, 140];
var starY = [40, 32, 60, 85, 85, 100, 225, 275, 290, 305, 355, 370, 352, 385, 
             395, 382, 385, 380, 340, 325, 275, 250, 230, 140, 110, 100, 70];
var starD = [10, 6, 4, 10, 10, 6, 10, 4, 5, 8, 5, 4, 8, 6, 
             10, 4, 6, 5, 10, 5, 4, 6, 10, 5, 8, 4, 5];
var time = ["1609", "1610", "1610", "1645", "1647", "1651", "1753", "1824", "1920", "1959", 
            "1961", "1964", "1966", "1967", "1968", "1969", "1969", "1972", "1976", 
            "1990", "1994", "1998", "2007", "2007", "2008", "2009"];
var data = ["Hans Lippershey invented the telescope.",
            "Galileo Galilei made the first telescopic observation of the moon.",
            "Thomas Harriot and Galileo Galilei drew the first telescopic representation of the moon.",
            "Michael Florent van Langren made the first map of the moon.",
            "Johannes Hevelius published the first treatise devoted to the moon.",
            "Giovanni Battista Riccioli named craters after philosophers and astronomers.",
            "Roger Joseph Boscovich proved the moon has no atmosphere.",
            "Franz von Gruithuisen thought craters were formed by meteor strikes.",
            "Robert Goddard suggested sending rockets to the moon.",
            "Soviet spacecraft Luna 2 reached the moon, impacting near the crater Autolycus.",
            "President John F. Kennedy proposed a manned lunar program.",
            "NASA's Ranger 7 produced the first close-up TV pictures of the lunar surface.",
            "Soviet spacecraft Luna 9 made the first soft landing on the moon.",
            "NASA's Lunar Orbiter missions completed photographic mapping of the moon.",
            "NASA's Apollo 8 made the first manned flight to the moon, circling it 10 times before returning to Earth.",
            "Apollo 11 mission made the first landing on the moon and returned samples.",
            "Apollo 12 made first precision landing on the the moon.",
            "Apollo 17 made the last manned landing of the Apollo Program.",
            "Soviet Luna 24 returned the last sample to be returned from the moon (to date).",
            "NASA's Galileo spacecraft obtained multispectral images of the western limb and part of the far side of the moon.",
            "NASA's Clementine mission conducted multispectral mapping of the moon.",
            "NASA's Lunar Prospector mission launched.",
            "Japanese SELENE (Kaguya) spacecraft launched.",
            "Chinese Chang'e 1 lunar orbiter launched.",
            "Indian Chandrayaan 1 moon orbiter launched.",
            "NASA's Lunar Reconnaissance Orbiter launched"]
var newData = [];
var newTime = [];

var speed = 100; // typing speed
var maxCharacters = 65; // max characters per line
var spacing = 15; // spacing between lines
var clicks = 0; // click count
var next = 0; // to evaluate when next star is clicked

var starClickIndices = []; // index values of clicked stars
var clear1 = []; // stores handles for text either appearing or intercepting
var clear2 = []; // stores handles for text either appearing or intercepting
var toClearOne = true; // used to differentiate between clear1 and clear2

function setup() {
    createCanvas(900, 450);
    background(255, 255, 255);

    // to match time to new data array
    for (var i = 0; i < time.length; i++) {
    	newTime.push([]);
    	newTime[i].push(time[i]);
    }

    // code to split long text lines 
    for (var i = 0; i < data.length; i++) {
    	newData.push([]);
    	var stringStart = 0;
    	var stringEnd = 0;
    	
    	while (stringEnd < data[i].length) {

    		stringEnd += maxCharacters;

    		var trunc = stringEnd; // index of where to truncate
    		while (data[i].substring(trunc - 1, trunc) != " " & 
    				(stringEnd - trunc <= 10)) {
    			trunc--;
    		}

    		if (data[i].substring(trunc - 1, trunc) == " ") {
    			newData[i].push(data[i].substring(stringStart, trunc));
    			stringStart = trunc;
    			stringEnd = trunc;
    		}
    		else {
    			newData[i].push(data[i].substring(stringStart, stringEnd));
    			stringStart = stringEnd;
    		}
    	}
    }

    // frame
    noFill();
    stroke(220);
    rect(0, 0, width - 1, height - 1);
}

function draw() {
    // moon
    moonChord();

    // constellation lines
    for (var i = 1; i < starClickIndices.length; i++) {
        stroke(220);
        strokeWeight(0.5);
        line(starX[starClickIndices[i]], starY[starClickIndices[i]], 
        	starX[starClickIndices[i - 1]], starY[starClickIndices[i - 1]]);
    }

    if (next != clicks) {

        // erase text
        fill(255);
        noStroke();
        rect(450, 170, 425, 125);

        // code to type text
        if (toClearOne) {
        	for (var i = clear1.length - 1; i >= 0; i--) {
        		clearTimeout(clear1[i]);
        		clear1.pop(i);
        	}
        }
        else {
        	for (var i = clear2.length - 1; i >= 0; i--) {
        		clearTimeout(clear2[i]);
        		clear2.pop(i);
        	}
        }

        toClearOne = ! toClearOne;

	    fill(220);
	    noStroke();

	    if (toClearOne) {
	        typeWriter(newTime[next], 0, 0, 475, 215, clear1);
	        typeWriter(newData[next], 0, 0, 475, 235, clear1);
	    }
	    else {
	        typeWriter(newTime[next], 0, 0, 475, 215, clear2);
	        typeWriter(newData[next], 0, 0, 475, 235, clear2);

	    }
    }

    // stars
    stroke(150);
    fill(150);
    for (i = 0; i < 27; i++) {
        ellipse(starX[i], starY[i], starD[i], starD[i],)
    }

    next = clicks;
}

function mousePressed() {
    for (var i = 0; i < 27; i++) {
        var distance = dist(mouseX, mouseY, starX[i], starY[i]);
        if (distance <= starD[i] / 2 + 2) {

        	var unclicked = true;
        	for (var j = 0; j < starClickIndices.length; j++) {
        		if (starClickIndices[j] == i) unclicked = false;
        	}

        	if (unclicked) {
	            starClickIndices.push(i);
	            clicks++;
	            if (clicks >= data.length) clicks = 0;
	            curStarIndex = i;
	        }
        }
    }
}

// typewriter effect to print text
function typeWriter(info, r, c, x, y, clear) {
    if (r < (info.length)) {

    	c++;
    	if (c > info[r].length) {
    		c = 1;
    		r++;
    	}

        if (r < info.length) {
	        noStroke();
	        textSize(12);
	        text(info[r].substring(0, c), 
	            x, y + (r * spacing));

	        var handle = setTimeout(function() {
		          typeWriter(info, r, c, x, y, clear)
		        }, speed)
	        clear.push(handle);
	    }

    }
}

// continuously draw chords fill moon
function moonChord() {
    stroke(0, 0, 0, 15);

    var angle1 = random(0, 2 * PI);
    var px1 = 225 + 150 * cos(angle1);
    var py1 = 225 + 150 * sin(angle1);

    var angle2 = random(0, 2 * PI);
    var px2 = 225 + 150 * cos(angle2);
    var py2 = 225 + 150 * sin(angle2);

    line(px1, py1, px2, py2);
}

Progression:

Reflection: The hardest part was getting the typewriter text to print like I wanted and coordinating all of the different actions to the mouse click.

Sources:
The representation of the moon was inspired by this example on p5js.org:
https://p5js.org/examples/math-random-chords.html
I referenced this code as a starting point for developing the typewriter text:
https://gist.github.com/mjvo/2dce29799eb75b7ee1a571380f12ef1b

Eliza Pratt – Final Project

dress up doll

/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Final Project
*/

//This program uses images to simulate an interactive dressup game.
//It allows users to click on items which will then jump to the 
//front of the screen via reordering of the array. Users can drag 
//clothing close to the body, where it will then snap into place
//in a smooth motion. When a shirt is snapped onto the body, a button
//will appear that allows the user to recolor the shirt (if clothing is 
//layered, only the top layer will be recolored). There is additional
//functionality for resetting the canvas and randomizing outfits.

//stores figure and clothing image links
var croquisLink = "https://i.imgur.com/7aZm27c.png";

var hairLinks = ["https://i.imgur.com/SwP45yO.png", 
                 "https://i.imgur.com/TqmIRYi.png", 
                 "https://i.imgur.com/JqFGPxq.png", 
                 "https://i.imgur.com/QzqTfIY.png", 
                ];

var shirtLinks = ["https://i.imgur.com/vNLNc6V.png", 
                 "https://i.imgur.com/e3LzXk6.png", 
                 "https://i.imgur.com/tBuSMNk.png", 
                 "https://i.imgur.com/wkJ7JJC.png"
                ];

var pantsLinks = ["https://i.imgur.com/hyAxaOY.png", 
                 "https://i.imgur.com/yk3zFDt.png", 
                 "https://i.imgur.com/mF21MeN.png", 
                  "https://i.imgur.com/ki89EhN.png"
                ];

var shoesLinks = ["https://i.imgur.com/EMbMtDy.png", 
                 "https://i.imgur.com/IZaU3Ls.png", 
                 "https://i.imgur.com/xa3Rrjs.png", 
                 "https://i.imgur.com/S8GJRGa.png"
                ];

//loads images for figure and clothing
var croquis;
var hair = [];
var shirt = [];
var pants = [];
var shoes = [];

//stores clothing objects
var blouse = [];
var bottom = [];
var feet = [];

//positions for figure and clothing
var bodyCenter = 120;
var headCenterY = 87;
var shirtCenter = 224;
var pantsCenter = 389;
var shoesCenter = 544;

//stores colors for clothing
var wheel = ["white", "red", "turquoise", "green"];
//image link for color wheel
var colorLink = "https://upload.wikimedia.org/wikipedia/commons/d/dc/Eight-colour-wheel-2D.png";
//stores color wheel image
var colorWheel;
//positions for wheel
var wheelX = 40;
var wheelY = 140;

//positions for random button
var randomX = 490;
var randomY = 580;

//positions for direction button
var infoX = 560;
var infoY = 580;

//counters for changing hair style and clothing color
var hairClick = 0;
var colorClick = 0;

//reset and random button color
var buttonColor = 255;

//indicate that pants and shoes are not being dragged
var dragBottom = false;
var dragFeet = false;

//array position of shirt on body
var wearing;

//display directions
var showInfo = false;
//------------------------------------------------------------------

//loads images into variables and arrays
function preload() {
    croquis = loadImage(croquisLink);
    colorWheel = loadImage(colorLink);
    for (var i = 0; i < hairLinks.length; i++) {
        hair[i] = loadImage(hairLinks[i]);
        shirt[i] = loadImage(shirtLinks[i]);
        pants[i] = loadImage(pantsLinks[i]);
        shoes[i] = loadImage(shoesLinks[i]);
    }
}


function setup() {
    createCanvas(600, 600);
    //calls function to make clothing objects and arrange on the page
    clothesSetup();
}


//fills shirt, shoes and pants arrays with objects containing images and positions
//serves as a reset function when mix() and reset() are called
function clothesSetup() {
    hairClick = 0;
    for (var i = 0; i < 4; i++) {
        blouse[i] = makeItem(shirt[i], width * 0.48 + 81 * i, 
                             height * 0.15 + 20 * i, shirtCenter);
        bottom[i] = makeItem(pants[i], width * 0.49 + 77 * i, 
                             height * 0.55 + 10 * i, pantsCenter);
        feet[i] = makeItem(shoes[i], width * 0.49 + 77 * i, 
                             height * 0.85 + 5 * i, shoesCenter);
    }
}


function draw() {
    background(206, 255, 181);
    imageMode(CENTER);

    //displays figure
    image(croquis, bodyCenter, height / 2, 225, 600);

    //displays clothing
    for (var i = 0; i < shirt.length; i++) {
        //draws current hair style
        image(hair[hairClick % 4], bodyCenter, headCenterY);
        //draws all pants, shirts and shoes
        bottom[i].draw();
        blouse[i].draw();
        feet[i].draw();

        //if shirt is on the body, store index and make color wheel appear
        if (blouse[i].x == bodyCenter) {
            drawWheel();
            wearing = i;
        }
    }

    //calls function to fit clothing on the figure
    snap(blouse);
    snap(bottom);
    snap(feet);

    //calls reset function
    reset();
    //calls direction function
    directions();

    //If the mouse is not being pressed, reset drag state to false
    //Note: this will be utilized in the mouseDragged function to prevent
    //multiple items from being "picked up" at once
    if (!mouseIsPressed) {
        dragBottom = false;
        dragFeet = false;
    }

    //draw random button
    drawButton("random", randomX, randomY, buttonColor);
    drawButton("directions", infoX, infoY, buttonColor);
}


function mousePressed() {
    //HAIR STYLE----------------------------------------------------
    //distance from mouse to head
    var dHair = dist(mouseX, mouseY, bodyCenter, headCenterY);

    //if hair is clicked, increase counter to display different style
    if (dHair < 60) hairClick++;

    //--------------------------------------------------------------

    var click = false; //tracks if a clothing item has been selected
    var selection; //stores type of selected item

    //SHIRT---------------------------------------------
    //cycle through shirt positions
    for (var i = 0; i < blouse.length; i++) { 
        var dBlouse = dist(mouseX, mouseY, blouse[i].x, blouse[i].y);
        //if shirt is clicked, store the array and index
        if (dBlouse < 75) {
            index = i;
            click = true;
            selection = blouse;
        }
    }

    //PANTS-------------------------------------------
    //cycle through pants positions
    for (var i = 0; i < bottom.length; i++) { 
        var dBottomX = abs(mouseX - bottom[i].x);
        var dBottomY = abs(mouseY - bottom[i].y);
        //if pants are clicked, store the array and index
        if (dBottomX < 60 & dBottomY < 150) {
            index = i;
            click = true;
            selection = bottom;
        }
    }

    //SHOES-------------------------------------------
    //cycle through shoes positions
    for (var i = 0; i < feet.length; i++) { 
        var dFeetX = abs(mouseX - feet[i].x);
        var dFeetY = abs(mouseY - feet[i].y);
        //if shoes is clicked, store the array and index
        if (dFeetX < 60 & dFeetY < 40) {
            index = i;
            click = true;
            selection = feet;
        }
    }

    //if an item is selected, display it on top of other items
    if (click) bringToFront(selection, index);  
    //---------------------------------------------------------------

    //RECOLORING-----------------------------------------
    //distance from mouse to button
    var dTint = dist(mouseX, mouseY, wheelX, wheelY);
    //if button is clicked, recolor item
    if (dTint < 20) recolor(3);

    //RANDOM OUTFIT--------------------------------------
    //distance from mouse to button
    var dRandomX = abs(randomX - mouseX);
    var dRandomY = abs(randomY - mouseY);

    //if button is clicked, assemble a random outfit
    if (dRandomX < 30 & dRandomY < 12) mix();

    //DIRECTIONS-----------------------------------------
    //distance from mouse to button
    var dInfoX = abs(infoX - mouseX);
    var dInfoY = abs(infoY - mouseY);

    //if button is clicked, display info
    if (dInfoX < 30 & dInfoY < 12) showInfo = !showInfo;
}


//if an item is selected, push it to the end of the array
//and remove it from its original position.
//Reordering the array allows item to displayed "on top"
function bringToFront(item, index) {
    item.push(item[index]);
    item.splice(index, 1);   
}


function mouseDragged() {
    //distance between mouse and "most recent" shirt, pants and shoe positions
    var dBlouse = dist(mouseX, mouseY, blouse[3].x, blouse[3].y);
    var dBottomX = abs(mouseX - bottom[3].x);
    var dBottomY = abs(mouseY - bottom[3].y);
    var dFeetX = abs(mouseX - feet[3].x);
    var dFeetY = abs(mouseY - feet[3].y);

    //If mouse is on the shirt and no pants or shoes are 
    //already selected, call function to allow dragging.
    //Establishing items as "true" when they are selected prevents
    //other items from being picked up while the mouse is dragged.
    if (dBlouse < 80 & !dragBottom && !dragFeet) {
        dragItem(blouse, 30);
    }
        // if only shoes are selected, allow them to be dragged
    else if (dFeetX < 60 & dFeetY < 50 && !dragBottom) {
        dragFeet = true;
        dragItem(feet, 0);
    }
    // if only pants are selected, allow them to be dragged
    else if (dBottomX < 60 & dBottomY < 140 && !dragFeet) {
        dragBottom = true;
        dragItem(bottom, 90);
    }
}


//allows selected item to be dragged
function dragItem(item, offset) {
    item[3].x = mouseX;
    item[3].y = mouseY + offset;
}


//snaps items near the body to their fixed positions
function snap(item) {
    //measures distance from item to target position
    var dx = bodyCenter - item[3].x;
    var dy = item[3].center - item[3].y;
    var D = sqrt(dx*dx + dy*dy);

    //when an item is near its target and the mouse is released,
    //snap it into position with a smooth motion
    if (D < 50 & !mouseIsPressed) {
        dirX = dx / max(1, D);
        dirY = dy / max(1, D);
        item[3].x += dirX;
        item[3].y += dirY;
    }
}


//BUTTON FUNCTIONS-------------------------------------

//draw button with label, position, and color parameters
function drawButton(type, x, y, col) {
    //button
    stroke(0);
    strokeWeight(2);
    fill(col);
    rectMode(CENTER);
    rect(x, y, 60, 24, 10);
    //text
    noStroke();
    fill("MAGENTA");
    textAlign(CENTER);
    text(type, x, y + 5);
}


//provides button to reset clothes to original position
function reset() {
    //button position
    var buttonX = 420;
    var buttonY = 580;

    //distance from mouse to center of button
    var dResetX = abs(buttonX - mouseX);
    var dResetY = abs(buttonY - mouseY);

    //if button is clicked, recall setup and draw "clicked" button
    if (mouseIsPressed & dResetX < 30 && dResetY < 12) {
        drawButton("reset", buttonX, buttonY, buttonColor - 80);
        clothesSetup();
    }
    //else, draw button in unclicked state
    else drawButton("reset", buttonX, buttonY, buttonColor);
}


//draw color wheel with an outline
function drawWheel() {
    image(colorWheel, wheelX, wheelY, 40, 40);
    noFill();
    stroke(0);
    strokeWeight(2);
    ellipse(wheelX, wheelY, 37, 37); 
}


//recolors shirt when wheel is clicked
function recolor() {
    //increase color counter and assign tint
    colorClick++;
    blouse[wearing].tint = wheel[colorClick % 4];
}


//provides button to assemble a random outfit
function mix() {
    //selects a random shirt, pants and shoe pairing
    var randBlouse = round(random(3));
    var randBottom = round(random(3));
    var randShoes = round(random(3));

    //draw button in "clicked" mode
    //call setup to remove any clothes on the body
    clothesSetup();
    //selects random hair style
    hairClick = round(random(3));

    //positions random shirt on the body
    blouse[randBlouse].x = bodyCenter;
    blouse[randBlouse].y = shirtCenter;
    //positions random pants on the body
    bottom[randBottom].x = bodyCenter;
    bottom[randBottom].y = pantsCenter;
    //positions random shoes on the body
    feet[randShoes].x = bodyCenter;
    feet[randShoes].y = shoesCenter; 
}


//displays directions for game
function directions() {
    if (showInfo) {
        stroke(0);
        strokeWeight(10);
        fill(255);
        rect(width / 2, height / 2, 400, 150, 30);
        noStroke();
        fill("MAGENTA");
        text("Drag and drop the clothes to make one chic as heck fashion diva", width / 2, height / 2 - 30);
        text("Click her face to change hair styles", width / 2, height / 2 - 5);
        text("Click the color wheel to recolor her shirt", width / 2, height / 2 + 20);
        text("(Press any key to escape)", width / 2, height / 2 + 60);
    }
    //exits directions when a key is pressed
    if (keyIsPressed) showInfo = false;
}

//---------------------------------------------------------------------

//OBJECT CREATION AND CLOTHING DISPLAY

//Creates objects with parameters for
//image, initial position, and center relative to the body.
function makeItem(ipic, ix, iy, icenter) {
    return {pic: ipic, x: ix, y: iy, 
            center: icenter, 
            tint: 255,
            draw: drawItem,
            };
}


//draw image and recolor with specified tint
function drawItem() {
    tint(this.tint);
    image(this.pic, this.x, this.y);
    noTint();
}



Directions: Drag and drop the clothes to make one chic-as-heck fashion diva! Click on the hair to change the style. If you give her a shirt, you can tint it by clicking on the color wheel. Click the random button to generate a random outfit, and click the reset button to put everything back!

Statement: This project was a lot of fun to make and I loved that I was able to incorporate my own drawing style with my code! It ended up being a lot more complicated than I thought to get the click, drag, and drop functions right, but I’m happy with what I was able to do. I’m proud I was able to figure out a way to change the order in which items were displayed on the screen, and I think this level of responsiveness helps my project feel more like a real dress up game. While I’m happy with how the game turned out, I do wish I could have the mouse respond to clicking anywhere on a clothing item rather than estimating its distance from the center.

Rachel Lee and Jenna Kim Section E Final Project

Space Crunch

/* Rachel Lee and Jenna Kim
rwlee@andrew.cmu.edu and jeeyoonk@andrew.cmu.edu
Section E
Final Project */

// Radius of cereal loops
var radius = 20;
// Number of cereal pieces displayed (maximum number possible)
var cerealNum = 50;
// Empty array that holds cheerio elements
var cereal = [];
// Variable to store clicked cereal pieces
var clicked;
// Game time elapsed
var time_elapsed = 0;
// Game duration (60 seconds)
var gameLength = 120;
// Changes states according to instructions screen, game and game over
var gameMode = 0;

var x = [];
var y = [];

function setup() {
    createCanvas(600, 500);
    frameRate(10);

    // Variables for spacing of cereal loops according to triangle principles
    var tw = 90; // horizontal spacing between cheerios
    var th = 70; // vertical spacing between cheerios
    var cy = 50; // original y position
    var cx = 30; // original x position

    // Creates and pushes cereal into empty array
    for (var y = 0; y < 10; y ++) {
        // creates and displays even rows
        if ((y % 2) == 0) {
            for (var x = 0; x < 15; x++) {
                var px = cx + x * tw;
                var py = cy + y * th;
                cereal.push(new cheerios(px, py));
            }
        }
        // Creates and displays offset odd rows
        else {
            for (var x = 0; x < 10; x++) {
                th = 60 * (sqrt(3) / 2);
                var px = cx + x * tw;
                var py = cy + y * th;
                cereal.push(new cheerios (px + tw / 2, py + 150));
            } 
        } 
    } 
    
    // Initializes the player's score
    clicked = 0;

    // Updates cereal every second to determine if they pop up or not
    // Updates timer every second (1000 = 1 second in milliseconds)
    setInterval(function() {
        for (var i = 0; i < cerealNum; i ++) {
            cereal[i].updateC();
        }
        time_elapsed += 2;
    }, 1000);
}

function draw() {
	// Color gradient sky
    var color1 = color(0, 0, 153); // Blue purple
    var color2 = color(204, 51, 0); // Red

    for (var i = 0; i < height; i++) {
        var gradient = map(i, 0, height / 2, 0, 1);
        // Lerp used to ease color transitions 
        var mesh = lerpColor(color1, color2, gradient); 
        fill(mesh);
        stroke(mesh);
        line (0, i, width, i);
    }

    hillShadow();
    hill();

    noStroke();

    // Instruction page/ start game mode
    if (gameMode == 0) {
        gameStart();
    }

    // If game is still running, draws cereal, UFO, game score and time tracker
    if (gameMode == 1) {
        for (var i = 0; i < cerealNum; i ++){
            cereal[i].drawC();
        }  
        drawUFO();
        gSgT();
    }

    // Game ends when timer runs out
    if (time_elapsed >= gameLength) {
        gameMode = 2;
        gameOver();
    }

    // Press s key to start game
    if (keyIsPressed) {
    	if((key == 's') || (key == 'S')) {
    		gameMode = 1;
    	}
    	// When the game is over, press r key to reset game
        if ((key == 'r') || (key == 'R')) {
            gameMode = 1;
            time_elapsed = 0;
            clicked = 0;
        }
    }
}

// Draws UFO that follows mouse position
function drawUFO() {
    strokeCap(ROUND);
    stroke(230);
    strokeWeight(4);
    line(mouseX + 12, mouseY + 2, mouseX + 27, mouseY + 14);
    line(mouseX - 12, mouseY + 2, mouseX - 27, mouseY + 14);
    noStroke();
    fill(245, 210, 145); // orange peach
    ellipse(mouseX, mouseY + 7, 57, 16);
    fill(55, 70, 140); // blue 
    ellipse(mouseX, mouseY - 1.5, 85, 25);
    fill(255, 105, 80); // orange 
    ellipse(mouseX, mouseY - 3.5, 85, 25);
    fill(245, 210, 145); // orange peach
    arc(mouseX, mouseY - 7, 57, 37, PI, TWO_PI);
    ellipse(mouseX, mouseY - 7, 57, 16);
}

// Defines object constraints
function cheerios(x, y, duration, drawC, updateC, clickedC) {
    var pos = {x: x, y: y, duration: duration, drawC: drawCheerios, 
    updateC: updateCheerios, clickedC: clickedCheerios};
    return pos;
}

function drawCheerios() {
    if (this.duration > 0) {
        stroke(180, 147, 119);
        strokeWeight(8);
        noFill();
        ellipse(this.x, this.y, radius, radius);
        stroke(240, 225, 190);
        ellipse(this.x + 2, this.y + 2, radius, radius);
    }
}

//Determines whether or not the cheerios appear
function updateCheerios() {
    if (this.duration > 0) {
        this.duration = this.duration - 0.5;
    } 
    else {
        var ratio = random(1);
        if (ratio < 0.15) {
            this.duration = random(5);
        }
    }
}

// Checks to see if user clicked the cereal, and adds to score
function clickedCheerios (clickedX, clickedY) {
    if ((dist(clickedX, clickedY, this.x, this.y - radius) < radius) & (this.duration >= 0)) {
        this.duration = 0;
        clicked += 1;  
    }
}

// Checks to see if the mouse was pressed, and if the cereal was clicked
function mousePressed() {
    for (var i = 0; i < cerealNum; i++) {
        cereal[i].clickedC(mouseX, mouseY);
    }
}

function gameStart() {
    // Color gradient sky start
    var colorStart1 = color(0, 0, 153); // Blue purple
    var colorStart2 = color(204, 51, 0); // Red

    for (var i = 0; i < height; i++) {
        var gradientStart = map(i, 0, height / 0.9, 0, 1);
        // Lerp used to ease color transitions 
        var meshStart = lerpColor(colorStart1, colorStart2, gradientStart); 
        fill(meshStart);
        stroke(meshStart);
        line (0, i, width, i);
    }

    fill(255);
    textFont('Futura');
    textSize(13);
    text("Collect cheerios to fuel the U.F.O.'s journey through outer space!", width / 10 + 50, height / 2);
    text("Press S to Start", width/ 10 + 200, height/ 2 + 30);
}

// Display game score and remaining game time
function gSgT() {
    fill(255);
    textFont('Futura');
    textSize(12);
    text("Score : " + clicked, 500, height - 40);
    text("Time Remaining: " + (60 * 2 - time_elapsed)/2 + " secs", 50, height - 40);	
}

// Game over screen
function gameOver() {
    // Color gradient sky end
    var colorEnd1 = color(204, 51, 0); // Red
    var colorEnd2 = color(0, 0, 153); // Blue purple

    for (var i = 0; i < height; i++) {
        var gradientEnd = map(i, 0, height / 0.7, 0, 1);
        // Lerp used to ease color transitions 
        var meshEnd = lerpColor(colorEnd1, colorEnd2, gradientEnd); 
        fill(meshEnd);
        stroke(meshEnd);
        line (0, i, width, i);
    }
    noStroke();
    fill(255);
    text("Game Over!", width/ 2 - width/ 20, height/ 2 - 30);
    text("Cheerios Collected : " + clicked, width/ 3 + 35, height/ 2);
    text("Press R to restart", width/ 3 + 55, height/ 2 + 30);
}

//drawing hill
function hill() {
    var hillSpeed = 0.0002;
    var hillDetail = 0.0025;
    stroke(210, 105, 95, 80);
    for (var x = 0; x < width; x++) {
        var t = (x * hillDetail) + (millis() * hillSpeed);
        var y = map(noise(t * 2), 0, 1, 330, 200);
        line(x, y, x, height);
    }
} 

function hillShadow() {
    var hillSpeed = 0.0001;
    var hillDetail = 0.0045;
    stroke(160, 70, 70, 55);
    for (var x = 0; x < width; x++) {
        var t = (x * hillDetail) + (millis() * hillSpeed);
        var y = map(noise(t * 2.2), 0, 1, 100, 300);
        line(x, y, x, height);
    }   
}

Backstory and Instructions

Help the U.F.O. continue its intergalactic journey by collecting cheerio fuel! Click on the cheerios before they disappear, and collect as many as possible before the timer runs out. Running game time is 60 seconds.

Work Distribution 

For our project, Rachel primarily focused on the structure and mechanics of the game. Rachel created the mechanism for the flashing cheerios on screen, the game timer and the score keeping system when cheerios were pressed. Jenna focused more on the visual aspect of the game, designing the background / scenery, U.F.O., as well as the ‘Start Game’ and ‘Game Over’ pages and the mechanics of the game modes (Start, actual game, end game).

Working Together

Overall, we had a lot of fun working together. We were able to make revisions and improvements to our code in terms of style, efficiency of structure and visuals through continued collaboration.

First iteration
Second Iteration

 

Yingying Yan- Project-12-Proposal

For the final project, I am interested in data visualization. More specifically, I want to represent the data of Pittsburgh’s rainfall record using what I learned from 104. The goal of this project is to allow people to “see” how much rainwater Pittsburgh gets for the past year. And what we can possibly do with the rainwater if we collected fifty percent or thirty-five percent of it. The project should also be visually attractive and easy to understand. So the audience will be interested and comprehending the message that the project tries to relate.

I am not sure how this project will look like yet.

Yingying Yan-Looking Outwards-12

The two projects I find interesting are both from data visualization practitioners. Phantom Terrains by Stefanie Posavec is an audio interface which communicates the silent wireless signals that are in London, where they collected the data from. The goal was to convert the characteristics of the invisible wireless data into sound. People will be able to hear the changes in the landscape of sound around them. I am less interested in what the experience the soundtrack creates. But the visualization that the project created is very interesting. It conveys the information while also visually attracting.

2d graphic

The second project that I am interested in is Unnumbered Spark by Aaron Koblin. This is a sculpture or building size installation that allows the audience to control the projection on the soft fabric. This project is more like a motivation for me. Allow me to see what data visualization can possibly become.

Nina Yoo – Looking Outwards – 12

“VOEZ”

 howls moving castle howl calcifer studio ghibli pixel gif png transparent pixel art pixal 8bit 8bit art

“Howl’s Moving Castle Howl and Casper”

 

So the two things that I got inspired by is the music game VOEZ and the 8bit character versions of studio Ghibli.  I have always been interested in music games and I’ve been playing them for a long time. VOEZ is game I have been playing for a while because their music and graphics are so beautiful and pleasing to experience. VOEZ is the sort of music game vibe that I wanted to have in collaboration with the music and characters from Studio Ghibli. Ghibli’s music is very well known and it has been an iconic for being one of the most relaxing pieces ever made. Along with the music, the characters made in Studio Ghibli are amazing with pastel colors that are just pleasing to see. I also got inspired by the 8bit form because it reminds me more of a game.

 

Nina Yoo- Final Project-Proposal

For this final project I wanted to do something with Studio Ghibli and their music. So I decided to have a rhythm game where if you press a certain key then a character from one of the Ghibli films will pop up. If you press two keys as the same time and have matching characters then the music of the movie will start to play until you find another matching pair. The characters will just be bouncing up and down when they appear on the screen and I might add some actions to them. I will limit the keys from A-L and Space which will mean there will be 10 characters total and 5 pairs.  Also, along with the music being played the title of the movie or film will pop up on the screen.  This game will have a plain background until there is a match where I will load in a picture background/ scene from the movie.