ECE 2036 Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE

main.cpp

Committer:
abraha2d
Date:
2019-11-21
Revision:
2:2042f29de6b7
Parent:
0:cf4396614a79

File content as of revision 2:2042f29de6b7:

/* Gatech ECE2035 2017 FALL MAZE RUNNER
* Copyright (c) 2017 Gatech ECE2035
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

// Include header files for platform
#include "mbed.h"

// Include header files for pacman project
#include "globals.h"
#include "math_extra.h"
#include "physics.h"
#include "game.h"
#include "wall.h"
#include "doublely_linked_list.h"

// Hardware initialization
DigitalIn left_pb(p21);     // push button
DigitalIn right_pb(p22);    // push button
DigitalIn up_pb(p23);       // push button
DigitalIn down_pb(p24);     // push button
uLCD_4DGL uLCD(p9,p10,p11); // LCD (serial tx, serial rx, reset pin;)
Serial pc(USBTX,USBRX);     // used by Accelerometer
MMA8452 acc(p28, p27, 100000);  // Accelerometer
//SDFileSystem sd(p5, p6, p7, p8, "sd");  // SD card and filesystem

DigitalOut redLED(p25);     // Red LED
DigitalOut greenLED(p26);   // Green LED
Speaker speaker(p18);       // Speaker

// Menu screen drawing functions
void do_main_menu();
void do_setup_menu();
void do_help_menu();
void do_level_start(int);
void do_level_complete(int, int);
void do_game_over();

// Level creation method declaration
DLinkedList* create_blank_level();
DLinkedList* create_level_1();
DLinkedList* create_level_2();
DLinkedList* create_level_3();

// Parameters. Declared in globals.h
const float mass = 0.001;
const int radius = 4;
const float bounce = 0.5;
int sound = 1;

/** Main() is where you start your implementation */
int main()
{
    ////////////////////////////
    // Power-on initialization
    ////////////////////////////

    // Turn up the serial data rate so we don't lag
    uLCD.baudrate(3000000);
    pc.baud(115200);

    // Initialize the buttons
    // Each *_pb variable is 0 when pressed
    left_pb.mode(PullUp);
    right_pb.mode(PullUp);
    up_pb.mode(PullUp);
    down_pb.mode(PullUp);

    // Other hardware initialization here (SD card, speaker, etc.)

    DLinkedList* levels = create_dlinkedlist();
    insertTail(levels, create_level_1());
    insertTail(levels, create_level_2());
    insertTail(levels, create_level_3());

    do_main_menu();

    ///////////////
    // Reset loop
    ///////////////
    // This is where control between major phases of the game happens
    // This is a good place to add choose levels, add the game menu, etc.

    // Start with the first level
    DLinkedList* arena = (DLinkedList*)getHead(levels);
    int level = 1;

    int gameOver = 0;
    while(gameOver == 0) {

        do_level_start(level);

        uLCD.cls();

        // (Re)Initialze game state
        Physics state = {0};
        int ix, iy;
        state.px = ix = ((Ball*)getTail(arena))->x;     // Initial position of ball
        state.py = iy = ((Ball*)getTail(arena))->y;
        state.vx = 0.0;         // Initial velocity of ball
        state.vy = 0.0;

        // Delegate to the game loop to execute the level
        // run_game() is in game.cpp
        int ret = run_game(arena, &state);

        // If we hit the goal, advance to the next level
        if (ret <= 30) {

            do_level_complete(level++, ret);

            // Destroy the arena and entities once we're done with the level
            destroyList(arena);

            // Get the next level
            arena = (DLinkedList*)getNext(levels);
            // If the next level is NULL, game over!
            if (arena == NULL) {
                gameOver = 1;
            }

        } else {

            if (ret == 32) {
                // Show help screen
                do_help_menu();
            } else {
                // Collision effect
                redLED = 1;
                for (int i = 4; i < 29; i++) {
                    redLED = !redLED;
                    int tone = (29 - i) * 5 + 100;
                    speaker.PlayNote(tone, 0.01, sound);
                    uLCD.circle(64, 64, i, RED);
                    uLCD.circle(64, 64, i - 1, 0xFFCC00);
                    uLCD.circle(64, 64, i - 2, WHITE);
                    uLCD.circle(64, 64, i - 3, 0);
                }
            }

            // If we hit a pothole, restart the level by redrawing all elements
            // and resetting the state
            ArenaElement* elem = (ArenaElement*)getHead(arena);
            do {
                switch(elem->type) {
                    case WALL:
                        // Redraw walls
                        ((Wall*)elem)->should_draw = 1;
                        break;
                    case BALL:
                        // Reset ball position
                        ((Ball*)elem)->x = ix;
                        ((Ball*)elem)->y = iy;
                        break;
                    case HOLE:
                        // Redraw holes
                        ((Hole*)elem)->should_draw = 1;
                        break;
                    case GOAL:
                        // Redraw goal
                        ((Goal*)elem)->should_draw = 1;
                        break;
                    default:
                        break;
                }
            } while(elem = (ArenaElement*)getNext(arena));

        }

    }

    do_game_over();

}

