Timothy Liu — Final Project

tcliu-FINALPROJECT

// Timothy Liu
// 15-104, Section C
// tcliu@andrew.cmu.edu
// FINAL PROJECT: Crossy Chicken, the game!

var showStart = true; // start off the game showing the start screen

var myChar; // the player (the chicken)
var charSpeed = 2; // speed player moves at

var borderW = 40; // border used in all popup screens

var firstCars = []; // arrays of cars (from bottom of screen to top)
var secondCars = [];
var thirdCars = [];
var fourthCars = [];

// road characteristics
var roadWidth = 100;
var roadLine = 2;
var carSpacing;

// river and bridge characteristics
var riverStart = 243; // identifies the top of the river
var riverWidth = 100; // identifies the width of the river
var riverEnd = riverStart + riverWidth; // identifies the bottom of the river
var bridgeWidth = 30; // width of the bridge
var bridgeMiddle = riverStart + riverWidth / 2; // the top part of the middle bridge segment
var randomBridgeStart; // where the first segment of the bridge starts 
var randomBridgeLength; // how long the middle segment of the bridge is

// variables that help draw/locate the egg and nest
var eggLocY = 50;
var eggW = 12;
var eggH = 16;
var nestLocY = 60;
var nestShadowY = 57;
var nestW = 30;
var nestH = 18;

// sound
var soundtrack;
var winSound;
var loseSound;

// preload all sounds
function preload() {

    // background track
    soundtrack = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/froggertrack.wav");
    soundtrack.setVolume(0.5);

    // losing jingle
    loseSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/lose.wav");
    loseSound.setVolume(0.6);

    // winning jingle
    winSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/win.wav");
    winSound.setVolume(0.9);

}

function setup() {

    createCanvas(600, 600); // create the canvas

    soundtrack.play(); // play the frogger soundtrack that's been preloaded

    myChar = makeCharacter(); // makes the character

    carSpacing = random(30, 45); // determines spacing between cars; ensures they don't hit each other (but varies the spacing randomly)
    
    randomBridgeStart = random(50, 500); // determines the random location of the bridge
    randomBridgeLength = random(60, 250); // determines the random length of the bridge

    firstCarSetup(); // defines properties for all the different rows of cars
    secondCarSetup(); // second row of cars (2nd from bottom)
    thirdCarSetup(); // third row of cars (3rd from bottom)
    fourthCarSetup(); // top row of cars

}

function draw() {

    background(87, 168, 84); // grass floor

    noStroke();

    drawFirstRoad(); // draw in the bottom road
    drawRiver(); // draw in the river
    drawSecondRoad(); // draw in the top road

    drawNest(); // draw in the nest

    // draw in and move the character!
    myChar.draw();
    myChar.move();

    // draws in the cars on the road using drawCars()
    showFirstCars();
    showSecondCars();
    showThirdCars();
    showFourthCars();

    characterWins(); // function that runs when the character reaches the egg and wins
    characterLoses(); // function that identifies when the character loses

    startScreen(); // starting screen shows right at the beginning

}

// the starting screen that shows rules and game info
function startScreen() {

    // right at start of game, this statement is true UNTIL SPACE IS PRESSED
    if (showStart === true) {

        noLoop();

        // the frame/popup screen
        fill(235, 131, 131);
        rect(width / 6, height / 6, width * 2 / 3, height * 2 / 3);

        fill(255);
        rect(width / 6 + borderW / 2, height / 6 + borderW / 2, width * 2 / 3 - borderW, height * 2 / 3 - borderW);

        // Start screen
        fill(0);
        textSize(20);

        textAlign(CENTER); // center the text
        textFont('Avenir'); // text font

        // starting screen text: the intro!
        textStyle(NORMAL);
        text("Welcome to Crossy Chicken!", width / 2, 225);
        text("Watch out for cars, and", width / 2, 255);
        text("don't let your feet get wet!", width / 2, 285);

        text("Use the WASD keys to move, and", width / 2, 345); 
        textStyle(BOLD);
        text("press SPACE to get started!", width / 2, 375);

    }

}

// triggers to start and reset the game
function keyPressed() {

    if (keyCode === 32) { // if SPACEBAR is pressed, let the game begin!
        showStart = false;
        loop();
    }
    if (keyCode === ENTER) { // if ENTER is pressed, the level restarts!
        restart(); // restart function resets the stage
    }

    return false; // prevents the webpage from moving when arrows are pressed

}

