Yiran Xuan – Final Project – Dueling Dragons

sketch

/*
Yiran Xuan
Section A
yxuan@andrew.cmu.edu
Final Project
*/

var redframes = []; // array for red dragon sprites
var blueframes = []; //array for blue dragon sprites

var beat; //sound variables
var impact;
var fire;
var growl;
var charge;
/*
status key:
0 = default
1 = attack
2 = shield
3 = reload
4 = impact
5 = shielded impact
6 = death (not real status)
*/

//---------------------------------------
function preload(){ //load all sprites into respective arrays
    //each sprite's index in array should match the status it represents
    //ex) the red dragon's default sprite should have index of zero
    /*
    redframes.push(loadImage("./DragonDefault.png"));  
    blueframes.push(loadImage("./DragonDefault2.png"));

    redframes.push(loadImage("./DragonAttack.png"));  
    blueframes.push(loadImage("./DragonAttack2.png"));

    redframes.push(loadImage("./DragonShield.png"));  
    blueframes.push(loadImage("./DragonShield2.png"));

    redframes.push(loadImage("./DragonReload.png"));  
    blueframes.push(loadImage("./DragonReload2.png"));

    redframes.push(loadImage("./DragonImpact.png"));  
    blueframes.push(loadImage("./DragonImpact2.png"));

    redframes.push(loadImage("./DragonShieldedImpact.png"));  
    blueframes.push(loadImage("./DragonShieldedImpact2.png"));

    redframes.push(loadImage("./DragonDeath.png"));  
    blueframes.push(loadImage("./DragonDeath2.png"));  

    beat = loadSound("rockyoubeat.wav"); //import sounds
    impact = loadSound("Strong_Punch.wav");
    fire = loadSound("Flame.wav");
    growl = loadSound("Growling Lion.wav");
    charge = loadSound("lasercharge.wav");
    */
    
    //default
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonDefault.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonDefault2.png")); 
    //attack
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonAttack.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonAttack2.png"));
    //shield
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonShield.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonShield2.png"));
    //reload
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonReload.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonReload2.png"));
    //impact
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonImpact.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonImpact2.png"));
    //shielded impact
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonShieldedImpact.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonShieldedImpact2.png"));
    //death
    redframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonDeath.png"));  
    blueframes.push(loadImage("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/DragonDeath2.png"));  

    beat = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/rockyoubeat.wav"); //import sounds
    impact = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/Strong_Punch.wav");
    fire = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/Flame.wav");
    growl = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/Growling-Lion.wav");
    charge = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/lasercharge.wav");
    

}

//--------------------------------------- Game Process functions

var RedDragon;
var BlueDragon;

var secondsbeforereload = 3;
var deadframecounter = 0; //after the endgame, counts number of frames before the game restarts

var cycle = 24; //number of frames in a cycle
var secondspercycle = 1; //how long one cycle
var framerate = cycle/secondspercycle;
var framecounter = 0; //counts frames to control the cycle


var actionwindow = cycle*2/3; //window for player input

function setup() {
    createCanvas(600, 400);
    imageMode(CENTER);
    
    textStyle(BOLD);
    textAlign(CENTER);
    frameRate(framerate);

    RedDragon = createDragon(3, 0, 1, redframes); //start with one health and no ammo
    BlueDragon = createDragon(3, 0, -1, blueframes);    

}

var redturn = true; //becomes false once a player has made move, ensures each player only makes one action per round
var blueturn = true;

