ECE 2036 Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE

Revision:
2:2042f29de6b7
Parent:
0:cf4396614a79
--- a/main.cpp	Wed Nov 08 21:01:43 2017 +0000
+++ b/main.cpp	Thu Nov 21 16:10:57 2019 +0000
@@ -32,22 +32,38 @@
 #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
+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 (mosi, miso, sck, cs)
+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;
+const float bounce = 0.5;
+int sound = 1;
 
 /** Main() is where you start your implementation */
 int main()
@@ -55,6 +71,7 @@
     ////////////////////////////
     // Power-on initialization
     ////////////////////////////
+
     // Turn up the serial data rate so we don't lag
     uLCD.baudrate(3000000);
     pc.baud(115200);
@@ -68,28 +85,557 @@
 
     // 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.
-    while(1) 
-    {
-        // Initialze game state
-        DLinkedList* arena = create_blank_level();
+
+    // 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};
-        state.px = 64.0;        // Position in the center of the screen
-        state.py = 64.0;
-        state.vx = 0.0;         // Initially unmoving
+        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
-        run_game(arena, &state);
+        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);
+
+}
 
-        // Destory the arena and entities once we're done with the level
-        destroyList(arena);
+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. */
@@ -99,11 +645,11 @@
 
     // Initialize the walls
     Wall* walls[4];
-    walls[0] = create_wall(HORIZONTAL, 0, 0, 127, bounce);  // top
+    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]);
@@ -113,12 +659,12 @@
     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 
+
+    // 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;
 }
\ No newline at end of file