ECE 2036 Project
Dependencies: mbed wave_player 4DGL-uLCD-SE
Revision 2:2042f29de6b7, committed 2019-11-21
- Comitter:
- abraha2d
- Date:
- Thu Nov 21 16:10:57 2019 +0000
- Parent:
- 1:c18c231cb299
- Commit message:
- Because other peeps is wanting dis...
Changed in this revision
diff -r c18c231cb299 -r 2042f29de6b7 Speaker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Speaker.h Thu Nov 21 16:10:57 2019 +0000 @@ -0,0 +1,52 @@ +class Speaker +{ +public: + Speaker(PinName pin) : _pin(pin) { +// _pin(pin) means pass pin to the Speaker Constructor +// precompute 32 sample points on one sine wave cycle +// used for continuous sine wave output later + for(int k=0; k<32; k++) { + Analog_out_data[k] = int (65536.0 * ((1.0 + sin((float(k)/32.0*6.28318530717959)))/2.0)); + // scale the sine wave to 16-bits - as needed for AnalogOut write_u16 arg + } + + } +// class method to play a note based on AnalogOut class + void PlayNote(float frequency, float duration, float volume) { + // scale samples using current volume level arg + for(int k=0; k<32; k++) { + Analog_scaled_data[k] = Analog_out_data[k] * volume; + } + // reset to start of sample array + i=0; + // turn on timer interrupts to start sine wave output + Sample_Period.attach(this, &Speaker::Sample_timer_interrupt, 1.0/(frequency*32.0)); + // play note for specified time + wait(duration); + // turns off timer interrupts + Sample_Period.detach(); + // sets output to mid range - analog zero + this->_pin.write_u16(32768); + + } +private: +// sets up specified pin for analog using AnalogOut class + AnalogOut _pin; + // set up a timer to be used for sample rate interrupts + Ticker Sample_Period; + + //variables used by interrupt routine and PlayNote + volatile int i; + short unsigned Analog_out_data[32]; + short unsigned Analog_scaled_data[32]; + +// Interrupt routine +// used to output next analog sample whenever a timer interrupt occurs + void Sample_timer_interrupt(void) { + // send next analog sample out to D to A + this->_pin.write_u16(Analog_scaled_data[i]); + // increment pointer and wrap around back to 0 at 32 + i = (i+1) & 0x01F; + } +}; +
diff -r c18c231cb299 -r 2042f29de6b7 doublely_linked_list.cpp --- a/doublely_linked_list.cpp Wed Nov 08 21:01:43 2017 +0000 +++ b/doublely_linked_list.cpp Thu Nov 21 16:10:57 2019 +0000 @@ -2,147 +2,396 @@ #include <stdio.h> #include "doublely_linked_list.h" -DLinkedList* create_dlinkedlist(void) { - DLinkedList* newList = (DLinkedList*)malloc(sizeof(DLinkedList)); +DLinkedList* create_dlinkedlist(void) +{ + +// printf("create_dlinkedlist\n"); + + DLinkedList* newList = (DLinkedList*) malloc(sizeof(DLinkedList)); + + newList->size = 0; newList->head = NULL; + newList->current = NULL; newList->tail = NULL; - newList->current = NULL; - newList->size = 0; + return newList; + } -LLNode* create_llnode(void* data) { +LLNode* create_llnode(void* data) +{ + +// printf("create_llnode\n"); + + LLNode* newNode = (LLNode*) malloc(sizeof(LLNode)); + + newNode->previous = NULL; + newNode->next = NULL; + newNode->data = data; + + return newNode; + +} + + +void insertHead(DLinkedList* dLinkedList, void* data) +{ - // Your code here - return NULL; +// printf("insertHead\n"); + + LLNode* newNode = create_llnode(data); + + if (dLinkedList->head == NULL) { + + dLinkedList->size++; + dLinkedList->head = newNode; + dLinkedList->tail = newNode; + + } else { + + dLinkedList->size++; + newNode->next = dLinkedList->head; + (dLinkedList->head)->previous = newNode; + dLinkedList->head = newNode; + + } } -void insertHead(DLinkedList* dLinkedList, void* data){ - LLNode* newNode = create_llnode(data); - if(dLinkedList->head == NULL){ - dLinkedList->size++; - dLinkedList->head = newNode; - dLinkedList->tail = newNode; - }else{ - dLinkedList->size++; - newNode->next = dLinkedList->head; - (dLinkedList->head)->previous = newNode; - dLinkedList->head = newNode; - } -} +void insertTail(DLinkedList* dLinkedList, void* data) +{ + +// printf("insertTail\n"); + + LLNode* newNode = create_llnode(data); + + if (dLinkedList->tail == NULL) { + dLinkedList->size++; + dLinkedList->tail = newNode; + dLinkedList->head = newNode; -void insertTail(DLinkedList* dLinkedList, void* data){ + } else { - // Your code here + dLinkedList->size++; + newNode->previous = dLinkedList->tail; + (dLinkedList->tail)->next = newNode; + dLinkedList->tail = newNode; + + } } -int insertAfter(DLinkedList* dLinkedList, void* newData){ +int insertAfter(DLinkedList* dLinkedList, void* newData) +{ + +// printf("insertAfter\n"); + + if (dLinkedList->current == NULL) { + return 0; + } + + LLNode* newNode = create_llnode(newData); - // Your code here - return 0; + dLinkedList->size++; + newNode->next = (dLinkedList->current)->next; + newNode->previous = dLinkedList->current; + if (newNode->next == NULL) { + dLinkedList->tail = newNode; + } else { + (newNode->next)->previous = newNode; + } + (newNode->previous)->next = newNode; + + return 1; } -int insertBefore(DLinkedList* dLinkedList, void* newData){ +int insertBefore(DLinkedList* dLinkedList, void* newData) +{ + +// printf("insertBefore\n"); + + if (dLinkedList->current == NULL) { + return 0; + } + + LLNode* newNode = create_llnode(newData); - // Your code here - return 0; + dLinkedList->size++; + newNode->next = dLinkedList->current; + newNode->previous = (dLinkedList->current)->previous; + (newNode->next)->previous = newNode; + if (newNode->previous == NULL) { + dLinkedList->head = newNode; + } else { + (newNode->previous)->next = newNode; + } + + return 1; } -void* deleteBackward(DLinkedList* dLinkedList){ +void* deleteBackward(DLinkedList* dLinkedList) +{ + +// printf("deleteBackward\n"); + + if (dLinkedList->current == NULL) { + return NULL; + } + + dLinkedList->size--; + + free((dLinkedList->current)->data); - //Your code here. - return NULL; + if ((dLinkedList->current)->previous == NULL) { + dLinkedList->head = (dLinkedList->current)->next; + } else { + ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next; + } + + if ((dLinkedList->current)->next == NULL) { + dLinkedList->tail = (dLinkedList->current)->previous; + } else { + ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous; + } + + LLNode* newCurrent = (dLinkedList->current)->previous; + + free(dLinkedList->current); + dLinkedList->current = newCurrent; + + if (dLinkedList->current == NULL) { + return NULL; + } + + return (dLinkedList->current)->data; } -void* deleteForward(DLinkedList* dLinkedList){ +void* deleteForward(DLinkedList* dLinkedList) +{ + +// printf("deleteForward\n"); + + if (dLinkedList->current == NULL) { + return NULL; + } + + dLinkedList->size--; + + free((dLinkedList->current)->data); - //Your code here. - return NULL; + if ((dLinkedList->current)->previous == NULL) { + dLinkedList->head = (dLinkedList->current)->next; + } else { + ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next; + } + + if ((dLinkedList->current)->next == NULL) { + dLinkedList->tail = (dLinkedList->current)->previous; + } else { + ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous; + } + + LLNode* newCurrent = (dLinkedList->current)->next; + + free(dLinkedList->current); + dLinkedList->current = newCurrent; + + if (dLinkedList->current == NULL) { + return NULL; + } + + return (dLinkedList->current)->data; } -void* removeBackward(DLinkedList* dLinkedList){ +void* removeBackward(DLinkedList* dLinkedList) +{ + +// printf("removeBackward\n"); + + if (dLinkedList->current == NULL) { + return NULL; + } + + dLinkedList->size--; - //Your code here. - return NULL; + if ((dLinkedList->current)->previous == NULL) { + dLinkedList->head = (dLinkedList->current)->next; + } else { + ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next; + } + + if ((dLinkedList->current)->next == NULL) { + dLinkedList->tail = (dLinkedList->current)->previous; + } else { + ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous; + } + + void* oldData = (dLinkedList->current)->data; + + LLNode* newCurrent = (dLinkedList->current)->previous; + + free(dLinkedList->current); + dLinkedList->current = newCurrent; + + return oldData; } -void* removeForward(DLinkedList* dLinkedList){ +void* removeForward(DLinkedList* dLinkedList) +{ + +// printf("removeForward\n"); + + if (dLinkedList->current == NULL) { + return NULL; + } + + dLinkedList->size--; - //Your code here. - return NULL; + if ((dLinkedList->current)->previous == NULL) { + dLinkedList->head = (dLinkedList->current)->next; + } else { + ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next; + } + + if ((dLinkedList->current)->next == NULL) { + dLinkedList->tail = (dLinkedList->current)->previous; + } else { + ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous; + } + + void* oldData = (dLinkedList->current)->data; + + LLNode* newCurrent = (dLinkedList->current)->next; + + free(dLinkedList->current); + dLinkedList->current = newCurrent; + + return oldData; } -void destroyList(DLinkedList* dLinkedList){ - if(dLinkedList->head != NULL){ - getHead(dLinkedList); - while(deleteForward(dLinkedList)){}; - } - free(dLinkedList); +void destroyList(DLinkedList* dLinkedList) +{ + +// printf("destroyList\n"); + + if (dLinkedList->head != NULL) { + getHead(dLinkedList); + while(deleteForward(dLinkedList)) {}; + } + + free(dLinkedList); + } -void* getHead(DLinkedList* dLinkedList){ +void* getHead(DLinkedList* dLinkedList) +{ + +// printf("getHead\n"); - //Your code here. - return NULL; + dLinkedList->current = dLinkedList->head; + + if (dLinkedList->head == NULL) { + return NULL; + } + + return (dLinkedList->head)->data; } -void* getTail(DLinkedList* dLinkedList){ +void* getTail(DLinkedList* dLinkedList) +{ + +// printf("getTail\n"); + + dLinkedList->current = dLinkedList->tail; - //Your code here. + if (dLinkedList->tail == NULL) { + return NULL; + } - return NULL; + return (dLinkedList->tail)->data; + } -void* getCurrent(DLinkedList* dLinkedList){ +void* getCurrent(DLinkedList* dLinkedList) +{ + +// printf("getCurrent\n"); - //Your code here. - return NULL; + if (dLinkedList->current == NULL) { + return NULL; + } + + return (dLinkedList->current)->data; } -void* getNext(DLinkedList* dLinkedList){ +void* getNext(DLinkedList* dLinkedList) +{ + +// printf("getNext\n"); + + if (dLinkedList->current == NULL) { + return NULL; + } - //Your code here. + dLinkedList->current = (dLinkedList->current)->next; - return NULL; + if (dLinkedList->current == NULL) { + return NULL; + } + + return (dLinkedList->current)->data; + } -void* getPrevious(DLinkedList* dLinkedList){ +void* getPrevious(DLinkedList* dLinkedList) +{ + +// printf("getPrevious\n"); + + if (dLinkedList->current == NULL) { + return NULL; + } - //Your code here. + dLinkedList->current = (dLinkedList->current)->previous; - return NULL; + if (dLinkedList->current == NULL) { + return NULL; + } + + return (dLinkedList->current)->data; + } -int getSize(DLinkedList* dLinkedList){ +int getSize(DLinkedList* dLinkedList) +{ - //Your code here. - return 0; +// printf("getSize\n"); + + return dLinkedList->size; } \ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 game.cpp --- a/game.cpp Wed Nov 08 21:01:43 2017 +0000 +++ b/game.cpp Thu Nov 21 16:10:57 2019 +0000 @@ -8,14 +8,64 @@ /** Erases the ball from the screen by drawing over it with the background color. */ void erase_ball(Ball* ball) { - // TODO: Draw background color over curriously drawn ball location + // Draw background color over previously drawn ball location + uLCD.filled_circle(ball->x, ball->y, radius, BLACK); } /** Draws the ball on the screen at the updated location (according to the state) */ void draw_ball(Ball* ball, Physics* state) { - // TODO: Save that updated ball position for later erasing - // TODO: Draw ball in its updated location + // Draw ball in its updated location + uLCD.filled_circle(state->px, state->py, radius, WHITE); + // Save that updated ball position for later erasing + ball->x = state->px; + ball->y = state->py; +} + +/** Draws a hole on the screen */ +void draw_hole(Hole* hole) +{ + if (hole->should_draw) { + // Draw hole in its location + uLCD.filled_circle(hole->x, hole->y, radius - 1, RED); + hole->should_draw = 0; + } +} + +/** Checks whether the ball has hit a hole */ +int do_hole(Hole* hole, Physics* curr) +{ + double dist = sqrt(pow(curr->px - hole->x, 2) + pow(curr->py - hole->y, 2)); + if (dist < radius * 2) { + hole->should_draw = 1; + } + if (dist < radius) { + return 2; + } + return 0; +} + +/** Draws the goal on the screen */ +void draw_goal(Goal* goal) +{ + if (goal->should_draw) { + // Draw goal in its location + uLCD.filled_circle(goal->x, goal->y, radius + 1, GREEN); + goal->should_draw = 0; + } +} + +/** Checks whether the ball has hit the goal */ +int do_goal(Goal* goal, Physics* curr) +{ + double dist = sqrt(pow(curr->px - goal->x, 2) + pow(curr->py - goal->y, 2)); + if (dist < radius * 2) { + goal->should_draw = 1; + } + if (dist < radius) { + return 1; + } + return 0; } /** Reads inputs to the game, such as accelerometer and buttons */ @@ -23,22 +73,65 @@ { GameInputs inputs = {0}; - // TODO: Get acceleration vector from accelerometer - // TODO: Read buttons + // Get acceleration vector from accelerometer + acc.readXYZGravity(&inputs.ax, &inputs.ay, &inputs.az); return inputs; } -int update_game(DLinkedList* arena, Physics* curr, GameInputs inputs, float delta) +int lrpb = left_pb || right_pb; +int lpb = 1; +int upb = up_pb; +int dpb = down_pb; + +int update_game(DLinkedList* arena, Physics* curr, GameInputs inputs, DLinkedList* checkpoints, float delta) { + + // Cheat codes! + if (left_pb == 0 && right_pb == 0 && lrpb == 1) { + lpb = 1; + uLCD.cls(); + uLCD.printf("\n\n\n\n Cheat code!"); + wait(0.5); + return 30; + } + + // Help! + if (left_pb == 1 && lpb == 0) { + lpb = 1; + return 32; + } + + // Save/restore state + if (up_pb == 0 && upb == 1) { + greenLED = 1; + Physics* saveState = (Physics*) malloc(sizeof(Physics)); + *saveState = *curr; + insertTail(checkpoints, saveState); + } + if (down_pb == 0 && dpb == 1) { + Physics* restoreState = (Physics*) getTail(checkpoints); + if (restoreState != NULL) { + *curr = *restoreState; + } + } + + // Save previous inputs + lrpb = left_pb || right_pb; + lpb = left_pb; + upb = up_pb; + dpb = down_pb; + /////////////////////////////// // Prepare for physics update /////////////////////////////// // Make a copy of the current state for modification Physics next = *curr; + // No acceleration unless the ArenaElements apply them. (Newton's 1st law) next.ax = next.ay = 0.0; + // Loop over all arena elements ArenaElement* elem = (ArenaElement*)getHead(arena); do { @@ -47,8 +140,20 @@ do_wall(&next, curr, (Wall*) elem, delta); break; case BALL: + next.ax += inputs.ay * ACCELERATION; + next.ay += inputs.ax * ACCELERATION; forward_euler(&next, delta); break; + case HOLE: + if (do_hole((Hole*) elem, curr)) { + return 31; + } + break; + case GOAL: + if (do_goal((Goal*) elem, curr)) { + return 1; + } + break; default: break; } @@ -56,8 +161,12 @@ // Last thing! Update state, so it will be saved for the next iteration. *curr = next; - + // Zero means we aren't done yet + // 1 means we've hit the goal + // 31 means we've hit a pothole + // 32 means we need help! + // 30 means we used the cheat code return 0; } @@ -75,17 +184,24 @@ int count = 0; int count2 = 0; + // Initialize checkpoint list + DLinkedList* checkpoints = create_dlinkedlist(); + // Initial draw of the game uLCD.background_color(BLACK); uLCD.cls(); + // Save start time + set_time(0); + time_t startTime = time(NULL); + /////////////////// // Main game loop /////////////////// while(1) { // Read timer to determine how long the last loop took tick = timer.read_ms(); - + /////////////////// // Physics Update /////////////////// @@ -101,8 +217,9 @@ GameInputs inputs = read_inputs(); // Update game state - int done = update_game(arena, state, inputs, delta); - if (done) return done; + int done = update_game(arena, state, inputs, checkpoints, delta); + if (done == 1) return 30 - (time(NULL) - startTime); + if (done != 0) return done; // Debug: Count physics updates count2++; @@ -121,7 +238,8 @@ case BALL: erase_ball((Ball*) elem); break; - default: break; + default: + break; } } while(elem = (ArenaElement*)getNext(arena)); @@ -135,11 +253,20 @@ case BALL: draw_ball((Ball*) elem, state); break; + case HOLE: + draw_hole((Hole*) elem); + break; + case GOAL: + draw_goal((Goal*) elem); + break; default: break; } } while(elem = (ArenaElement*)getNext(arena)); + uLCD.line(0, 0, 127, 0, 0); + uLCD.line(0, 0, (30 - (time(NULL) - startTime)) * (127/30), 0, GREEN); + /////////////// // Debug info /////////////// @@ -148,11 +275,11 @@ // Second number is how many physics iterations between drawing frames // Only displayed every 10th render update (roughly 2.5 Hz) // TODO: Take this out before you turn your code in! - if ((count = (count+1)%10) == 0) { - uLCD.locate(0, 0); - uLCD.printf("%d %d \r\n", timer.read_ms()-tick, count2); - } - + //if ((count = (count+1)%10) == 0) { + // uLCD.locate(0, 0); + // uLCD.printf("%d %d \r\n", timer.read_ms()-tick, count2); + //} + // Reset physics iteration counter after every render update count2 = 0; }
diff -r c18c231cb299 -r 2042f29de6b7 game.h --- a/game.h Wed Nov 08 21:01:43 2017 +0000 +++ b/game.h Thu Nov 21 16:10:57 2019 +0000 @@ -4,8 +4,7 @@ #include "doublely_linked_list.h" /* A structure for holding all the game inputs */ -struct GameInputs -{ +struct GameInputs { // Measurements from the accelerometer double ax, ay, az; }; @@ -24,6 +23,8 @@ // Element types #define WALL 0 #define BALL 1 +#define GOAL 2 +#define HOLE 3 /** An ArenaElement struct representing the ball. */ struct Ball { @@ -33,6 +34,24 @@ int x, y; }; +/** An ArenaElement struct representing the goal. */ +struct Goal { + // ArenaElement type (must be first element) + int type; + // Drawing info + int x, y; + int should_draw; +}; + +/** An ArenaElement struct representing a hole. */ +struct Hole { + // ArenaElement type (must be first element) + int type; + // Drawing info + int x, y; + int should_draw; +}; + ///////////////////////// // ArenaElement helpers ///////////////////////// @@ -43,8 +62,13 @@ /* Add additional helpers for other ArenaElement types here */ +/** Draws the goal */ +void draw_goal(Goal* goal); +/** Draws a hole */ +void draw_hole(Hole* hole); + /////////////////////////// -// Game control functions +// Game control functions /////////////////////////// /* Reads all game inputs */ GameInputs read_inputs();
diff -r c18c231cb299 -r 2042f29de6b7 globals.h --- a/globals.h Wed Nov 08 21:01:43 2017 +0000 +++ b/globals.h Thu Nov 21 16:10:57 2019 +0000 @@ -32,6 +32,9 @@ #include "wave_player.h" #include "SDFileSystem.h" #include "MMA8452.h" +#include "Speaker.h" + +#define ACCELERATION 500 // Hardware declarations. Initialization is in main.cpp extern uLCD_4DGL uLCD; // Screen @@ -45,9 +48,14 @@ extern wave_player waver; // wav player extern SDFileSystem sd; // SD card and filesystem (mosi, miso, sck, cs) +extern DigitalOut redLED; // Red LED +extern DigitalOut greenLED; // Green LED +extern Speaker speaker; // Speaker + // Global parameters. Initialized in main.cpp extern const float mass; extern const int radius; extern const float bounce; +extern int sound; #endif //GLOBAL_H \ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 main.cpp --- 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
diff -r c18c231cb299 -r 2042f29de6b7 physics.cpp --- a/physics.cpp Wed Nov 08 21:01:43 2017 +0000 +++ b/physics.cpp Thu Nov 21 16:10:57 2019 +0000 @@ -2,17 +2,23 @@ #include "math_extra.h" void forward_euler(Physics* state, float delta) -{ +{ // TODO: Implement proper forward euler updates for position and velocity - + // Compute random motion - float damp = 0.5; - float dx = damp*coin_flip(); - float dy = damp*coin_flip(); +// float damp = 0.5; +// float dx = damp*coin_flip(); +// float dy = damp*coin_flip(); + +// state->px = state->px + dx; +// state->py = state->py + dy; +// state->vx = dx; +// state->vy = dy; // Update position and velocity - state->px = state->px + dx; - state->py = state->py + dy; - state->vx = dx; - state->vy = dy; + state->vx += state->ax * delta; + state->vy += state->ay * delta; + state->px += state->vx * delta; + state->py += state->vy * delta; + } \ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 physics.h --- a/physics.h Wed Nov 08 21:01:43 2017 +0000 +++ b/physics.h Thu Nov 21 16:10:57 2019 +0000 @@ -3,10 +3,10 @@ /** * The main state structure for the game. * This structure holds all the global state for the game, and is updated during - * the game loop. When you implement the "jump back" feature, this is the + * the game loop. When you implement the "jump back" feature, this is the * structure you need to save/restore. */ -struct Physics { +struct Physics { float px, py; // Ball position float vx, vy; // Ball velocity float ax, ay; // Ball acceleration
diff -r c18c231cb299 -r 2042f29de6b7 wall.cpp --- a/wall.cpp Wed Nov 08 21:01:43 2017 +0000 +++ b/wall.cpp Thu Nov 21 16:10:57 2019 +0000 @@ -9,19 +9,19 @@ { // Alocate memory for wall Wall* wall = (Wall*) malloc(sizeof(Wall)); - + // Initialize type info. // Always draw on the first frame wall->type = WALL; wall->should_draw = 1; - + // Set user parameters wall->direction = direction; wall->x = x; wall->y = y; wall->length = length; wall->bounce = bounce; - + return wall; } @@ -29,56 +29,55 @@ { // Debug info // pc.printf("wall: %d %d %d %d\r\n", wall->direction, wall->x, wall->y, wall->length); - + float adj, percent, contact; - if (wall->direction == VERTICAL) - { + if (wall->direction == VERTICAL) { // Step 0: Adjust the wall location based on ball radius adj = wall->x - sgn(curr->vx)*(radius+1); // Step 1: Compute percent of motion before bounce percent = (adj - curr->px) / (curr->vx*delta); - + // Negative percent means we're moving away from the wall // >=100% means we don't need to bounce yet - if (percent >= 0.0 && percent < 1.0) - { + if (percent >= 0.0 && percent < 1.0) { // Compute the bounce location contact = curr->py + curr->vy*percent*delta; - if (in_range(contact, wall->y, wall->y + wall->length)) - { - + if (in_range(contact, wall->y, wall->y + wall->length)) { + // SGFX + redLED = 1; + speaker.PlayNote(100, 0.01, sound); + redLED = 0; + // Reverse velocity and slow down next->vx = -wall->bounce*curr->vx; // Adjust X position. - // This dampens the integration based on how far the ball had + // This dampens the integration based on how far the ball had // to travel before reflecting. next->px = adj - percent*next->vx*delta; } // Draw the wall if we're close by wall->should_draw = 1; } - + // Make sure we aren't inside the wall if (in_range((int)curr->px, wall->x - (radius+1), wall->x + (radius+1)) - && in_range((int)curr->py, wall->y, wall->y + wall->length)) - { + && in_range((int)curr->py, wall->y, wall->y + wall->length)) { next->px = wall->x + sgn(curr->px - wall->x)*(radius+1); wall->should_draw = 1; } - } - else //direction == HORIZONTAL - { + } else { //direction == HORIZONTAL // Same as vertical case, but swap x/y - adj = wall->y - sgn(curr->vy)*(radius+1); + adj = wall->y - sgn(curr->vy)*(radius+1); percent = (adj - curr->py) / (curr->vy*delta); - if (percent >= 0.0 && percent < 1.0) - { + if (percent >= 0.0 && percent < 1.0) { contact = curr->px + curr->vx*percent*delta; - if (in_range(contact, wall->x, wall->x + wall->length)) - { + if (in_range(contact, wall->x, wall->x + wall->length)) { + redLED = 1; + speaker.PlayNote(100, 0.01, sound); + redLED = 0; next->vy = -wall->bounce*curr->vy; next->py = adj - percent*next->vy*delta; } @@ -86,8 +85,7 @@ wall->should_draw = 1; } if (in_range((int)curr->py, wall->y - (radius+1), wall->y + (radius+1)) - && in_range((int)curr->px, wall->x, wall->x + wall->length)) - { + && in_range((int)curr->px, wall->x, wall->x + wall->length)) { next->py = wall->y + sgn(curr->py - wall->y)*(radius+1); wall->should_draw = 1; } @@ -96,16 +94,15 @@ void draw_wall(Wall* wall) { - if (wall->should_draw) - { + if (wall->should_draw) { int wx1, wx2, wy1, wy2; wx1 = wall->x; wy1 = wall->y; wx2 = wx1 + ((wall->direction == HORIZONTAL) ? wall->length : 0); wy2 = wy1 + ((wall->direction == VERTICAL) ? wall->length : 0); uLCD.line(wx1, wy1, wx2, wy2, WHITE); - + // Don't draw again unless requested wall->should_draw = 0; } -} \ No newline at end of file +} \ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 wall.h --- a/wall.h Wed Nov 08 21:01:43 2017 +0000 +++ b/wall.h Thu Nov 21 16:10:57 2019 +0000 @@ -6,7 +6,7 @@ /** * Structure to represent a Wall in the arena. - * + * * This structure is a ArenaElement; its first data element is an integer (type) * whose value is always WALL. */ @@ -47,7 +47,7 @@ /** * Draws a given wall to the screen. - * + * * @param[in] wall The wall to draw */ void draw_wall(Wall* wall);