Final Project: Survive the Particles

For my final project, I create a particle game in which the player attempts to avoid an increasing amount of particles which follow the cursor. The circular cursor is controlled by the mouse and is the direction in which all the particles move individually towards. A timer tracks the number of red particles on the screen and acts as a scoreboard which halts when the cursor makes contact with a particle. This game is based off one of my favorite iPhone apps which I discuss in my project priors and precursors.

The main source code comes from the Flock Particle Mutual Interactions example from our class notes. Overall, I was able to execute my original proposal. There were some features that I found worked better than others which was the main difference between my proposal and my final project.

 

sketch

//Kyle Lee
//Section C
//kdlee@andrew.cmu.edu
//Final Project

function particleUpdate() {
    if (this.bFixed == false) {
        this.vx *= this.damping;
        this.vy *= this.damping;

        this.px += this.vx;
        this.py += this.vy;
    }
    if (this.px + particleDiameter/2 > width ||
        this.px - particleDiameter/2 < 0){
        this.vx = -this.vx;
    }
    if (this.py + particleDiameter/2 > height ||
        this.py - particleDiameter/2 < 0){
        this.vy = -this.vy;
    }
}

var particleDiameter = 8;
function particleDraw() {
    fill("#FA4E44");//red
    ellipse(this.px, this.py, particleDiameter, particleDiameter);
}

// add a force to the particle using F = mA
function particleAddForce(fx, fy) {
    var ax = fx / this.mass;
    var ay = fy / this.mass;
    this.vx += ax;
    this.vy += ay;
}


// make a new particle
function makeParticle(x, y, dx, dy) {
    var p = {px: x, py: y, vx: dx, vy: dy,
             mass: 1.0, damping: 0.9,
             bFixed: false,
             addForce: particleAddForce,
             update: particleUpdate,
             draw: particleDraw
            }
    return p;
}

var seekFactor = 0.0010;
function seek(p) {
    var desiredX = mouseX - p.px;
    var desiredY = mouseY - p.py;
    p.addForce(desiredX * seekFactor, desiredY * seekFactor);
}

//attempt to implement a restart without reloading page.
//Unable to empty array and restart time
// function keyPressed() {
//     loop();
//     background();
//     time = 0;
//     myParticles.push(time);
// }

var myParticles = [];
var nParticles = 1000;
var follow = true;
var cursorD = 30;
var x = 200;
var y = 200;
var diffx = 0;
var diffy = 0;

function setup() {
    createCanvas(400, 400);
    for (var i = 0; i < nParticles; i++) {
        var rx = random(width);
        var ry = random(height);
        var p = makeParticle(rx, ry, 0, 0);
        p.bElasticBoundaries = false;
        p.damping = 0.99;
        myParticles[i] = p;
    }
    frameRate(25);
    noStroke();
}

function draw() {
    background(250);
    var time = ceil(frameCount/10);
    var xConstrain = constrain(x, cursorD/2, width - cursorD/2);//mouse boundary
    var yConstrain = constrain(y, cursorD/2, height - cursorD/2);//mouse boundary
    for (var i = 0; i < time; i++) {
        var ithParticle = myParticles[i];
        ithParticle.fx = 0;
        ithParticle.fy = 0;
        if (follow) seek(ithParticle);
    }

    fill("#FA9998");
    textAlign(CENTER);
    textStyle(BOLD);
    textSize(36);
    text(time, width/2, 100);//displays time/score

    fill("#2A3447");
    ellipseMode(CENTER);
    diffx = mouseX - x;
    diffy = mouseY - y;
    x = x + 0.2*diffx;
    y = y + 0.2*diffy;
    ellipse(xConstrain, yConstrain, cursorD, cursorD);//draws cursor/player

    for (var i = 0; i < time; i++) {
        var p = myParticles[i]
        var length = dist(xConstrain, yConstrain, p.px, p.py);
        p.update(); // update all locations
        p.draw(); // draw all particles

        if (length < cursorD/2){//stops game
            textStyle(BOLD);
            textSize(48);
            fill("#FA4E44");
            text("Game Over", width/2, height/2);

            textStyle(NORMAL);
            textSize(14);
            fill(0);
            text("reload to restart", width/2, height/2 + 20);
            noLoop();
        }
    }
}

Final Project