function draw() {
    background('white');
    
    if(RedDragon.death || BlueDragon.death){ //if one dragon had died, just display default renders
        GameEnd();
    }

    else{
        if(framecounter < actionwindow){ //Stage 1: allowing player action input, displaying default renders
            fill('green');
            RedDragon.DefaultRender();
            BlueDragon.DefaultRender();
        }

        else if (framecounter == actionwindow){ //Stage 2: processing player actions
            fill('red');
            RedDragon.Action();
            BlueDragon.Action();
            RedDragon.opponentaction = BlueDragon.currentaction;
            BlueDragon.opponentaction = RedDragon.currentaction;
        }
        else if (framecounter < cycle*5/6){ //Stage 3: display player actions
            fill('red');
            RedDragon.ActionRender();
            BlueDragon.ActionRender();
        }
        else if (framecounter == cycle*5/6){ //Stage 4: process opponent actions and end result
            fill('red');
            RedDragon.Result();
            BlueDragon.Result();
        }
        else{ //Stage 5: display result of interaction
            fill('red');
            RedDragon.ResultRender();
            BlueDragon.ResultRender();
        }

        framecounter++; //framecounter is here music stops after end of the game
    }

    textSize(30);
    fill('green');
    text("Health: " + RedDragon.health, RedDragon.x, RedDragon.y - 75); //display current healths
    text("Health: " + BlueDragon.health, BlueDragon.x, BlueDragon.y - 75); 


    textSize(15);
    fill('red');
    text("J to attack, K to shield, L to reload", RedDragon.x, RedDragon.y - 125); //display current healths
    fill('blue');
    text("A to attack, S to shield, D to reload", BlueDragon.x, BlueDragon.y - 125);


    if (framecounter == cycle){ //when cycle is complete
        framecounter = 0;
        redturn = true; //allows players action again
        blueturn = true; 
        RedDragon.Reset(); //and reset round variables (currentmove, opponentmove, status) 
        BlueDragon.Reset();
        beat.play();//beat starts playing here
    }
}


//--------------------------------------- Event functions

function GameEnd(){
    
    RedDragon.DefaultRender(); //display the dragons; DefaultRender contains death render as well
    BlueDragon.DefaultRender();

    var winner = "Nobody"; //default is draw 
    if(RedDragon.health > BlueDragon.health){ //comparing health to determine victor
        winner = "Red Dragon";
    }
    if(RedDragon.health < BlueDragon.health){ 
        winner = "Blue Dragon";
    }

    fill('black');
    textSize(50);
    text(winner + " Wins!", width/2, 75); //writing victory text

    deadframecounter++; 
    if(deadframecounter == framerate*secondsbeforereload){ //reloads entire page after 3 seconds to restart game
        location.reload();
        }

}


function keyPressed(){
    if(key == 'a' || key == 's' || key == 'd'){ //is the pressed key a valid blue action?
        if(framecounter < actionwindow & blueturn){ //is it within the action window, and has blue made a move already?
            switch(key){
                case 'a':
                    BlueDragon.currentaction = 1; //A to fire
                    break;
                case 's':
                    BlueDragon.currentaction = 2; //S to shield
                    break;
                case 'd':
                    BlueDragon.currentaction = 3; //D to reload
                    break;
            }
            blueturn = false; //blue has spent its move
        }
    }

    if(key == 'j' || key == 'k' || key == 'l'){ //is the pressed key a valid red action?
        if(framecounter < actionwindow & redturn){ //is it within the action window, and has blue made a move already?
            switch(key){
                case 'j':
                    RedDragon.currentaction = 1; //A to fire
                    break;
                case 'k':
                    RedDragon.currentaction = 2; //S to shield
                    break;
                case 'l':
                    RedDragon.currentaction = 3; //D to reload
                    break;
            }
            redturn = false; //red has spent its move
        }
    }
}

//--------------------------------------- Dragon creation functions

function createDragon(startinghealth, startingammo, drdirection, drsprites) {
    var dragon = {
        
        health: startinghealth,
        death: 0,
        ammo: startingammo,
        shield: false,
        status: 0, 
        currentaction: 0, //action key: 0 = nonaction, 1 = shoot, 2 = shield, 3 = reload
        opponentaction: 0,

        direction: drdirection,
        sprites: drsprites,
        x: width/2 + drdirection*150, //where to render the sprite
        y: 225,

        Action: dragonAction, //processing gameplay
        Result: dragonResult,
        Reset: dragonReset,
        GameOver: isAlive,

        ActionRender: dragonActionRender,
        ResultRender: dragonResultRender,
        DefaultRender: dragonDefaultRender };
    return dragon;
}

/*
status key:
0 = default
1 = attack
2 = shield
3 = reload
4 = impact
5 = shielded impact
6 = death (not real status)
*/