// this function initializes all variables and then reruns the setup function, effectively restarting the game
function restart() {

    firstCars = []; // initialize all of the car arrays so they can be redrawn/setup
    secondCars = [];
    thirdCars = [];
    fourthCars = [];

    setup(); // re-run setup, which resets the stage
    loop(); // start running the code again!

}

// define all character properties (the chicken)
function makeCharacter() {

    return {
        x: 300,
        y: 550,
        c: 255,
        w: 25,
        h: 40,
        r: 25,
        hX: 300,
        hY: 490,
        hW: 15,
        hH: 20,
        eyeC: 0,
        eyeW: 2,
        beakC: color(252, 202, 3),
        crownW: 5,
        crownH: 10,
        crownC: color(207, 58, 58),
        footW: 7,
        footH: 4,
        draw: drawCharacter,
        move: moveCharacter
    }

}

// uses the obj characteristics and var myChar to draw the chicken
function drawCharacter() {

    var headOffset = 18;
    var eyeOffsetX = 3;
    var eyeOffsetY = 21;
    var beakOffsetX = 4;
    var beakOffsetY = 19;
    var beakOffsetY2 = 15;
    var crownOffsetY = 27;
    var footOffset = 5;

    // red crown on head
    fill(myChar.crownC);
    arc(myChar.x, myChar.y - crownOffsetY, myChar.crownW, myChar.crownH, PI, TWO_PI);

    // feet
    fill(myChar.beakC);
    arc(myChar.x - footOffset, myChar.y, myChar.footW, myChar.footH, 0, PI);   
    arc(myChar.x + footOffset, myChar.y, myChar.footW, myChar.footH, 0, PI);  

    // head and body   
    fill(myChar.c);
    arc(myChar.x, myChar.y, myChar.w, myChar.h, PI, TWO_PI);
    arc(myChar.x, myChar.y - headOffset, myChar.hW, myChar.hH, PI, TWO_PI);

    // eyes
    fill(myChar.eyeC);
    ellipse(myChar.x - eyeOffsetX, myChar.y - eyeOffsetY, myChar.eyeW, myChar.eyeW);
    ellipse(myChar.x + eyeOffsetX, myChar.y - eyeOffsetY, myChar.eyeW, myChar.eyeW);

    // beak
    fill(myChar.beakC);
    triangle(myChar.x - beakOffsetX, myChar.y - beakOffsetY, myChar.x + beakOffsetX, myChar.y - beakOffsetY,
            myChar.x, myChar.y - beakOffsetY2);

}

// this function allows the character to move
function moveCharacter() {

    if (keyIsDown(65)) { // if pressing the A key
        myChar.x -= charSpeed; // move the character's x position left
        if (myChar.x + myChar.r < 0) { // if the character moves off the screen, have it wrap to the other side
            myChar.x = width + myChar.r;
        }
    }

    if (keyIsDown(68)) { // if pressing the D key 
        myChar.x += charSpeed; // move the character's x position right
        if (myChar.x - myChar.r > width) { // if the character moves off the screen, have it wrap to the other side
            myChar.x = -myChar.r;
        }
    }

    if (keyIsDown(87)) { // if pressing the W key
        myChar.y -= charSpeed; // move the character's y position up
    }

    if (keyIsDown(83)) { // if pressing the S key
        myChar.y += charSpeed; // move the character's y position down
        if (myChar.y + myChar.r > height) { // if it hits the bottom, don't let it go off the page
            myChar.y = height - myChar.r;
        }
    }

}

// what happens if the character reaches the egg
function characterWins() {

    // if the character reaches the egg successfully
    if (myChar.y > eggLocY - eggH / 2 & myChar.y < nestLocY + nestH / 2) {
        if (myChar.x > width / 2 - nestW / 2 && myChar.x < width / 2 + nestW / 2) {
            noLoop(); // game stops
            winningScreen(); // display winning screen
            winSound.play(); // play winning jingle!
        }
    }

}

// this function determines if the character loses using two other functions: hit by car, or fall in river
function characterLoses() {

    characterHitByCar(); // function if myChar is hit by a car
    characterFallsInRiver(); // function if myChar falls into the river

}