void do_main_menu()
{

    int cont = 1;
    while (cont) {

        uLCD.cls();
        uLCD.color(WHITE);
        uLCD.printf("\n\n");
        uLCD.printf("   Maze Runner!   ");
        uLCD.printf("\n\n");
        uLCD.printf("      Play        ");
        uLCD.printf("\n");
        uLCD.printf("      Setup       ");
        uLCD.printf("\n");
        uLCD.printf("      Help        ");
        uLCD.printf("\n\n");

        uLCD.rectangle(15, 34, 112, 51, WHITE);
        uLCD.rectangle(15, 51, 112, 67, WHITE);
        uLCD.rectangle(15, 67, 112, 84, WHITE);
        uLCD.rectangle(16, 35, 111, 51, WHITE);
        uLCD.rectangle(16, 51, 111, 67, WHITE);
        uLCD.rectangle(16, 67, 111, 83, WHITE);

        int offset = 35;
        uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);

        int rpb = right_pb;
        int upb = up_pb;
        int dpb = down_pb;
        int rpb2 = rpb;
        int upb2 = upb;
        int dpb2 = dpb;

        int cont2 = 1;
        while(cont2) {

            int crpb = right_pb;
            int cupb = up_pb;
            int cdpb = down_pb;

            if (!cupb && upb && upb2) {
                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, WHITE);
                if (offset > 35) {
                    offset -= 16;
                }
                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);
                speaker.PlayNote(100, 0.01, sound);
            }

            if (!cdpb && dpb && dpb2) {
                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, WHITE);
                if (offset < 67) {
                    offset += 16;
                }
                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);
                speaker.PlayNote(100, 0.01, sound);
            }

            if (!crpb && rpb && rpb2) {

                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, GREEN);
                speaker.PlayNote(100, 0.01, sound);
                wait(0.25);

                if (offset == 51) {
                    do_setup_menu();
                    cont2 = 0;
                } else if (offset == 67) {
                    do_help_menu();
                    cont2 = 0;
                } else {
                    cont = 0;
                    cont2 = 0;
                }

            }

            rpb2 = rpb;
            upb2 = upb;
            dpb2 = dpb;
            rpb = crpb;
            upb = cupb;
            dpb = cdpb;

        }

    }

}