function dragonAction(){ //function to process dragon's action
    switch(this.currentaction){ //processing currentaction
        case 0: //if no action
            break;

        case 1: //if attacking
            if(this.ammo == 0){ 
                this.currentaction = 0; //if attempted to attack without ammo, will change to no action
            }
            else{
                this.ammo--;
                fire.play();
            }
            break;

        case 2: //if shielding
            this.shield = true;
            break;

        case 3: //if reloading
            this.ammo++; //can reload indefinitely; reloads even if attacked
            charge.play();
            break;
    }

    this.ActionRender();
}


function dragonResult(){//function to process result of both dragon's actions
    this.status = this.currentaction; //by default, status is the same as action

    if(this.opponentaction == 1){ //unless attacked by other dragon
        if(this.shield){
            this.status = 5; //shield is up, attack is blocked
            impact.play();
        }
        else{
            this.status = 4;
            this.health--; //otherwise, attack hits, takes damage
            impact.play();
        }
    }
    this.GameOver();
    this.ResultRender();
}

function isAlive(){ //checks if dragon is alive or dead
    if (this.health < 1){
        this.death = 1;
        growl.play();
    }
    else this.death = 0;
}


function dragonActionRender(){ //function to display the dragon
    image(this.sprites[this.currentaction], this.x, this.y, 300, 225);
}

function dragonResultRender(){ //function to display the dragon
    image(this.sprites[this.status], this.x, this.y, 300, 225);
}

function dragonDefaultRender(){
    image(this.sprites[this.death*6], this.x, this.y, 300, 225); //renders either alive or dead state

}

function dragonReset(){ //resets the dragon actions and status to default at the end of the round
    this.currentaction = 0;
    this.status = 0;
    this.opponentaction = 0;
    this.shield = false;
}

(Using 1 Grace Day.)

(Recommend clicking the game to start it)

Dueling Dragons is the virtual, 1-computer-2-players version of the playground game “Shotgun”, in which players attempt to defeat their opponent by playing one of 3 moves (shoot, shield, reload) in accordance to a beat, usually clapping twice.

In my version, two dragons are fighting each other while “We Will Rock You”s stomp-stomp-clap plays; The final clap is starts a short time window in which both players can perform an action using the keys displayed.

Each player starts with 3 health and no ammo. Health is displayed, but ammo isn’t, for tactical reasons.

A player can make 4 moves:
0) no action (don’t press a key or press it out of the timing window); left vulnerable
1) attack; will expend an ammo only if there is any, otherwise will become no action
2) shield; protects the player from damage
3) reload; increases ammo by one, can increase indefinitely. A reload is still successful even if the player is damaged.

If both players are attacked, both of them will suffer damage

The game continues until at least one player’s health drops to zero, after which a win screen appears for 3 seconds, and then the page attempts to refresh (recommend manually refreshing the page)

Of course, there are sound effects!

Liz Maday Final Project

Liz Maday’s Virtual Instrument

emaday sketch copy

I am providing a zip file containing all the files involved in this project, available here: zip file .

There were too many files for the project to run adequately on word press. In order to run this program, the provided zip file must be downloaded, and a local server must be set up using either terminal in OSX or a command window in Windows. This would be accomplished by changing the directory to the file named Elizabeth Maday Final Project, and then typing in “python -m SimpleHTTPServer” or “python -m http.server”. Then the project can be viewed with the URL http://localhost:8000.

Sometimes this project seems to run better on Firefox than on Chrome.

This project was enjoyable to complete because it gave me an idea of what I might like to use p5 for in the future. I am interested in learning more about music technology and experimental methods of producing music, and I believe that p5 could be a great creative outlet.

Rani Randell Final Project

hi! welcome to my final project. please allow webcam access and sit in the center of your webcam for full effect. my project is a commentary on the artist John Baldessari. I have included a zip file below of my work as I am aware it may not run on WP. i will explain more and include photos of his work below:

sketch

/* Rani Randell
rrandell@andrew.cmu.edu
Section A
Final Project */

// please open in chrome and with your body centered in the middle of the webcam

var floatingText = 0
var cd = 80 //circle diameter for key pressed A
var myCamera;