For my final project I created an animation of a robot watching a tree grow through different seasons. I was able to create what I proposed in that the eyes watch the tree grow and there is something different about the robot in each season. I modified the tree example from lab so that it would grow at a steady rate. There is not much different between the project and my proposal except that I added a bit to summer and fall that were not mentioned. Overall some aspects of this project were harder to make than I thought, but it was a lot of fun to create.

sketch

//Rebecca Enright
//renright@andrew.cmu.edu
//Section A
//Final Project

//variables for rain/ snow/ leaves locations
var x;
var y;
//variable for ground color
var c;
//create object for umbrella
uX = 215;
uY = 240;
uR = 100;
uS = 50;
var umbrella = {locationX: uX, locationY: uY, left: uR, right: uS};

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

function draw() {
    background(0, 220, 255);
    //create variable for tree growth
    var growth = 0;
    growth = growth + (millis()/4000);
    //create condition to stop growth 
    if (growth > 30) {
    	growth = 30;	
    }

    //create conditionals to change scene
    if (second() <= 14) {
        MakeItRain();
    }
    
    if (second() > 14 & second() < 29 ) {
        summerSun(growth); 
    }

    if (second() >= 29 & second() < 44) {
        autumn(growth);
    }

    if (second() >= 44) {
    	LetItSnow();
    }

    //call tree function
    push();
    translate(400, 350);
    drawBranch(0, growth);
    pop();  
    //call robot functions
    drawRobot(growth);
    
}

//create tree
function drawBranch(depth, len) {
    stroke(215, 150, 60);
    line(0, 0, 0, -len);
    push();
    translate(0, -len);
    drawTree(depth + 1, len);
    stroke(0, 200, 0);
    pop();
    
}

//create tree
function drawTree(depth, len) {
    //variable for tree swaying
    var angle = 5 * (noise(millis()/4000) - 0.5);
    //conditional for number of branches
    if (depth < 10) {
        rotate(radians(-10 + angle));
        drawBranch(depth, len);
        rotate(radians(20));
        drawBranch(depth, len);
    }
}

//create general draw robot function
function drawRobot(growth) {
    //drawRock();
    drawRobotHead(growth);
    drawRobotBody();
}

//function for robot head
function drawRobotHead(growth) {
    //draw robot face
    fill(200);
    rect(200, 250, 25, 25);
    //draw robot eyes
    movingRobotEyes(growth);
    //draw robot smile
    fill(255);
    arc(218, 270, 10, 10, 0, PI);
    //draw robot antenna
    fill(200);
    rect(210, 240, 5, 10);  
}

//function for robot body
function drawRobotBody() {
	//draw neck
    fill(200);
    rect(207, 275, 10, 5);
    //draw stomach
    fill(200);
    rect(200, 280, 20, 30);
    //arm
    fill(200);
    rect(195, 280, 10, 20);
    rect(195, 300, 30, 10);
    //bolts for arm
    fill(190);
    ellipse(200, 285, 5, 5);
    ellipse(200, 305, 5, 5);
    //legs
    fill(200);
    rect(200, 310, 30, 10);
    rect(220, 310, 10, 25);
    //bolt for leg
    fill(190);
    ellipse(225, 315, 5, 5);
    //foot
    fill(200);
    rect(220, 335, 15, 5);
}

//create rock function for robot to sit on
function drawRock() {
    fill(175);
    ellipse(200, 325, 50, 25);
}

//create snow function for winter
function LetItSnow() {
    //draw ellipse
    fill(255);
    //variables for snowflake locations
    //x location
    x = 10 + random(5);
    //y location
    y = 0;
    y = 2 * y; 
    
    //make loop for snowflakes
    for (var i = 0; i < width; i++) {
        sX = x * i;
        sY = y + random(300);

        r = random(5, 10);
        ellipse(sX, sY, r, r);    
    }
    //create snowy ground
    fill(255);
	rect(0, 295, 599, 104);
	//draw red dot for robot antenna
    fill(255, 0, 0);
    ellipse(213, 240, 5, 5);
    //draw scarf
    scarf(); 
    //draw rock to sit on
    drawRock();  
}

//create rain function for spring
function MakeItRain() {
    stroke(0, 0, 255);
    //reset variables for x and y locations
    //x location
    x = 5;
    //y location 
    y = 0;
    y = y + 1;

    //make loop for rain drops
    for (var i = 0; i < width; i++) {
        //rain drop x and y location
        rX = x * i;
        rY = y + random(300);
        line(rX, rY, rX + 5, rY + 5);	
    }
    //reset stroke color
    stroke(0);
    
    //call workUmbrella to open umbrella
    workUmbrella();

    //create ground 
    fill(0, 190, 0);
	rect(0, 295, 599, 104);
	//draw rock to sit on
	drawRock();
}