void do_setup_menu()
{

    int cont = 1;
    while (cont) {

        uLCD.cls();
        uLCD.color(WHITE);
        uLCD.printf("\n\n");
        uLCD.printf("      Setup       ");
        uLCD.printf("\n\n");
        if (sound) {
            uLCD.printf("    Sound ON      ");
        } else {
            uLCD.printf("    Sound OFF     ");
        }

        int offset = 35;
        uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);

        int lpb = left_pb;
        int rpb = right_pb;

        int cont2 = 1;
        while(cont2) {

            int clpb = left_pb;
            int crpb = right_pb;

            if (!crpb && rpb) {
                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, GREEN);
                wait(0.25);
                if (sound == 1) {
                    sound = 0;
                } else {
                    sound = 1;
                }
                speaker.PlayNote(100, 0.01, sound);
                cont2 = 0;
            }

            if (!clpb && lpb) {
                speaker.PlayNote(100, 0.01, sound);
                cont = 0;
                cont2 = 0;
            }

            lpb = clpb;
            rpb = crpb;

        }

    }

}

void do_help_menu()
{
    uLCD.cls();
    uLCD.color(WHITE);
    uLCD.printf("\n\n");
    uLCD.printf("      Help        ");
    uLCD.printf("\n\n");

    uLCD.printf("Tilt the game to  ");
    uLCD.printf("get through the   ");
    uLCD.printf("maze to the ");
    uLCD.color(GREEN);
    uLCD.printf("green ");
    uLCD.color(WHITE);
    uLCD.printf("dot. Don't touch  ");
    uLCD.printf("the ");
    uLCD.color(RED);
    uLCD.printf("red");
    uLCD.color(WHITE);
    uLCD.printf(" dots!     ");
    uLCD.printf("\n");

    uLCD.color(BLUE);
    uLCD.printf("UP");
    uLCD.color(WHITE);
    uLCD.printf(" saves state.   ");
    uLCD.printf("\n");

    uLCD.color(BLUE);
    uLCD.printf("DOWN");
    uLCD.color(WHITE);
    uLCD.printf(" jumps to the ");
    uLCD.printf("last saved state. ");

    while(left_pb) {}

    speaker.PlayNote(100, 0.01, sound);

}

void do_level_start(int level)
{

    uLCD.cls();
    uLCD.color(WHITE);
    uLCD.printf("\n\n\n\n");
    uLCD.printf("     Level %d      ", level);
    uLCD.printf("\n\n\n");

    uLCD.rectangle(16, 19, 103, 51, WHITE);

    uLCD.printf("  ");
    for (int i = 3; i > 0; i--) {
        redLED = 1;
        uLCD.printf("%i... ", i);
        speaker.PlayNote(293.665, 0.25, sound);
        redLED = 0;
        wait(0.75);
    }
    greenLED = 1;
    uLCD.printf("\n\n       Go!");
    speaker.PlayNote(391.995, 0.75, sound);
    greenLED = 0;

}

void do_level_complete(int level, int time)
{

    uLCD.cls();
    uLCD.color(WHITE);
    uLCD.printf("\n\n\n\n");
    uLCD.printf("     Level %d      \n", level);
    uLCD.printf("    Complete!     ");
    uLCD.printf("\n\n\n");
    uLCD.printf("  Score:  %d/30   ", time);

    uLCD.rectangle(16, 19, 103, 67, WHITE);

    greenLED = 1;
    speaker.PlayNote(391.995, 0.12, sound);
    greenLED = 0;
    wait(0.12);
    greenLED = 1;
    speaker.PlayNote(493.883, 0.12, sound);
    speaker.PlayNote(587.330, 0.24, sound);
    greenLED = 0;
    wait(1);

}

void do_game_over()
{
    uLCD.cls();
    uLCD.color(WHITE);
    uLCD.printf("\n\n\n\n");
    uLCD.printf("    Game Over!    ");
    uLCD.printf("\n\n\n");

    uLCD.rectangle(16, 19, 103, 51, WHITE);

    uLCD.printf("  Press the blue  ");
    uLCD.printf("  button to play  ");
    uLCD.printf("      again!      ");



    greenLED = 1;
    speaker.PlayNote(587.330, 0.2, sound);
    greenLED = 0;
    wait(0.2);
    greenLED = 1;
    speaker.PlayNote(587.330, 0.1, sound);
    wait(0.1);
    greenLED = 0;
    speaker.PlayNote(587.330, 0.2, sound);
    greenLED = 1;
    speaker.PlayNote(493.883, 0.2, sound);
    greenLED = 0;
    speaker.PlayNote(587.330, 0.1, sound);
    wait(0.1);
    greenLED = 1;
    speaker.PlayNote(783.991, 0.5, sound);
    greenLED = 0;
}