// if the character is hit by a car
function characterHitByCar() {

    // if char is hit by first row of cars
    for (var i = 0; i < firstCars.length; i++) {

        var carMiddleX = firstCars[i].x + (firstCars[i].w / 2);
        var carMiddleY = firstCars[i].y + (firstCars[i].h / 2);

        var charMiddleX = myChar.x;
        var charMiddleY = myChar.y - (myChar.h / 2);

        // if the edges of the character fall within the edges of the car, you lose!
        if (charMiddleX - myChar.w / 4 < carMiddleX + firstCars[i].w / 2 & charMiddleX + myChar.w / 4 > carMiddleX - firstCars[i].w / 2
            && myChar.y > carMiddleY - firstCars[i].h / 2 && charMiddleY - myChar.h / 5 < carMiddleY + firstCars[i].h / 2) {
            noLoop(); // game stops
            losingScreenCar(); // show losing screen
            loseSound.play(); // losing sound plays
        }

    }

    // if char is hit by second row of cars
    for (var j = 0; j < secondCars.length; j++) {

        var carMiddleX = secondCars[j].x + (secondCars[j].w / 2);
        var carMiddleY = secondCars[j].y + (secondCars[j].h / 2);

        var charMiddleX = myChar.x;
        var charMiddleY = myChar.y - (myChar.h / 2);

        // if the edges of the character fall within the edges of the car, you lose!
        if (charMiddleX - myChar.w / 4 < carMiddleX + secondCars[j].w / 2 & charMiddleX + myChar.w / 4 > carMiddleX - secondCars[j].w / 2
            && myChar.y > carMiddleY - secondCars[j].h / 2 && charMiddleY - myChar.h / 5 < carMiddleY + secondCars[j].h / 2) {
            noLoop(); // game stops
            losingScreenCar(); // show losing screen
            loseSound.play(); // losing sound plays
        }

    }

    // if char is hit by third row of cars
    for (var k = 0; k < thirdCars.length; k++) {

        var carMiddleX = thirdCars[k].x + (thirdCars[k].w / 2);
        var carMiddleY = thirdCars[k].y + (thirdCars[k].h / 2);

        var charMiddleX = myChar.x;
        var charMiddleY = myChar.y - (myChar.h / 2);

        // if the edges of the character fall within the edges of the car, you lose!
        if (charMiddleX - myChar.w / 4 < carMiddleX + thirdCars[k].w / 2 & charMiddleX + myChar.w / 4 > carMiddleX - thirdCars[k].w / 2
            && myChar.y > carMiddleY - thirdCars[k].h / 2 && charMiddleY - myChar.h / 5 < carMiddleY + thirdCars[k].h / 2) {
            noLoop(); // game stops
            losingScreenCar(); // show losing screen
            loseSound.play(); // losing sound plays
        }

    }

    // if char is hit by fourth row of cars
    for (var l = 0; l < fourthCars.length; l++) {

        var carMiddleX = fourthCars[l].x + (fourthCars[l].w / 2);
        var carMiddleY = fourthCars[l].y + (fourthCars[l].h / 2);

        var charMiddleX = myChar.x;
        var charMiddleY = myChar.y - (myChar.h / 2);

        // if the edges of the character fall within the edges of the car, you lose!
        if (charMiddleX - myChar.w / 4 < carMiddleX + fourthCars[l].w / 2 & charMiddleX + myChar.w / 4 > carMiddleX - fourthCars[l].w / 2
            && myChar.y > carMiddleY - fourthCars[l].h / 2 && charMiddleY - myChar.h / 5 < carMiddleY + fourthCars[l].h / 2) {
            noLoop(); // game stops
            losingScreenCar(); // show losing screen (car version)
            loseSound.play(); // losing sound plays
        }
    }

}

