ECE 2036 Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers <title>game.cpp Source File</title>

game.cpp

00001 #include "game.h"
00002 
00003 #include "globals.h"
00004 #include "physics.h"
00005 #include "wall.h"
00006 
00007 
00008 /** Erases the ball from the screen by drawing over it with the background color. */
00009 void erase_ball(Ball* ball)
00010 {
00011     // Draw background color over previously drawn ball location
00012     uLCD.filled_circle(ball->x, ball->y, radius, BLACK);
00013 }
00014 
00015 /** Draws the ball on the screen at the updated location (according to the state) */
00016 void draw_ball(Ball* ball, Physics* state)
00017 {
00018     // Draw ball in its updated location
00019     uLCD.filled_circle(state->px, state->py, radius, WHITE);
00020     // Save that updated ball position for later erasing
00021     ball->x = state->px;
00022     ball->y = state->py;
00023 }
00024 
00025 /** Draws a hole on the screen */
00026 void draw_hole(Hole* hole)
00027 {
00028     if (hole->should_draw) {
00029         // Draw hole in its location
00030         uLCD.filled_circle(hole->x, hole->y, radius - 1, RED);
00031         hole->should_draw = 0;
00032     }
00033 }
00034 
00035 /** Checks whether the ball has hit a hole */
00036 int do_hole(Hole* hole, Physics* curr)
00037 {
00038     double dist = sqrt(pow(curr->px - hole->x, 2) + pow(curr->py - hole->y, 2));
00039     if (dist < radius * 2) {
00040         hole->should_draw = 1;
00041     }
00042     if (dist < radius) {
00043         return 2;
00044     }
00045     return 0;
00046 }
00047 
00048 /** Draws the goal on the screen */
00049 void draw_goal(Goal* goal)
00050 {
00051     if (goal->should_draw) {
00052         // Draw goal in its location
00053         uLCD.filled_circle(goal->x, goal->y, radius + 1, GREEN);
00054         goal->should_draw = 0;
00055     }
00056 }
00057 
00058 /** Checks whether the ball has hit the goal */
00059 int do_goal(Goal* goal, Physics* curr)
00060 {
00061     double dist = sqrt(pow(curr->px - goal->x, 2) + pow(curr->py - goal->y, 2));
00062     if (dist < radius * 2) {
00063         goal->should_draw = 1;
00064     }
00065     if (dist < radius) {
00066         return 1;
00067     }
00068     return 0;
00069 }
00070 
00071 /** Reads inputs to the game, such as accelerometer and buttons */
00072 GameInputs read_inputs()
00073 {
00074     GameInputs inputs = {0};
00075 
00076     // Get acceleration vector from accelerometer
00077     acc.readXYZGravity(&inputs.ax, &inputs.ay, &inputs.az);
00078 
00079     return inputs;
00080 }
00081 
00082 int lrpb = left_pb || right_pb;
00083 int lpb = 1;
00084 int upb = up_pb;
00085 int dpb = down_pb;
00086 
00087 int update_game(DLinkedList* arena, Physics* curr, GameInputs inputs, DLinkedList* checkpoints, float delta)
00088 {
00089 
00090     // Cheat codes!
00091     if (left_pb == 0 && right_pb == 0 && lrpb == 1) {
00092         lpb = 1;
00093         uLCD.cls();
00094         uLCD.printf("\n\n\n\n    Cheat code!");
00095         wait(0.5);
00096         return 30;
00097     }
00098 
00099     // Help!
00100     if (left_pb == 1 && lpb == 0) {
00101         lpb = 1;
00102         return 32;
00103     }
00104 
00105     // Save/restore state
00106     if (up_pb == 0 && upb == 1) {
00107         greenLED = 1;
00108         Physics* saveState = (Physics*) malloc(sizeof(Physics));
00109         *saveState = *curr;
00110         insertTail(checkpoints, saveState);
00111     }
00112     if (down_pb == 0 && dpb == 1) {
00113         Physics* restoreState = (Physics*) getTail(checkpoints);
00114         if (restoreState != NULL) {
00115             *curr = *restoreState;
00116         }
00117     }
00118 
00119     // Save previous inputs
00120     lrpb = left_pb || right_pb;
00121     lpb = left_pb;
00122     upb = up_pb;
00123     dpb = down_pb;
00124 
00125     ///////////////////////////////
00126     // Prepare for physics update
00127     ///////////////////////////////
00128     // Make a copy of the current state for modification
00129     Physics next = *curr;
00130 
00131     // No acceleration unless the ArenaElements apply them. (Newton's 1st law)
00132     next.ax = next.ay = 0.0;
00133 
00134 
00135     // Loop over all arena elements
00136     ArenaElement* elem = (ArenaElement*)getHead(arena);
00137     do {
00138         switch(elem->type) {
00139             case WALL:
00140                 do_wall(&next, curr, (Wall*) elem, delta);
00141                 break;
00142             case BALL:
00143                 next.ax += inputs.ay * ACCELERATION;
00144                 next.ay += inputs.ax * ACCELERATION;
00145                 forward_euler(&next, delta);
00146                 break;
00147             case HOLE:
00148                 if (do_hole((Hole*) elem, curr)) {
00149                     return 31;
00150                 }
00151                 break;
00152             case GOAL:
00153                 if (do_goal((Goal*) elem, curr)) {
00154                     return 1;
00155                 }
00156                 break;
00157             default:
00158                 break;
00159         }
00160     } while(elem = (ArenaElement*)getNext(arena));
00161 
00162     // Last thing! Update state, so it will be saved for the next iteration.
00163     *curr = next;
00164 
00165     // Zero means we aren't done yet
00166     // 1 means we've hit the goal
00167     // 31 means we've hit a pothole
00168     // 32 means we need help!
00169     // 30 means we used the cheat code
00170     return 0;
00171 }
00172 
00173 int run_game(DLinkedList* arena, Physics* state)
00174 {
00175     // Initialize game loop timers
00176     int tick, phys_tick, draw_tick;
00177     Timer timer;
00178     timer.start();
00179     tick = timer.read_ms();
00180     phys_tick = tick;
00181     draw_tick = tick;
00182 
00183     // Initialize debug counters
00184     int count = 0;
00185     int count2 = 0;
00186 
00187     // Initialize checkpoint list
00188     DLinkedList* checkpoints = create_dlinkedlist();
00189 
00190     // Initial draw of the game
00191     uLCD.background_color(BLACK);
00192     uLCD.cls();
00193 
00194     // Save start time
00195     set_time(0);
00196     time_t startTime = time(NULL);
00197 
00198     ///////////////////
00199     // Main game loop
00200     ///////////////////
00201     while(1) {
00202         // Read timer to determine how long the last loop took
00203         tick = timer.read_ms();
00204 
00205         ///////////////////
00206         // Physics Update
00207         ///////////////////
00208         // Rate limit: 1 ms
00209         int diff = tick - phys_tick;
00210         if (diff < 1) continue;
00211         phys_tick = tick;
00212 
00213         // Compute elapsed time in milliseconds
00214         float delta = diff*1e-3;
00215 
00216         // Read inputs
00217         GameInputs inputs = read_inputs();
00218 
00219         // Update game state
00220         int done = update_game(arena, state, inputs, checkpoints, delta);
00221         if (done == 1) return 30 - (time(NULL) - startTime);
00222         if (done != 0) return done;
00223 
00224         // Debug: Count physics updates
00225         count2++;
00226 
00227         //////////////////
00228         // Render update
00229         //////////////////
00230         // Rate limit: 40ms
00231         if(tick - draw_tick < 40) continue;
00232         draw_tick = tick;
00233 
00234         // Erase moving stuff
00235         ArenaElement* elem = (ArenaElement*)getHead(arena);
00236         do {
00237             switch(elem->type) {
00238                 case BALL:
00239                     erase_ball((Ball*) elem);
00240                     break;
00241                 default:
00242                     break;
00243             }
00244         } while(elem = (ArenaElement*)getNext(arena));
00245 
00246         // Draw everything
00247         elem = (ArenaElement*)getHead(arena);
00248         do {
00249             switch(elem->type) {
00250                 case WALL:
00251                     draw_wall((Wall*) elem);
00252                     break;
00253                 case BALL:
00254                     draw_ball((Ball*) elem, state);
00255                     break;
00256                 case HOLE:
00257                     draw_hole((Hole*) elem);
00258                     break;
00259                 case GOAL:
00260                     draw_goal((Goal*) elem);
00261                     break;
00262                 default:
00263                     break;
00264             }
00265         } while(elem = (ArenaElement*)getNext(arena));
00266 
00267         uLCD.line(0, 0, 127, 0, 0);
00268         uLCD.line(0, 0, (30 - (time(NULL) - startTime)) * (127/30), 0, GREEN);
00269 
00270         ///////////////
00271         // Debug info
00272         ///////////////
00273         // Displays rate info in the top corner
00274         //  First number is total time to update and render this frame
00275         //  Second number is how many physics iterations between drawing frames
00276         //  Only displayed every 10th render update (roughly 2.5 Hz)
00277         // TODO: Take this out before you turn your code in!
00278         //if ((count = (count+1)%10) == 0) {
00279         //    uLCD.locate(0, 0);
00280         //    uLCD.printf("%d %d \r\n", timer.read_ms()-tick, count2);
00281         //}
00282 
00283         // Reset physics iteration counter after every render update
00284         count2 = 0;
00285     }
00286 }