//create function for umbrella
function workUmbrella() {
    fill(255, 0, 0);
    arc(umbrella.locationX, umbrella.locationY, umbrella.left, umbrella.right, PI, 0); 
    fill(0);
    ellipse(umbrella.locationX, umbrella.locationY - 25, 5, 5);
}

//create function for scarf
function scarf() {
	fill(0, 190, 0);
	rect(200, 275, 25, 5);
	fill(200);
	rect(220, 280, 5, 10);
    fill(0, 190, 0);
	rect(220, 290, 5, 10);
}

//create function for summer
function summerSun(growth) {//lX, lY, lS, lC, len) {
    //create sun
    fill(255, 255, 0);
    ellipse(100, 100, 50, 50);
    //create rays for sun
    push();
    translate(100, 100);
    for (i = 0; i < 8; i++) {
        //create sun rays
        rotate(QUARTER_PI);
        triangle(30, 30, 40, 60, 50, 50);
    }
    pop();
    //create ground
    fill(0, 227, 0);
    rect(0, 295, 599, 104); 
    

    //call leaves
    push();
    translate(400, 350);
    drawBranch2(0, growth);
    pop(); 
    //create flower for antenna 
    flower(); 
    //create rock to sit on
    drawRock();  
}
//create second drawbranch function for green during summer
function drawBranch2(depth, len) {
    stroke(0, 200, 0);
    line(0, 0, 0, -len);
    push();
    translate(0, -len);
    drawTree2(depth + 1, len);
    stroke(0, 200, 0);
    pop();
    
}

//create second drawtree for green during summer
function drawTree2(depth, len) {
    //variable for tree swaying
    var angle = 5 * (noise(millis()/4000) - 0.5);
    //conditional for tree branches
    if (depth < 12) {
        rotate(radians(-10 + angle));
        drawBranch2(depth, len);
        rotate(radians(20));
        drawBranch2(depth, len);
    }
}

//create function for fall
function autumn(growth) {
    //create ground
    fill(0, 210, 0);
    rect(0, 295, 599, 104); 
    //create leaves on ground
    var ln = 10;
    ln = ln + millis()/5000;

    for (i = 0; i < ln; i++) {
        //set random leaf locations around base of tree
        var lx = random(340, 460);
        var ly = random(350, 390);
        //create leaf size
        var ls = 1;
        ls = growth//1 + millis()/5000;
        //draw leaves
        fill(random(255), random(255), 0);
        ellipse(lx, ly, ls/2, ls/2 + 2);
    }
    //create background 
    fallLeafBackground(); 
    //draw  pumpkin for robot to sit on
    drawPumpkin();  
}

//create function for leaf background
function fallLeafBackground() {
    //reassign pixel vairables so m moves by 10
    //and reassign y so that it is randomized
    for (var i = 0; i < width; i++) {
        //leaf locations
        var blx = 25;
        blx = blx * i;
        var bly = random(1,300);
        //draw leaves
        fill(random(255), random(255), 0);
        ellipse(blx, bly, 5, 10);
       
    }

}


//put flower on antenna during summer
function flower() {
    //center
    fill(255, 255, 0);
	ellipse(215, 235, 5, 5);
    //petals
    push();
    translate(215, 235);
	for (var i = 0; i < 10; i++) {
        rotate(QUARTER_PI);
		fill(255);
		ellipse(5, 0, 5, 5);   
	}
	pop();
}

//create function so that robot eyes move
function movingRobotEyes(growth) {
	//variable for robot pupil y location
	var ey = 262;
	ey = ey - (millis()/4000)/10;
    //conditional to limit eye location
	if (ey < 259) {
		ey = 259;
	}

	//draw robot eyes
    fill(255);
    ellipse(210, 260, 10, 10);
    ellipse(225, 260, 10, 10);
    //pupil
    fill(0);
    ellipse(212, ey, 5, 5);
    ellipse(227, ey, 5, 5);
}

