ECE 2036 Project
Dependencies: mbed wave_player 4DGL-uLCD-SE
game.cpp
- Committer:
- abraha2d
- Date:
- 2019-11-21
- Revision:
- 2:2042f29de6b7
- Parent:
- 1:c18c231cb299
File content as of revision 2:2042f29de6b7:
#include "game.h" #include "globals.h" #include "physics.h" #include "wall.h" /** Erases the ball from the screen by drawing over it with the background color. */ void erase_ball(Ball* ball) { // 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) { // 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 */ GameInputs read_inputs() { GameInputs inputs = {0}; // Get acceleration vector from accelerometer acc.readXYZGravity(&inputs.ax, &inputs.ay, &inputs.az); return inputs; } 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 { switch(elem->type) { case WALL: 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; } } while(elem = (ArenaElement*)getNext(arena)); // 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; } int run_game(DLinkedList* arena, Physics* state) { // Initialize game loop timers int tick, phys_tick, draw_tick; Timer timer; timer.start(); tick = timer.read_ms(); phys_tick = tick; draw_tick = tick; // Initialize debug counters 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 /////////////////// // Rate limit: 1 ms int diff = tick - phys_tick; if (diff < 1) continue; phys_tick = tick; // Compute elapsed time in milliseconds float delta = diff*1e-3; // Read inputs GameInputs inputs = read_inputs(); // Update game state 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++; ////////////////// // Render update ////////////////// // Rate limit: 40ms if(tick - draw_tick < 40) continue; draw_tick = tick; // Erase moving stuff ArenaElement* elem = (ArenaElement*)getHead(arena); do { switch(elem->type) { case BALL: erase_ball((Ball*) elem); break; default: break; } } while(elem = (ArenaElement*)getNext(arena)); // Draw everything elem = (ArenaElement*)getHead(arena); do { switch(elem->type) { case WALL: draw_wall((Wall*) elem); break; 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 /////////////// // Displays rate info in the top corner // First number is total time to update and render this frame // 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); //} // Reset physics iteration counter after every render update count2 = 0; } }