// if the strays from the bridge and falls into the river
function characterFallsInRiver() {

    // if the character is crossing the river...
    if (myChar.y > riverStart & myChar.y < riverEnd) {

        // first segment of the bridge (vertical)
        if (myChar.y > bridgeMiddle + bridgeWidth && myChar.y < riverEnd) {

            // if char is outside the bridge boundaries
            if (myChar.x < randomBridgeStart || myChar.x > randomBridgeStart + bridgeWidth) {
                noLoop(); // game stops
                losingScreenRiver(); // show losing screen (splash version)
                loseSound.play(); // play losing sound
            }
        }
        
        // the bridge randomly goes left or right based on starting position...
        // if the bridge goes rightward:
        if (randomBridgeStart < width / 2) {

            // second segment of the bridge (horizontal)
            if (myChar.y > bridgeMiddle & myChar.y < bridgeMiddle + bridgeWidth) {
                // if char is outside the boundaries of the horizontal bridge segment
                if (myChar.x < randomBridgeStart || myChar.x > randomBridgeStart + randomBridgeLength + bridgeWidth) {
                    noLoop(); // game stops
                    losingScreenRiver(); // show losing screen (splash version)
                    loseSound.play(); // play losing sound
                }
            }
        
            // last segment of the bridge (vertical)
            if (myChar.y > riverStart & myChar.y < bridgeMiddle) {
                if (myChar.x < randomBridgeStart + randomBridgeLength || myChar.x > randomBridgeStart + randomBridgeLength + bridgeWidth) {
                    noLoop(); // game stops
                    losingScreenRiver(); // show losing screen (splash version)
                    loseSound.play(); // play losing sound
                }
            }

        // if the bridge goes leftward:
        } else {

            // second segment of the bridge (horizontal)
            if (myChar.y > bridgeMiddle & myChar.y < bridgeMiddle + bridgeWidth) {
                if (myChar.x < randomBridgeStart - randomBridgeLength || myChar.x > randomBridgeStart + bridgeWidth) {
                    noLoop(); // game stops
                    losingScreenRiver(); // show losing screen (splash version)
                    loseSound.play(); // play losing sound
                }
            }

            // last segment of the bridge (vertical)
            if (myChar.y > riverStart & myChar.y < bridgeMiddle) {
                if (myChar.x < randomBridgeStart - randomBridgeLength || myChar.x > randomBridgeStart - randomBridgeLength + bridgeWidth) {
                    noLoop(); // game stops
                    losingScreenRiver(); // show losing screen (splash version)
                    loseSound.play(); // play losing sound
                }
            }
        }
    }
}

// the popup screen when you win
function winningScreen() {

	soundtrack.stop(); // stop background sound

    // border + screen
    fill(255, 213, 0);
    rect(width / 4, height / 4, width / 2, height / 2);

    fill(255);
    rect(width / 4 + borderW / 2, height / 4 + borderW / 2, width / 2 - borderW, height / 2 - borderW);

    // winning screen text for when you make it to the egg
    fill(0);
    textSize(20);
    textAlign(CENTER); // center the text
    textFont('Avenir'); // text font

    // text:
    textStyle(NORMAL);
    text("You protected your egg;", width / 2, 270);
    textStyle(BOLD);
    text("Congratulations!", width / 2, 300);
    textStyle(NORMAL);
    text("Hit ENTER to play again!", width / 2, 330);

}

// the popup screen when you're hit by a car
function losingScreenCar() {

    soundtrack.stop();

    fill(235, 131, 131);
    rect(width / 4, height / 4, width / 2, height / 2);

    fill(255);
    rect(width / 4 + borderW / 2, height / 4 + borderW / 2, width / 2 - borderW, height / 2 - borderW);

    // losing screen text for when a car runs into you
    fill(0);
    textSize(20);
    textAlign(CENTER); // center the text
    textFont('Avenir'); // text font

    // text:
    textStyle(NORMAL);
    text("Oh no, a car got you!", width / 2, 285);
    text("Hit ENTER to try again!", width / 2, 315);

}

// the popup screen when you fall into the river
function losingScreenRiver() {

    soundtrack.stop();

    fill(53, 99, 240);
    rect(width / 4, height / 4, width / 2, height / 2);

    fill(255);
    rect(width / 4 + borderW / 2, height / 4 + borderW / 2, width / 2 - borderW, height / 2 - borderW);

    // losing screen text for when you fall into the water
    fill(0);
    textSize(20);

    textAlign(CENTER); // center the text
    textFont('Avenir'); // text font

    // text:
    textStyle(BOLD); // bold the sound effect (splash)
    text("Splash...", width / 2, 270);
    textStyle(NORMAL);
    text("You fell into the water!", width / 2, 300);
    text("Hit ENTER to try again!", width / 2, 330);

}

// draw in the bottom (first) road
function drawFirstRoad() {

    var roadLocX = 0;
    var roadLocY = 385;
    var lineLocY = 434;

    fill(180);
    rect(roadLocX, roadLocY, width, roadWidth); // draws the road

    fill(245, 224, 66);
    rect(roadLocX, lineLocY, width, roadLine); // the dividing yellow line

}

// draw in the top (second) road
function drawSecondRoad() {

    var roadLocX = 0;
    var roadLocY = 100;
    var lineLocY = 149;

    fill(180);
    rect(roadLocX, roadLocY, width, roadWidth); // draws the road

    fill(245, 224, 66);
    rect(roadLocX, lineLocY, width, roadLine); // the dividing yellow line

}