function setup() {
    createCanvas(640, 480);
    myCamera = createCapture(VIDEO);
    myCamera.size(640, 480);
    myCamera.hide();  // attempt to size the camera. 
}

function draw() {

    image(myCamera, 0, 0); 
    myCamera.loadPixels(); 

    // scrolling instructions along bottom of screen
    noStroke();
    fill('yellow');
    rect(0, 400, 640, 200); //yellow bar with black scrolling writing
    textSize(40); 
    textStyle(BOLD);
    fill('black');
    textFont('Courier New');
    text('press keys a or b for a surprise', floatingText, 450);
    floatingText = floatingText + 1
    if (floatingText > 640) {
    floatingText = -750
    }

    noStroke();
    if (keyIsPressed) {

        if ((key == 'a') || (key == 'A')) { //primary colored circles
            fill('blue')
            ellipseMode(CENTER);
            ellipse(100, 100, cd, cd);
            ellipse(200, 200, cd, cd);
            ellipse(100, 200, cd, cd);
            ellipse(200, 300, cd, cd);
            ellipse(500, 100, cd, cd);
            ellipse(600, 200, cd, cd);
            ellipse(600, 300, cd, cd);
            ellipse(450, 300, cd, cd);
            ellipse(0, 0, cd, cd);
            ellipse(0, 200, cd, cd);
            ellipse(0, 300, cd, cd);
            ellipse(450, 0, cd, cd);
            ellipse(600, 0, cd, cd);
            ellipse(260, 0, cd, cd);
            ellipse(390, 0, cd, cd);
            ellipse(80, 0, cd, cd);
            ellipse(525, 260, cd, cd);
            ellipse(200, 60, cd, cd);
            ellipse(0, 150, cd, cd);

            fill('yellow');
            ellipse(0, 100, cd, cd);
            ellipse(250, 70, cd, cd);
            ellipse(200, 350, cd, cd);
            ellipse(570, 290, cd, cd);
            ellipse(480, 310, cd, cd);
            ellipse(300, 0, cd, cd);
            ellipse(640, 220, cd, cd);
            ellipse(250, 300, cd, cd);
            ellipse(0, 250, cd, cd);
            ellipse(640, 0, cd, cd);
            ellipse(210, 0, cd, cd);
            ellipse(150, 210, cd, cd);
            ellipse(470, 200, cd, cd);
            ellipse(140, 120, cd, cd);
            ellipse(600, 100, cd, cd);
            ellipse(570, 30, cd, cd);
            ellipse(120, 70, cd, cd);
            ellipse(100, 350, cd, cd);

            fill('red');
            ellipse(0, 200, cd, cd);
            ellipse(550, 330, cd, cd);
            ellipse(550, 170, cd, cd);
            ellipse(50, 170, cd, cd);
            ellipse(175, 190, cd, cd);
            ellipse(100, 300, cd, cd);
            ellipse(640, 100, cd, cd);
            ellipse(150, 0, cd, cd);
            ellipse(510, 0, cd, cd);
            ellipse(640, 290, cd, cd);
            ellipse(450, 0, cd, cd);
            ellipse(30, 77, cd, cd);
            ellipse(460, 240, cd, cd);
            ellipse(540, 50, cd, cd);
            ellipse(160, 80, cd, cd);
            ellipse(0, 350, cd, cd);
            ellipse(450, 95, cd, cd);
            ellipse(170, 280, cd, cd);

        }

        if ((key == 'b') || (key == 'B')) { //complementary colored circles
            fill('orange');
            ellipse(100, 100, cd, cd);
            ellipse(200, 200, cd, cd);
            ellipse(100, 200, cd, cd);
            ellipse(200, 300, cd, cd);
            ellipse(500, 100, cd, cd);
            ellipse(600, 200, cd, cd);
            ellipse(600, 300, cd, cd);
            ellipse(450, 300, cd, cd);
            ellipse(0, 0, cd, cd);
            ellipse(0, 200, cd, cd);
            ellipse(0, 300, cd, cd);
            ellipse(450, 0, cd, cd);
            ellipse(600, 0, cd, cd);
            ellipse(260, 0, cd, cd);
            ellipse(390, 0, cd, cd);
            ellipse(80, 0, cd, cd);
            ellipse(525, 260, cd, cd);
            ellipse(200, 60, cd, cd);
            ellipse(0, 150, cd, cd);

            fill('purple');
            ellipse(0, 100, cd, cd);
            ellipse(250, 70, cd, cd);
            ellipse(200, 350, cd, cd);
            ellipse(570, 290, cd, cd);
            ellipse(480, 310, cd, cd);
            ellipse(300, 0, cd, cd);
            ellipse(640, 220, cd, cd);
            ellipse(250, 300, cd, cd);
            ellipse(0, 250, cd, cd);
            ellipse(640, 0, cd, cd);
            ellipse(210, 0, cd, cd);
            ellipse(150, 210, cd, cd);
            ellipse(470, 200, cd, cd);
            ellipse(140, 120, cd, cd);
            ellipse(600, 100, cd, cd);
            ellipse(570, 30, cd, cd);
            ellipse(120, 70, cd, cd);
            ellipse(100, 350, cd, cd);
       

            fill('green');
            ellipse(0, 200, cd, cd);
            ellipse(550, 330, cd, cd);
            ellipse(550, 170, cd, cd);
            ellipse(50, 170, cd, cd);
            ellipse(175, 190, cd, cd);
            ellipse(100, 300, cd, cd);
            ellipse(640, 100, cd, cd);
            ellipse(150, 0, cd, cd);
            ellipse(510, 0, cd, cd);
            ellipse(640, 290, cd, cd);
            ellipse(450, 0, cd, cd);
            ellipse(30, 77, cd, cd);
            ellipse(460, 240, cd, cd);
            ellipse(540, 50, cd, cd);
            ellipse(160, 80, cd, cd);
            ellipse(0, 350, cd, cd);
            ellipse(450, 95, cd, cd);
            ellipse(170, 280, cd, cd);


        }

    }

}

