ECE 2036 Project
Dependencies: mbed wave_player 4DGL-uLCD-SE
Diff: main.cpp
- 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