// draw in the river
function drawRiver() {

    var riverEdgeL = 0;

	fill(100, 100, 255); // blue color
    rect(riverEdgeL, riverStart, width, riverWidth);

    drawBridge(); // draw in bridge using bridge function

}

// draws the bridge the crosses the river. the bridge is randomly generated each time the game is played!
// it will go rightward if the starting point is on the left of the screen, and leftward if the starting point is to the right
function drawBridge() {

    fill(186, 145, 104); // brown bridge color

    rect(randomBridgeStart, bridgeMiddle, bridgeWidth, riverWidth / 2); // first bridge segment
    
    // this if-else statement determines which direction the bridge goes in
    if (randomBridgeStart < width / 2) {
        rect(randomBridgeStart, bridgeMiddle, randomBridgeLength, bridgeWidth); // second bridge segment
        rect(randomBridgeStart + randomBridgeLength, riverStart, bridgeWidth, riverWidth / 2 + bridgeWidth); // final bridge segment
    } else {
        rect(randomBridgeStart - randomBridgeLength, bridgeMiddle, randomBridgeLength, bridgeWidth); // second bridge segment
        rect(randomBridgeStart - randomBridgeLength, riverStart, bridgeWidth, riverWidth / 2 + bridgeWidth); // final bridge segment
    }

}

// characteristics of the car objects
function makeCars(px, py) {
    return {
        x: px,
        y: py,
        c: color(random(255), random(255), random(255)),
        w: 50,
        h: 30,
        lightsW: 2,
        lightsH: 5,
        lightsC: color(242, 235, 19),
        tireW: 9,
        tireH: 3,
        tireC: color(0, 0, 0),
        windshieldW: 4,
        windshieldH: 25,
        windshieldC: color(100, 100, 100),
        draw: drawCars
    }
}

// uses the obj characteristics to draw cars
function drawCars() {

	var tireOffsetX = 6;
	var tireOffsetY = 2;
    var windshieldOffsetX = 10;
    var windshieldOffsetY = 2.5;

    // car body
    fill(this.c);
    rect(this.x, this.y, this.w, this.h);

    // car headlights (x4)
    fill(this.lightsC);
    rect(this.x + this.w - this.lightsW, this.y, this.lightsW, this.lightsH);
    rect(this.x + this.w - this.lightsW, this.y + this.h - this.lightsH, this.lightsW, this.lightsH);
    rect(this.x, this.y, this.lightsW, this.lightsH);
    rect(this.x, this.y + this.h - this.lightsH, this.lightsW, this.lightsH);

    // car tires
    fill(this.tireC);
    rect(this.x + this.w - (2.5 * tireOffsetX), this.y - tireOffsetY, this.tireW, this.tireH);
    rect(this.x + tireOffsetX, this.y - tireOffsetY, this.tireW, this.tireH);
    rect(this.x + this.w - (2.5 * tireOffsetX), this.y + this.h - (tireOffsetY / 2), this.tireW, this.tireH);
    rect(this.x + tireOffsetX, this.y + this.h - (tireOffsetY / 2), this.tireW, this.tireH);

    // car windshields
    fill(this.windshieldC);
    rect(this.x + (3.5 * windshieldOffsetX), this.y + windshieldOffsetY, this.windshieldW, this.windshieldH);
    rect(this.x + (1.2 * windshieldOffsetX), this.y + windshieldOffsetY, this.windshieldW, this.windshieldH);

    if (this.x > width) {
        this.x = -this.w;
    }

    if (this.x + this.w < 0) {
        this.x = width;
    }
}

// draws the nest using nest variables
function drawNest() {

    // the nest
    fill(219, 181, 75);
    ellipse(width / 2, nestLocY, nestW * 1.3, nestH);

    fill(163, 129, 34);
    ellipse(width / 2, nestShadowY, nestW, nestH / 2);
 
    // the egg
    fill(250, 242, 220);
    ellipse(width / 2, eggLocY, eggW, eggH);

}

// setting up the first row of cars and placing them (very bottom row of cars)
function firstCarSetup() { 

    var carPlacement; // car placement variable
    var numCars = 5; // number of cars in the first row of cars
    var carLocY = 445;

    var newCar = makeCars();
    firstCars.push(newCar); // add each new car to the empty array firstCars

    // place each car in the first row of cars and add to the array firstCars
    for (var i = 0; i < numCars; i++) {
        carPlacement = random((i * width / numCars) + carSpacing, ((i + 1) * width / numCars) - carSpacing);
        firstCars[i] = makeCars(carPlacement, carLocY); // placement of the first row of cars
    }

}