below are some screen grabs of my working project, if for some reason the webcam isn’t working you can reference these! final 104 <- here is a zip file of my project as I am aware that it is not working on the WP.

John Baldessari is an artist who is most famous for his works where he took colored sticker dots and put them over the faces of people in photographs. This act is meant to be about erasure and obliteration. For my project I decided to flip that on its head and make it about erasing the background and focusing on the individuality. The duality of color (primary colors and their complement) are meant to emphasize individuality in humanity as wellBelow is a John Baldessari image to reference:

 

Kyle Leve Final Project


One image from the animation


Another image from the animation

Final Project-Kyle Leve

My project is an interactive art form where a tree is decorated with ornaments in time with music playing in the background. The song that is playing is “Carol of the Bells” by the Trans Siberian Orchestra. However, since I used multiple js files for this project WordPress would not run the whole project. So I have attached a zip file to run all the files. Download and unzip the zip file. Then to look at the code, look at all the different js files. To look at the project, open the index. As long as the index is running in a browser that allows audio, the file should play correctly. Once the index is loaded, all that needs to be done to start the animation is click the mouse on the screen and the music should start playing.

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.

Katherine Hua and Min Lee – Final Project

sketch

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

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

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

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

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

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

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

}

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

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

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

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

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

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


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

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

        }    
        pop();
    }
}

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

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

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

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

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

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

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

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

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

} 

Instructions:

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

Statements:

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

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

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

Jamie Dorst Final Project

sketch

/*
Jamie Dorst
jdorst@andrew.cmu.edu
Final Project
Section A
*/

// global variables
// weather
var weather;
var weatherUrl;
var temp;
var currentLocation;
var condition;
var city;
var rainConditions = ["Patchy light drizzle", "Light drizzle", "Freezing drizzle",
                      "Heavy freezing drizzle", "Patchy light rain", "Light rain",
                      "Moderate rain at times", "Moderate rain",
                      "Heavy rain at times", "Heavy rain", "Light freezing rain",
                      "Moderate or heavy freezing rain", "Light sleet",
                      "Moderate or heavy sleet", "Ice pellets", "Light rain shower",
                      "Torrential rain shower", "Light sleet showers",
                      "Moderate or heavy sleet showers", "Light showers of ice pellets",
                      "Moderate or heavy showers of ice pellets"];