function drawPumpkin() {
    fill(255, 150, 0);
    ellipse(200, 325, 50, 25);
    fill(0);
    //eyes
    triangle(190, 325, 195, 320, 200, 325);
    triangle(205, 325, 210, 320, 215, 325);
    //mouth
    rect(190, 330, 25, 2);
    rect(195, 332, 5, 2);
    rect(205, 332, 5, 2);
}






Michal Luria – Final Project

mluria-final

/*  Submitted by: Michal Luria
    Section A: 9:00AM - 10:20AM
    mluria@andrew.cmu.edu
    Final-Project
*/

//variables to draw circles
var circles = []; //array of circle objects
var sentArray = []; //array for sentences
var posX = []; //the circle bases (character) X array
var posY = []; //the circle bases (character) Y array

//variables to determine most dominant character
var scores = []; //start with an empty array 
var currentHighest = 0; //currently most sentences
var winnerIndex; //the index of the winner
var previousWinnerIndex = -1; //the index of the previous winner 

function preload() {
    //load text to strings - each part (by character) is a string
    textArray = loadStrings('https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/the-miser.txt'); 

}

function setup () {

    createCanvas(700,500);
    frameRate(30);

    //determine initial positions of characters
    posX = [width/2, width/5, width/5*4, width/2, width/2, width/5, width/5*4]; 
    posY = [height/2, height/2, height/2, height/5, height/5*4, height/5*4, height/5];

    //initialize 0 for all scores
    for (var k = 0; k < posX.length; k++){

        scores[k] = 0;

    }

    //for every paragraph in the file (one string), split into sentences
    for (var i = 0; i < textArray.length; i++){ 

        //split sentences whenever one of the following chars appear: ;!?.
        sentArray = splitTokens(textArray[i], ";!?.");


        //The following code will do this: for every sentence a character says, create a circle object and draw it

        //if VAL is talking (if the word VAL in the string)
        if (textArray[i].indexOf("VAL") >= 0) {

            //for every sentence VAL speaks, push a circle object into the circle array
            for (var j = 1; j < sentArray.length; j++) {

                /*pass the following variables for each circle object: 
                                        name
                                        length of sentence (the size of the circle is determined by how long the sentence is)
                                        Start frame - each circle has a frame number on which it can start drawing (using FrameCount)
                                                      The start frame is influenced by the index of the play sentences (how far is
                                                      the sentence into the play [i]), by the current index [j], and by the
                                                      length of the previous sentence, in order to give a feel of the play dynamics
                                        Color
                                        Index number
                                        */
                circles.push(new Circle("VAL", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(247, 132, 163, 80), 0));
            }   

        }

        //The above comments are true for each one of the characters in the play below:

        //if ELI is talking (found in string)
        if (textArray[i].indexOf("ELI") >= 0) {

            //for every sentence ELI speaks, push a circle onject into array
            for (var j = 1; j < sentArray.length; j++) {

                circles.push(new Circle("ELI", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(132, 247, 159, 80), 1));
            }

        }

        //if CLE is talking (found in string)
        if (textArray[i].indexOf("CLE") >= 0) {

            //for every sentence CLE speaks, push a circle onject into array
            for (var j = 1; j < sentArray.length; j++) {

                circles.push(new Circle("CLE", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(132, 194, 247, 80), 2));
            }

        }

        //if HAR is talking (found in string)
        if (textArray[i].indexOf("HAR") >= 0) {

            //for every sentence HAR speaks, push a circle onject into array
            for (var j = 1; j < sentArray.length; j++) {

                circles.push(new Circle("HAR", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(255, 246, 100, 80), 3));
            }

        }

        //if LA FL is talking (found in string)
        if (textArray[i].indexOf("LA FL") >= 0) {

            //for every sentence LA FL speaks, push a circle onject into array
            for (var j = 1; j < sentArray.length; j++) {

                circles.push(new Circle("LA FL", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(205, 139, 255, 80), 4));
            }

        }


        //if SIM is talking (found in string)
        if (textArray[i].indexOf("SIM") >= 0) {

            //for every sentence SIM speaks, push a circle onject into array
            for (var j = 1; j < sentArray.length; j++) {

                circles.push(new Circle("SIM", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(133, 251, 255, 80), 5));
            }

        }

        //if FRO is talking (found in string)
        if (textArray[i].indexOf("FRO") >= 0) {

            //for every sentence FRO speaks, push a circle onject into array
            for (var j = 1; j < sentArray.length; j++) {

                circles.push(new Circle("FRO", sentArray[j].length, 
                                        j*i*20+(sentArray[j-1].length*2), color(255, 133, 255, 80), 6));
            }

        }

    }

}