/** Creates the first level. */
DLinkedList* create_level_1()
{
    DLinkedList* arena = create_dlinkedlist();

    // Initialize the walls
    Wall* walls[12];
    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
    walls[2] = create_wall(VERTICAL, 0, 2, 127, bounce);    // left
    walls[3] = create_wall(VERTICAL, 127, 2, 127, bounce);  // right
    walls[4] = create_wall(VERTICAL, 21, 21, 84, bounce);
    walls[5] = create_wall(VERTICAL, 42, 2, 42, bounce);
    walls[6] = create_wall(VERTICAL, 63, 21, 106, bounce);
    walls[7] = create_wall(VERTICAL, 84, 64, 32, bounce);
    walls[8] = create_wall(VERTICAL, 42, 84, 21, bounce);
    walls[9] = create_wall(HORIZONTAL, 21, 64, 42, bounce);
    walls[10] = create_wall(HORIZONTAL, 21, 105, 21, bounce);
    walls[11] = create_wall(HORIZONTAL, 84, 64, 43, bounce);

    // Add the walls to the arena
    for (int i = 0; i < 12; i++)
        insertTail(arena, (void*)walls[i]);

    // Initialize the goal
    Goal* goal = (Goal*) malloc(sizeof(Goal));
    goal->type = GOAL;
    goal->x = 95;
    goal->y = 80;
    goal->should_draw = 1;

    // Add goal to the arena
    insertTail(arena, (void*)goal);

    // Initialize the ball
    Ball* ball = (Ball*) malloc(sizeof(Ball));
    ball->type = BALL;
    ball->x = 31;
    ball->y = 95;

    // Add ball to the arena
    insertTail(arena, (void*)ball);

    return arena;
}

/** Creates the second level. */
DLinkedList* create_level_2()
{
    DLinkedList* arena = create_dlinkedlist();

    // Initialize the walls
    Wall* walls[15];
    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
    walls[2] = create_wall(VERTICAL, 0, 2, 127, bounce);    // left
    walls[3] = create_wall(VERTICAL, 127, 2, 127, bounce);  // right
    walls[4] = create_wall(VERTICAL, 64, 2, 21, bounce);
    walls[5] = create_wall(HORIZONTAL, 0, 21, 32, bounce);
    walls[6] = create_wall(VERTICAL, 32, 21, 43, bounce);
    walls[7] = create_wall(VERTICAL, 96, 21, 22, bounce);
    walls[8] = create_wall(HORIZONTAL, 64, 43, 63, bounce);
    walls[9] = create_wall(HORIZONTAL, 32, 64, 32, bounce);
    walls[10] = create_wall(HORIZONTAL, 64, 85, 32, bounce);
    walls[11] = create_wall(VERTICAL, 64, 85, 42, bounce);
    walls[12] = create_wall(HORIZONTAL, 0, 85, 32, bounce);
    walls[13] = create_wall(VERTICAL, 32, 85, 22, bounce);
    walls[14] = create_wall(HORIZONTAL, 96, 107, 31, bounce);

    // Add the walls to the arena
    for (int i = 0; i < 15; i++)
        insertTail(arena, (void*)walls[i]);

    // Initialize a hole
    Hole* hole = (Hole*) malloc(sizeof(Hole));
    hole->type = HOLE;
    hole->x = 96;
    hole->y = 64;
    hole->should_draw = 1;

    // Add hole to the arena
    insertTail(arena, (void*)hole);

    // Initialize the goal
    Goal* goal = (Goal*) malloc(sizeof(Goal));
    goal->type = GOAL;
    goal->x = 112;
    goal->y = 21;
    goal->should_draw = 1;

    // Add goal to the arena
    insertTail(arena, (void*)goal);

    // Initialize the ball
    Ball* ball = (Ball*) malloc(sizeof(Ball));
    ball->type = BALL;
    ball->x = 16;
    ball->y = 96;

    // Add ball to the arena
    insertTail(arena, (void*)ball);

    return arena;
}