var cloudyConditions = ["Cloudy", "Overcast", "Mist", "Patchy rain possible",
                        "Patchy snow possible", "Patchy sleet possible",
                        "Patchy freezing drizzle possible", "Thundery outbreaks possible",
                        "Fog", "Freezing fog"];
var snowyConditions = ["Blowing snow", "Blizzard", "Patchy light snow", "Light snow",
                       "Patchy moderate snow", "Moderate snow", "Patchy heavy snow", "Heavy snow"];
// custom variables
var button;
var cityInput;
var myFont;
// rain
var rainArray = [];
var rainAmount;
var rainSpeed;
var visibleR = false;
// snow
var snowflakeImg;
var snowArray = [];
var snowAmount;
var snowSpeed;
var visibleS = false;
// clouds
var cloudCover;
var cloudArray = [];
var cloudAmount;
var wind;
var rightWind = ["S", "SE", "E", "NE", "NNE", "ENE", "ESE", "SSE"];
var leftWind = ["N", "NW", "W", "SW", "SSW", "WSW", "WNW", "NNW"];


// preload weather API and snowflake image
function preload() {
    weatherUrl = 'https://api.apixu.com/v1/current.json?key=8f4b2cd0980d46aba2e201006182511&q=Pittsburgh';
    loadJSON(weatherUrl, getWeather);
    snowflakeImg = loadImage('https://i.imgur.com/VADyEQ9.png');
}

function setup() {
    createCanvas(480, 480);
    // case insensitive
    var lowCon = condition.toLowerCase();
    // make rain/snow relative to how heavy it is
    if (lowCon.indexOf('light') > -1) {
        rainAmount = 10;
        rainSpeed = 2;
        snowAmount = 10;
        snowSpeed = 1;
    } else if (lowCon.indexOf('moderate') > -1) {
        rainAmount = 15;
        rainSpeed = 3;
        snowAmount = 15;
        snowSpeed = 2;
    } else if (lowCon.indexOf('heavy') > -1) {
        rainAmount = 20;
        rainSpeed = 4;
        snowAmount = 20;
        snowSpeed = 3;
    } else {
        rainAmount = 30;
        rainSpeed = 5;
        snowAmount = 30;
        snowSpeed = 4;
    }
    // make amount of clouds relative to cloud cover
    cloudAmount = map(cloudCover, 0, 100, 0, 30);
    // prepare for rain/snow/clouds by filling array
    for (var i = 0; i < rainAmount; i++) {
        rainArray[i] = makeRain(random(170, 313), random(0, 315));
    }
    for (var i = 0; i < snowAmount; i++) {
        snowArray[i] = makeSnow(random(175, 305), random(0, 315));
    }
    for (var i = 0; i < cloudAmount; i++) {
        cloudArray[i] = makeCloud(random(-75, width + 75), random(320, height),
                                  random(100, 170), 175);
    }
    // let user name a city with input and button
    cityInput = createInput();
    cityInput.position(width - cityInput.width - 40, 20);
    button = createButton('GO');
    button.position(cityInput.x + cityInput.width + 5, 20);
    button.mouseClicked(changeCity);
}

// function to allow enter key to also submit input
async function keyPressed() {
    if (keyCode === ENTER) {
        changeCity();
    }
}

// function to change the weather to the user-inputted city
function changeCity() {
    // give variable a default
    city = 'Pittsburgh'
    // change city to inputted city
    city = cityInput.value();
    cityInput.value('');
    // reload weather data
    weatherUrl = 'https://api.apixu.com/v1/current.json?key=8f4b2cd0980d46aba2e201006182511&q=' + city;
    loadJSON(weatherUrl, getWeather);
}

async function cloudUpdate() {
    // make amount of clouds relative to cloud cover
        cloudAmount = map(cloudCover, 0, 100, 0, 30);
        // refill arrays so animations change
        for (var i = 0; i < rainAmount; i++) {
            rainArray[i] = makeRain(random(170, 313), random(0, 315));
        }
        for (var i = 0; i < snowAmount; i++) {
            snowArray[i] = makeSnow(random(175, 305), random(0, 315));
        }
        for (var i = 0; i < cloudAmount; i++) {
            cloudArray[i] = makeCloud(random(-75, width + 75), random(320, height),
                                      random(100, 170), 175);
        }
}