function draw () {

    background(0);
    stroke(0);

    //draw all circle objects
    for (var i = 0; i < circles.length; i++){

        circles[i].draw();

    }

    //The follow section checks who the most dominant character (winner) is and updates their location

    //check all the scores all the time (score = number of sentences a character said)
    for (var j = 0; j < scores.length; j++){

        //if a score is higher the current highest score
        if (scores[j] > currentHighest) {

            currentHighest = scores[j]; //update highest score

            if (j != winnerIndex) { //if the highest score holder (character) changed

                previousWinnerIndex = winnerIndex; //update the previous winner category
                winnerIndex = j; //and update the new winner

            }


        }
    }

    /*Update the winner's location
    The following parts check where the winner is, and move them towards the center
    In parallel, the previous winner is moved in the opposite direction of the winner
    in order to switch between their locations */


    if (posX[winnerIndex] < width/2) {
        posX[winnerIndex]++; 
        posX[previousWinnerIndex]--; 
    }


    if (posY[winnerIndex] < height/2) {
        posY[winnerIndex]++;
        posY[previousWinnerIndex]--;
    }

    if (posX[winnerIndex] > width/2) {
        posX[winnerIndex]--;
        posX[previousWinnerIndex]++;
    }

    if (posY[winnerIndex] > height/2){
        posY[winnerIndex]--;
        posY[previousWinner]++;
    }

}

//define circle object: name, sentence array, start frame, color and index
function Circle(name, sentArray, 
     myStartFrame, circColor, index) {

    this.name = name; //name of actor
    this.sent = sentArray; //length of sentence
    this.index = index; // index of character
    this.x = posX[this.index]; //circle X location
    this.y = posY[this.index]; //circle Y location
    this.siz = 0; //circle Size
    this.start = myStartFrame; //the frame to start drawing the circle
    this.color = circColor; //the color of the circle
 

    this.draw = function() { //draw a circle

        noStroke();


  
        fill(this.color); //use the object's circle

        /*determine circle size by sentence length (as long as the size is smaller than the sentence length * 2.5)
        and only if the current frame count is bigger than the object's start frame
        draw the circle*/
        if (this.siz < this.sent * 2.5 & frameCount > this.start) {
            
            this.x = posX[this.index]; //update the x position according to winner check
            this.y = posY[this.index]; //update the y position according to winner check
            ellipse (this.x, this.y, this.siz, this.siz); //draw the circle
            this.siz++; //increase circle size
            scores[this.index]++; //increase the score count for the character for each of his/her sentence circle 

            //write the name of the character below (also shows up and disappears according to the character on stage)
            textSize(10); 
            text(this.name, this.index*100+40, height-50);

        } 

    }

}

The Miser / Moliere

In my final project I wanted to do data visualization. With a background in theater, I thought it would be interesting to look at plays and show new aspects by using their data.

I used the famous play “The Miser” by Moliere, and created several aspects that would allow viewers to get a sense of the play dynamics.

Description of what you see: 

  1. Each circle is a sentence in the play.
  2. The size of the circle represents the sentence length.
  3. The circle sequence is according to the chronological order of sentences in the play.
  4. The interval between sentences is in proportion to the length of the previous sentence.
  5. The most dominant character in each part of the play is centered in location.

My final project visualized each sentence by a character in the play using a circle, “played” in the order of the characters text. The size of each circle visualizes the length of the sentence. The project also presents who is on stage at every given moment, and finally, the character that is most dominant in the play comes to the center of the stage.

I hope that using these aspects, it will be easy to get a sense of the pace of the play, if the dialog is quick or slow, who talks a lot and who is more quiet, when monologs occur, and who dominates the play dynamics. I hope that the visualization will allow looking at a famous masterpiece in a new light.

Project 3 – Alison Hoffman

sketch

//Alison Hoffman
//Section D
//achoffma@andrew.cmu.edu
//Project 3

//*This Program is a dynamic drawing that responds to the mouseX and mouseY position
function setup() {
    createCanvas(640,480);
}