/** Creates the third level. */
DLinkedList* create_level_3()
{
    DLinkedList* arena = create_dlinkedlist();

    // Initialize the walls
    Wall* walls[15];
    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
    walls[2] = create_wall(VERTICAL, 0, 2, 127, bounce);    // left
    walls[3] = create_wall(VERTICAL, 127, 2, 127, bounce);  // right
    walls[4] = create_wall(HORIZONTAL, 0, 18, 107, bounce);
    walls[5] = create_wall(VERTICAL, 107, 18, 92, bounce);
    walls[6] = create_wall(HORIZONTAL, 64, 110, 43, bounce);
    walls[7] = create_wall(HORIZONTAL, 43, 91, 42, bounce);
    walls[8] = create_wall(VERTICAL, 43, 91, 36, bounce);
    walls[9] = create_wall(HORIZONTAL, 0, 91, 21, bounce);
    walls[10] = create_wall(VERTICAL, 21, 73, 18, bounce);
    walls[11] = create_wall(HORIZONTAL, 21, 73, 64, bounce);
    walls[12] = create_wall(VERTICAL, 85, 37, 36, bounce);
    walls[13] = create_wall(HORIZONTAL, 21, 37, 64, bounce);
    walls[14] = create_wall(HORIZONTAL, 0, 55, 43, bounce);

    // Add the walls to the arena
    for (int i = 0; i < 15; i++)
        insertTail(arena, (void*)walls[i]);

    // Initialize a hole
    Hole* hole = (Hole*) malloc(sizeof(Hole));
    hole->type = HOLE;
    hole->x = 96;
    hole->y = 82;
    hole->should_draw = 1;

    // Add hole to the arena
    insertTail(arena, (void*)hole);

    // Initialize a hole
    Hole* hole2 = (Hole*) malloc(sizeof(Hole));
    hole2->type = HOLE;
    hole2->x = 64;
    hole2->y = 55;
    hole2->should_draw = 1;

    // Add hole to the arena
    insertTail(arena, (void*)hole2);

    // Initialize the goal
    Goal* goal = (Goal*) malloc(sizeof(Goal));
    goal->type = GOAL;
    goal->x = 11;
    goal->y = 82;
    goal->should_draw = 1;

    // Add goal to the arena
    insertTail(arena, (void*)goal);

    // Initialize the ball
    Ball* ball = (Ball*) malloc(sizeof(Ball));
    ball->type = BALL;
    ball->x = 21;
    ball->y = 110;

    // Add ball to the arena
    insertTail(arena, (void*)ball);

    return arena;
}

/** Creates a level with only bounding walls and a ball. */
DLinkedList* create_blank_level()
{
    DLinkedList* arena = create_dlinkedlist();

    // Initialize the walls
    Wall* walls[4];
    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
    walls[2] = create_wall(VERTICAL, 0, 0, 127, bounce);    // left
    walls[3] = create_wall(VERTICAL, 127, 0, 127, bounce);  // right

    // Add the walls to the arena
    for (int i = 0; i < 4; i++)
        insertTail(arena, (void*)walls[i]);

    // Initialize the ball
    Ball* ball = (Ball*) malloc(sizeof(Ball));
    ball->type = BALL;
    ball->x = 20;
    ball->y = 20;

    // Add ball to the arena
    // NOTE: The ball should always be last in the arena list, so that the other
    // ArenaElements have a chance to compute the Physics updates before the
    // ball applies forward euler method.
    insertTail(arena, (void*)ball);

    return arena;
}