// get weather data
function getWeather(weather) {
    temp = Number(weather.current.temp_f);
    condition = weather.current.condition.text;
    currentLocation = weather.location.name;
    cloudCover = weather.current.cloud;
    wind = weather.current.wind_mph;
    windDir = weather.current.wind_dir;
    cloudUpdate();
}

async function draw() {
        // background is light during day, dark during night
        if (hour() > 8 & hour() < 18) {
            background("#0077CC");
        } else {
            background("#00487C");        
        }
        // font and size
        noStroke();
        textFont("Sans-serif");
        textAlign(CENTER);
        fill("EBF2FA");
        textSize(30);
        text(currentLocation, width / 2, 88);
        textSize(100);
        text(temp + "°", width / 2, 220);
        textSize(18);
        text(condition, width / 2, 120);
        textSize(12);
        text("Enter a city name or zip code to change location", 145, 28);
        // draw based on weather conditions
        if (condition === "Sunny") {
            sunny();
        } else if (condition === "Clear") {
            clearSky();
        } else if (condition === "Partly cloudy") {
            sunny();
            cloudy();
        } else if (rainConditions.some(weatherTest) == true) {
            rainy();
        } else if (cloudyConditions.some(weatherTest) == true) {
            cloudy();
        } else if (snowyConditions.some(weatherTest) == true) {
            snowy();
        } else if (condition === ("Patchy light rain with thunder") ||
                                 ("Moderate or heavy rain with thunder")) {
            rainy();
            thunder();
        } else if (condition === ("Patchy light snow with thunder") ||
                                 ("Moderate or heavy snow with thunder")) {
            snowy();
            thunder();
        }
}

// test weather conditions
function weatherTest(value) {
    return value == condition;
}
function directionTest(value) {
    return value == windDir;
}


//======================SUNNY=========================
function sunny() {
    // color of sun mapped to how hot it is
    // redder when hotter, yellower when cooler
    var sunColorG = map(temp, 0, 110, 230, 155);
    noStroke();
    fill(255, sunColorG, 0);
    // draw sun
    ellipse(width / 2, 350, 100, 100);
    // draw sun rays
    push();
    angleMode(DEGREES);
    translate(width / 2, 350);
    for (var i = 0; i < 10; i++) {
        fill ("orange");
        triangle(0, -80, -10, -60, 10, -60);
        rotate(36);
    }
    pop();
}

//======================CLEAR=========================
// function to draw moon
function clearSky() {
    noStroke();
    fill("#EBF2FA");
    ellipse(width / 2, 350, 150, 150);
    fill("#E3E9F2");
    ellipse(270, 330, 20, 20);
    ellipse(220, 360, 60, 60);
    ellipse(200, 300, 10, 10);
    ellipse(277, 400, 25, 25);
    ellipse(250, 291, 30, 30);
}


//=====================CLOUDY=========================
// function to make rain drop objects
function makeCloud(x, y, cloudColor) {
    var cloudObj = {
        x: x,
        y: y,
        cc: cloudColor,
        move: cloudMove,
        render: renderCloud
    };
    return cloudObj;
}

// function to draw clouds
function renderCloud() {
    noStroke();
    fill(this.cc);
    ellipse(this.x, this.y, 75, 75);
    ellipse(this.x + 60, this.y - 17, 100, 100);
    ellipse(this.x + 110, this.y + 5, 50, 50);
}

// function to make clouds move
// based on wind speed and direction
function cloudMove() {
    if (leftWind.some(directionTest) == true) {
        if (this.x > -160) {
            this.x -= map(wind, 0, 50, 0, 10);
        } else if (this.x <= -37.5) {
            this.x = width + 160;
        }
    } if (rightWind.some(directionTest) == true) {
        if (this.x < width + 37.5) {
            this.x += map(wind, 0, 50, 0, 10);
        } else if (this.x >= width + 37.5) {
            this.x = -160;
        }
    }
}