// setting up the second row of cars and placing them
function secondCarSetup() {

    var carPlacement; // car placement variable
    var numCars = 5; // number of cars in the first row of cars
    var carLocY = 395;

    var newCar = makeCars();
    secondCars.push(newCar); // add each new car to the empty array secondCars

    // place each car in the second row of cars and add to the array secondCars
    for (var i = 0; i < numCars; i++) {
        carPlacement = random((i * width / numCars) + carSpacing, ((i + 1) * width / numCars) - carSpacing);
        secondCars[i] = makeCars(carPlacement, carLocY);
    }

}

// setting up the third row of cars and placing them
function thirdCarSetup() {

    var carPlacement; // car placement variable
    var numCars = 5; // number of cars in the first row of cars
    var carLocY = 160;

    var newCar = makeCars();
    thirdCars.push(newCar); // add each new car to the empty array secondCars

    // place each car in the third row of cars and add to the array secondCars
    for (var i = 0; i < numCars; i++) {
        carPlacement = random((i * width / numCars) + carSpacing, ((i + 1) * width / numCars) - carSpacing);
        thirdCars[i] = makeCars(carPlacement, carLocY);
    }

}

// setting up the fourth row of cars and placing them
function fourthCarSetup() {

    var carPlacement; // car placement variable
    var numCars = 5; // number of cars in the first row of cars
    var carLocY = 110;

    var newCar = makeCars();
    fourthCars.push(newCar); // add each new car to the empty array secondCars

    // place each car in the fourth row of cars and add to the array secondCars
    for (var i = 0; i < numCars; i++) {
        carPlacement = random((i * width / numCars) + carSpacing, ((i + 1) * width / numCars) - carSpacing);
        fourthCars[i] = makeCars(carPlacement, carLocY);
    }

}

// draws the first row of cars (closest to the bottom of the screen)
function showFirstCars() {

    for (var i = 0; i < firstCars.length; i++) {
        firstCars[i].draw(); // draws in cars
        firstCars[i].x += 1; // makes the cars drive rightward on the first road (bottom)
    }

}

// draws the second row of cars (next row up from bottom of the screen)
function showSecondCars() {

    for (var i = 0; i < secondCars.length; i++) {
        secondCars[i].draw();
        secondCars[i].x -= 1; // makes the cars move in the opposite direction (leftward) on the first road
    }

}

// draws the third row of cars (next row up from bottom of the screen)
function showThirdCars() {

    for (var i = 0; i < thirdCars.length; i++) {
        thirdCars[i].draw();
        thirdCars[i].x += 1.8; // faster cars to increase the difficulty (rightward, top road)!
    }

}

// draws the fourth row of cars (row of cars near top of screen)
function showFourthCars() {

    for (var i = 0; i < fourthCars.length; i++) {
        fourthCars[i].draw();
        fourthCars[i].x -= 1.8; // faster cars in opposite direction to increase the difficulty (leftward, top road)!
    }

}

Welcome to Crossy Chicken, my final project for 15-104! A tribute to the original Frogger, Crossy Chicken involves a chicken trying to reach her beloved egg. But to get there, the chicken must first cross two busy streets as well as a perilous bridge; can you get her back to her egg?

To play, use the WASD keys (W = Up, S = Down, A = Left, D = Right) to direct the chicken and follow the instructions on screen! Make sure you dodge all the cars and don’t let the chicken’s feet touch the water!

I had a fantastic time coding this project, and I’m proud of how I distributed the work. I broke my project down into phases, and I worked through them in the following order:

  1. Character movement
  2. Introducing cars
  3. Adding roads
  4. Creating the river and bridge
  5. Adding the next 3 rows of cars
  6. Losing screen
  7. Winning screen
  8. Reset button (ENTER)
  9. Start button (SPACE)
  10. Adding sounds

In the end, I wound up with what I felt was a very polished and complete game. I’m really happy that I was able to build a visually pleasing game with fun and retro graphics while using a multitude of elements from p5js. From objects, to loops, to sound, my game really has a bit of everything in it. The soundtrack (which is actually the original Frogger music!) adds an element of excitement and nostalgia, and the losing and winning sound effects complete the experience for the gamer. I hope you have a great time playing!

(*Note 2: as is typically the case with p5js, the sound is sometimes a bit glitchy on Chrome and certain other browsers. However, the implementation of sound is all correct, as can be seen in my code.)

Leave a Reply