function draw() {
    background("lavender");
    noStroke();
    rectMode(CENTER);

    var boxColor = map(mouseX,0,width,0,180);
    var boxTrans = map(mouseX,0,width,100,255);
    //top row 
    fill(boxColor);
    push();
    translate(width*.15,100);
    rotate(radians(mouseX));
    rect(0,0,50,50);
    pop();
    push();
    translate(width*.38,100);
    rotate(radians(-mouseX));
    rect(0,0,50,50);
    pop();
    push();
    translate(width*.62,100);
    rotate(radians(mouseX));
    rect(0,0,50,50);
    pop();
    push();
    translate(width*.85,100);
    rotate(radians(-mouseX));
    rect(0,0,50,50);
    pop();

    //middle row 
    fill(255,255,255,boxTrans);
    push();
    translate(width*.12,height/2);
    scale(1 + mouseY/80);
    rect(0,0,25,25);
    pop();
    push();
    translate(width*.30,height/2);
    scale(1 - mouseY/80);
    rect(0,0,25,25);
    pop();
    push();
    translate(width*.50,height/2);
    scale(1 + mouseY/80);
    rect(0,0,25,25);
    pop();
    push();
    translate(width*.70,height/2);
    scale(1 - mouseY/80);
    rect(0,0,25,25);
    pop();
    push();
    translate(width*.88,height/2);
    scale(1 + mouseY/80);
    rect(0,0,25,25);
    pop();
    //rect(width*.25,height/2,25,25);
    //rect(width*.47,height/2,25,25);
    //rect(width*.69,height/2,25,25);
    //rect(width*.86,height/2,25,25);



    //bottom row
    fill(boxColor);
    push();
    translate(width*.15,380);
    rotate(radians(mouseX));
    rect(0,0,50,50);
    pop();
    push();
    translate(width*.38,380);
    rotate(radians(-mouseX));
    rect(0,0,50,50);
    pop();
    push();
    translate(width*.62,380);
    rotate(radians(mouseX));
    rect(0,0,50,50);
    pop();
    push();
    translate(width*.85,380);
    rotate(radians(-mouseX));
    rect(0,0,50,50);
    pop();

}

For this project I focused on making the mouseX & mouseY interaction feel intuitive. As you move mouseX left to right, the boxes in the first and third row rotate alternatively based on the mouseX position. The shade of the boxes also get lighter as you increase mouseX. The transparency of the the smaller white boxes in the middle row also decrease as mouseX decreases. MouseY controls the scale of the middle boxes as well.

Diana Connolly – Final Project

For my final project, I created a simple computer game. Going into the assignment, I knew that I wanted to create a game in which you simply were flying and avoiding hitting cliffs above and below you. My game turned into a jetpacker game in which you are going deeper and deeper into a cave.

Please click on the canvas to be able to use the key commands. Press ‘S’ first to start the game and get everything moving. Then, you can use ‘J’ to ignite your jetpack, and to jump upwards. I recommend you hold down ‘J’ for longer strides instead of using short, jerky jump motions. Either way, try to stay alive as long as possible, measured by the seconds alive listed in the top left corner and the background cave color changing as you go deeper into the cave.

Jetpack Game

var topRocks = [];
var bottomRocks = [];
var count = 0; //will keep track of where on the noise curve we are
var jetPackY; //character's Y location, from top

var flameImg; //character image with flame
var noFlameImg; //character
var monsterImg; //flying monster character

var notPaused = false; //game is paused
var gameOver = false; //game is in play

var initialTime = 0; //time counter variables
var elapsed;
var timeAtDeath = 0;

var colR = 255; //initial background color
var colG = 161;
var colB = 105;

function preload() {
    flameImg = loadImage("http://dianaconnolly.me/assets/jetpacker!-01.png");
    noFlameImg = loadImage("http://dianaconnolly.me/assets/jetpackerNoFlame-01.png");
}

function setup() {
		monsterX = width + 1000;
		monsterY = height / 2 - 30;
    createCanvas(600, 400);
    frameRate(40);
    jetPackY = height / 2;
    // pushes in noise values into top and bottom rock arrays
    while (count < width + 1) {
        topRocks.push(height - noise(count * 0.01) * height / 3);
        bottomRocks.push(noise(width + count * 0.01) * height / 3);
        count++;
    }
}