// weather condition function
function cloudy() {
    for (var i = 0; i < cloudAmount; i++) {
        cloudArray[i].render();
        cloudArray[i].move();
    }
}


//======================THUNDER=======================
// function to draw thunder
function thunder() {
    stroke("yellow");
    noFill();
    angleMode(DEGREES);
    arc(300, 320, 60, 60, 280, 0);
    arc(300, 320, 70, 70, 280, 0);
    arc(190, 315, 85, 85, 180, 285);
    arc(190, 315, 95, 95, 180, 285);
}


//======================RAIN==========================
// function to make rain drop objects
function makeRain(x, y) {
    var raindrop = {
        x: x,
        y: y,
        fall: rainFall,
        render: renderRain,
        visibleR: visibleR
    };
    return raindrop;
}

// function to draw rain
function renderRain() {
    noStroke();
    // only display raindrops when they are below the cloud
    if (this.visibleR == false) {
        ellipse(this.x, this.y, 0, 0);
    } else {
        ellipse(this.x, this.y, 7, 13);
    }
}

// function to make rain fall
function rainFall() {
    if (this.y < height) {
        this.y += rainSpeed
    } else if (this.y >= height) {
        this.y = random(300, 315);
    }
    if (this.y < 315) {
        this.visibleR = false;
    } else {
        this.visibleR = true;
    }
}

// weather condition function
function rainy() {
    // case insensitive
    var lowCon = condition.toLowerCase();
    // make rain relative to how heavy it is
    if (lowCon.indexOf('light') > -1) {
        rainAmount = 10;
        rainSpeed = 2;
    } else if (lowCon.indexOf('moderate') > -1) {
        rainAmount = 15;
        rainSpeed = 3;
    } else if (lowCon.indexOf('heavy') > -1) {
        rainAmount = 20;
        rainSpeed = 4;
    } else {
        rainAmount = 30;
        rainSpeed = 5;
    }
    // color of rain dependent upon temperature
    fill(0, map(temp, 32, 100, 255, 0), 255);
    for (var i = 0; i < rainAmount; i++) {
        rainArray[i].render();
        rainArray[i].fall();
    }
    var rainCloud = makeCloud(190, 315, 100);
    rainCloud.render();
}

//=======================SNOW=========================
// function to make snowflake objects
function makeSnow(x, y) {
    var snowflake = {
        x: x,
        y: y,
        fall: snowFall,
        render: renderSnow,
        visibleS: visibleS
    };
    return snowflake;
}

// function to draw snow
function renderSnow() {
    if (this.visibleS == false) {
        image(snowflakeImg, -5, -5, 1, 1);
    } else {
        image(snowflakeImg, this.x, this.y, 15, 15);
    }
}

// function to make snow fall
function snowFall() {
    if (this.y < height) {
        this.y += snowSpeed;
    } else if (this.y >= height) {
        this.y = 315;
    }
    if (this.y < 315) {
        this.visibleS = false;
    } else {
        this.visibleS = true;
    }
}

// weather condition function
function snowy() {
        // case insensitive
    var lowCon = condition.toLowerCase();
    // make snow relative to how heavy it is
    if (lowCon.indexOf('light') > -1) {
        snowAmount = 10;
        snowSpeed = 1;
    } else if (lowCon.indexOf('moderate') > -1) {
        snowAmount = 15;
        snowSpeed = 2;
    } else if (lowCon.indexOf('heavy') > -1) {
        snowAmount = 20;
        snowSpeed = 3;
    } else {
        snowAmount = 30;
        snowSpeed = 4;
    }
    fill(255);
    for (var i = 0; i < snowAmount; i++) {
        snowArray[i].render();
        snowArray[i].fall();
    }
    var snowCloud = makeCloud(190, 315, 100);
    snowCloud.render();
}

For my final project, I created a weather app. It defaults to Pittsburgh, but you can enter in any city or zip code you like and get the weather there. All of the animations are relative to some function of the weather such as the amount of rain, percent of cloud coverage, wind direction, and/or temperature. I learned a lot through making this project, from coming up with a plausible idea to figuring out how to get it to upload, and I’m happy with what I was able to produce.