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.

Leave a Reply