function draw() {
    background(colR, colG, colB);

    drawBottomRocks();
    drawTopRocks();

    //prints time alive
    fill(255);
    textSize(15);
    textStyle(BOLD);
    textAlign(LEFT);
    textFont("Helvetica");
    if (!notPaused) {
        elapsed = 0;
    } else if (gameOver) {
        elapsed = timeAtDeath;
    } else {
        var elapsed = getElapsed();
    }
    text("Seconds alive: " + elapsed, 15, 25);

    //moving background and jetpacker
    if (notPaused & !gameOver) {
        timeAtDeath = getElapsed();
        updateScreen();
				monsterX -= 3;
        updateBackgroundColor(elapsed);
        println("lik");
        if (keyIsDown(74)) {
            jetPackY -= 5; //start moving jetPack w/ pressing "J"
        } else {
            jetPackY += 3; //jetPack falls otherwise
        }
    }

    //draw jetPack
    var jetPackX = width / 3;
    if (keyIsDown(74)) {
        image(flameImg, jetPackX, jetPackY, 30, 40);
    } else {
        image(noFlameImg, jetPackX, jetPackY, 30, 40);
    }

    if (!notPaused & !gameOver) { //starting page
        fill(0);
        textSize(20);
        textStyle(BOLD);
        textAlign(CENTER);
        textFont("Helvetica");
        text("Press 'S' to start game", width / 2, height / 2 - 10);
        text("Hold down 'J' to move up", width / 2, height / 2 + 50);
    }

    //checks for hitting bottom rocks
    var tallestBottomPoint = bottomRocks[jetPackX];
    for (var j = jetPackX; j < jetPackX + 30; j++) {
        tallestBottomPoint = max(bottomRocks[j], tallestBottomPoint);
    }
    if (jetPackY + 30 >= height - tallestBottomPoint) {
        gameOver = true;
        textAlign(CENTER);
        textSize(60);
        textFont("Helvetica");
        fill(255, 0, 0);
        text("GAME OVER", width / 2, height / 2);
        textSize(20);
        fill(0);
        text("Press 'R' to start again", width / 2, height / 2 + 40);
    }

    //checks for hitting top rocks
    var tallestTopPoint = height - topRocks[jetPackX];
    for (var k = jetPackX; k < jetPackX + 30; k++) {
        tallestTopPoint = max(height - topRocks[k], tallestTopPoint);
    }
    if (jetPackY + 10 <= tallestTopPoint) {
        gameOver = true;
        textAlign(CENTER);
        textSize(60);
        textFont("Helvetica");
        fill(255, 0, 0);
        text("GAME OVER", width / 2, height / 2);
        textSize(20);
        fill(0);
        text("Press 'R' to start again", width / 2, height / 2 + 40);
    }

    //restart game
    if (keyIsPressed) {
        if (key == 'r' || key == 'R') {
            jetPackY = height / 2;
            notPaused = false;
            gameOver = false;
        }
    }

}

function keyPressed() {
    // if you press S, start and reset start time
    if (key == 's' || key == 'S') {
        initialTime = getSecondsToday();
        notPaused = true;
    }
}



// ----------------------------------------------------------------------------------------
// FUNCTIONS CALLED FROM ABOVE

function drawBottomRocks() {
    beginShape();
    noStroke();
    fill(31, 19, 79);
    vertex(0, height);
    for (var i = 0; i < bottomRocks.length; i++) {
        vertex(i, height - bottomRocks[i]);
    }
    vertex(width, height);
    endShape(CLOSE);
}

function drawTopRocks() {
    beginShape();
    noStroke();
    fill(31, 19, 79);
    vertex(0, 0);
    for (var i = 0; i < topRocks.length; i++) {
        vertex(i, height - topRocks[i]);
    }
    vertex(width, 0);
    endShape(CLOSE);
}

function updateScreen() {
    //shifts over mountains based on noise plots
    for (var i = 0; i < 5; i++) {
        bottomRocks.shift();
        topRocks.shift();
        count++;
        topRocks.push(height - noise(count * 0.01) * height / 2);
        bottomRocks.push(noise(width + count * 0.01) * height / 2);
    }
}

function getSecondsToday() {
    // returns seconds since midnight today
    var h = hour();
    var m = minute();
    var s = second();
    return (s) + (m * 60) + (h * 60 * 60);
}

function getElapsed() {
    // responsible for returning seconds since game started
    return getSecondsToday() - initialTime;
}

function updateBackgroundColor(elapsed) {
    //shifts background color
    colR = map(elapsed, 0, 20, 255, 227);
    colG = map(elapsed, 0, 20, 161, 167);
    colB = map(elapsed, 0, 20, 105, 193);
}