ECE 2036 Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE

Committer:
abraha2d
Date:
Thu Nov 21 16:10:57 2019 +0000
Revision:
2:2042f29de6b7
Parent:
1:c18c231cb299
Because other peeps is wanting dis...

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rconnorlawson 0:cf4396614a79 1 #include "game.h"
rconnorlawson 0:cf4396614a79 2
rconnorlawson 0:cf4396614a79 3 #include "globals.h"
rconnorlawson 0:cf4396614a79 4 #include "physics.h"
rconnorlawson 0:cf4396614a79 5 #include "wall.h"
rconnorlawson 0:cf4396614a79 6
rconnorlawson 0:cf4396614a79 7
rconnorlawson 0:cf4396614a79 8 /** Erases the ball from the screen by drawing over it with the background color. */
rconnorlawson 0:cf4396614a79 9 void erase_ball(Ball* ball)
rconnorlawson 0:cf4396614a79 10 {
abraha2d 2:2042f29de6b7 11 // Draw background color over previously drawn ball location
abraha2d 2:2042f29de6b7 12 uLCD.filled_circle(ball->x, ball->y, radius, BLACK);
rconnorlawson 0:cf4396614a79 13 }
rconnorlawson 0:cf4396614a79 14
rconnorlawson 0:cf4396614a79 15 /** Draws the ball on the screen at the updated location (according to the state) */
rconnorlawson 0:cf4396614a79 16 void draw_ball(Ball* ball, Physics* state)
rconnorlawson 0:cf4396614a79 17 {
abraha2d 2:2042f29de6b7 18 // Draw ball in its updated location
abraha2d 2:2042f29de6b7 19 uLCD.filled_circle(state->px, state->py, radius, WHITE);
abraha2d 2:2042f29de6b7 20 // Save that updated ball position for later erasing
abraha2d 2:2042f29de6b7 21 ball->x = state->px;
abraha2d 2:2042f29de6b7 22 ball->y = state->py;
abraha2d 2:2042f29de6b7 23 }
abraha2d 2:2042f29de6b7 24
abraha2d 2:2042f29de6b7 25 /** Draws a hole on the screen */
abraha2d 2:2042f29de6b7 26 void draw_hole(Hole* hole)
abraha2d 2:2042f29de6b7 27 {
abraha2d 2:2042f29de6b7 28 if (hole->should_draw) {
abraha2d 2:2042f29de6b7 29 // Draw hole in its location
abraha2d 2:2042f29de6b7 30 uLCD.filled_circle(hole->x, hole->y, radius - 1, RED);
abraha2d 2:2042f29de6b7 31 hole->should_draw = 0;
abraha2d 2:2042f29de6b7 32 }
abraha2d 2:2042f29de6b7 33 }
abraha2d 2:2042f29de6b7 34
abraha2d 2:2042f29de6b7 35 /** Checks whether the ball has hit a hole */
abraha2d 2:2042f29de6b7 36 int do_hole(Hole* hole, Physics* curr)
abraha2d 2:2042f29de6b7 37 {
abraha2d 2:2042f29de6b7 38 double dist = sqrt(pow(curr->px - hole->x, 2) + pow(curr->py - hole->y, 2));
abraha2d 2:2042f29de6b7 39 if (dist < radius * 2) {
abraha2d 2:2042f29de6b7 40 hole->should_draw = 1;
abraha2d 2:2042f29de6b7 41 }
abraha2d 2:2042f29de6b7 42 if (dist < radius) {
abraha2d 2:2042f29de6b7 43 return 2;
abraha2d 2:2042f29de6b7 44 }
abraha2d 2:2042f29de6b7 45 return 0;
abraha2d 2:2042f29de6b7 46 }
abraha2d 2:2042f29de6b7 47
abraha2d 2:2042f29de6b7 48 /** Draws the goal on the screen */
abraha2d 2:2042f29de6b7 49 void draw_goal(Goal* goal)
abraha2d 2:2042f29de6b7 50 {
abraha2d 2:2042f29de6b7 51 if (goal->should_draw) {
abraha2d 2:2042f29de6b7 52 // Draw goal in its location
abraha2d 2:2042f29de6b7 53 uLCD.filled_circle(goal->x, goal->y, radius + 1, GREEN);
abraha2d 2:2042f29de6b7 54 goal->should_draw = 0;
abraha2d 2:2042f29de6b7 55 }
abraha2d 2:2042f29de6b7 56 }
abraha2d 2:2042f29de6b7 57
abraha2d 2:2042f29de6b7 58 /** Checks whether the ball has hit the goal */
abraha2d 2:2042f29de6b7 59 int do_goal(Goal* goal, Physics* curr)
abraha2d 2:2042f29de6b7 60 {
abraha2d 2:2042f29de6b7 61 double dist = sqrt(pow(curr->px - goal->x, 2) + pow(curr->py - goal->y, 2));
abraha2d 2:2042f29de6b7 62 if (dist < radius * 2) {
abraha2d 2:2042f29de6b7 63 goal->should_draw = 1;
abraha2d 2:2042f29de6b7 64 }
abraha2d 2:2042f29de6b7 65 if (dist < radius) {
abraha2d 2:2042f29de6b7 66 return 1;
abraha2d 2:2042f29de6b7 67 }
abraha2d 2:2042f29de6b7 68 return 0;
rconnorlawson 0:cf4396614a79 69 }
rconnorlawson 0:cf4396614a79 70
rconnorlawson 0:cf4396614a79 71 /** Reads inputs to the game, such as accelerometer and buttons */
rconnorlawson 0:cf4396614a79 72 GameInputs read_inputs()
rconnorlawson 0:cf4396614a79 73 {
rconnorlawson 0:cf4396614a79 74 GameInputs inputs = {0};
rconnorlawson 0:cf4396614a79 75
abraha2d 2:2042f29de6b7 76 // Get acceleration vector from accelerometer
abraha2d 2:2042f29de6b7 77 acc.readXYZGravity(&inputs.ax, &inputs.ay, &inputs.az);
rconnorlawson 0:cf4396614a79 78
rconnorlawson 0:cf4396614a79 79 return inputs;
rconnorlawson 0:cf4396614a79 80 }
rconnorlawson 0:cf4396614a79 81
abraha2d 2:2042f29de6b7 82 int lrpb = left_pb || right_pb;
abraha2d 2:2042f29de6b7 83 int lpb = 1;
abraha2d 2:2042f29de6b7 84 int upb = up_pb;
abraha2d 2:2042f29de6b7 85 int dpb = down_pb;
abraha2d 2:2042f29de6b7 86
abraha2d 2:2042f29de6b7 87 int update_game(DLinkedList* arena, Physics* curr, GameInputs inputs, DLinkedList* checkpoints, float delta)
rconnorlawson 0:cf4396614a79 88 {
abraha2d 2:2042f29de6b7 89
abraha2d 2:2042f29de6b7 90 // Cheat codes!
abraha2d 2:2042f29de6b7 91 if (left_pb == 0 && right_pb == 0 && lrpb == 1) {
abraha2d 2:2042f29de6b7 92 lpb = 1;
abraha2d 2:2042f29de6b7 93 uLCD.cls();
abraha2d 2:2042f29de6b7 94 uLCD.printf("\n\n\n\n Cheat code!");
abraha2d 2:2042f29de6b7 95 wait(0.5);
abraha2d 2:2042f29de6b7 96 return 30;
abraha2d 2:2042f29de6b7 97 }
abraha2d 2:2042f29de6b7 98
abraha2d 2:2042f29de6b7 99 // Help!
abraha2d 2:2042f29de6b7 100 if (left_pb == 1 && lpb == 0) {
abraha2d 2:2042f29de6b7 101 lpb = 1;
abraha2d 2:2042f29de6b7 102 return 32;
abraha2d 2:2042f29de6b7 103 }
abraha2d 2:2042f29de6b7 104
abraha2d 2:2042f29de6b7 105 // Save/restore state
abraha2d 2:2042f29de6b7 106 if (up_pb == 0 && upb == 1) {
abraha2d 2:2042f29de6b7 107 greenLED = 1;
abraha2d 2:2042f29de6b7 108 Physics* saveState = (Physics*) malloc(sizeof(Physics));
abraha2d 2:2042f29de6b7 109 *saveState = *curr;
abraha2d 2:2042f29de6b7 110 insertTail(checkpoints, saveState);
abraha2d 2:2042f29de6b7 111 }
abraha2d 2:2042f29de6b7 112 if (down_pb == 0 && dpb == 1) {
abraha2d 2:2042f29de6b7 113 Physics* restoreState = (Physics*) getTail(checkpoints);
abraha2d 2:2042f29de6b7 114 if (restoreState != NULL) {
abraha2d 2:2042f29de6b7 115 *curr = *restoreState;
abraha2d 2:2042f29de6b7 116 }
abraha2d 2:2042f29de6b7 117 }
abraha2d 2:2042f29de6b7 118
abraha2d 2:2042f29de6b7 119 // Save previous inputs
abraha2d 2:2042f29de6b7 120 lrpb = left_pb || right_pb;
abraha2d 2:2042f29de6b7 121 lpb = left_pb;
abraha2d 2:2042f29de6b7 122 upb = up_pb;
abraha2d 2:2042f29de6b7 123 dpb = down_pb;
abraha2d 2:2042f29de6b7 124
rconnorlawson 0:cf4396614a79 125 ///////////////////////////////
rconnorlawson 0:cf4396614a79 126 // Prepare for physics update
rconnorlawson 0:cf4396614a79 127 ///////////////////////////////
rconnorlawson 0:cf4396614a79 128 // Make a copy of the current state for modification
rconnorlawson 0:cf4396614a79 129 Physics next = *curr;
abraha2d 2:2042f29de6b7 130
rconnorlawson 0:cf4396614a79 131 // No acceleration unless the ArenaElements apply them. (Newton's 1st law)
rconnorlawson 0:cf4396614a79 132 next.ax = next.ay = 0.0;
rconnorlawson 0:cf4396614a79 133
abraha2d 2:2042f29de6b7 134
rconnorlawson 0:cf4396614a79 135 // Loop over all arena elements
rconnorlawson 0:cf4396614a79 136 ArenaElement* elem = (ArenaElement*)getHead(arena);
rconnorlawson 0:cf4396614a79 137 do {
rconnorlawson 0:cf4396614a79 138 switch(elem->type) {
rconnorlawson 0:cf4396614a79 139 case WALL:
rconnorlawson 0:cf4396614a79 140 do_wall(&next, curr, (Wall*) elem, delta);
rconnorlawson 0:cf4396614a79 141 break;
rconnorlawson 0:cf4396614a79 142 case BALL:
abraha2d 2:2042f29de6b7 143 next.ax += inputs.ay * ACCELERATION;
abraha2d 2:2042f29de6b7 144 next.ay += inputs.ax * ACCELERATION;
rconnorlawson 0:cf4396614a79 145 forward_euler(&next, delta);
rconnorlawson 0:cf4396614a79 146 break;
abraha2d 2:2042f29de6b7 147 case HOLE:
abraha2d 2:2042f29de6b7 148 if (do_hole((Hole*) elem, curr)) {
abraha2d 2:2042f29de6b7 149 return 31;
abraha2d 2:2042f29de6b7 150 }
abraha2d 2:2042f29de6b7 151 break;
abraha2d 2:2042f29de6b7 152 case GOAL:
abraha2d 2:2042f29de6b7 153 if (do_goal((Goal*) elem, curr)) {
abraha2d 2:2042f29de6b7 154 return 1;
abraha2d 2:2042f29de6b7 155 }
abraha2d 2:2042f29de6b7 156 break;
rconnorlawson 0:cf4396614a79 157 default:
rconnorlawson 0:cf4396614a79 158 break;
rconnorlawson 0:cf4396614a79 159 }
rconnorlawson 0:cf4396614a79 160 } while(elem = (ArenaElement*)getNext(arena));
rconnorlawson 0:cf4396614a79 161
rconnorlawson 0:cf4396614a79 162 // Last thing! Update state, so it will be saved for the next iteration.
rconnorlawson 0:cf4396614a79 163 *curr = next;
abraha2d 2:2042f29de6b7 164
rconnorlawson 0:cf4396614a79 165 // Zero means we aren't done yet
abraha2d 2:2042f29de6b7 166 // 1 means we've hit the goal
abraha2d 2:2042f29de6b7 167 // 31 means we've hit a pothole
abraha2d 2:2042f29de6b7 168 // 32 means we need help!
abraha2d 2:2042f29de6b7 169 // 30 means we used the cheat code
rconnorlawson 0:cf4396614a79 170 return 0;
rconnorlawson 0:cf4396614a79 171 }
rconnorlawson 0:cf4396614a79 172
rconnorlawson 0:cf4396614a79 173 int run_game(DLinkedList* arena, Physics* state)
rconnorlawson 0:cf4396614a79 174 {
rconnorlawson 0:cf4396614a79 175 // Initialize game loop timers
rconnorlawson 0:cf4396614a79 176 int tick, phys_tick, draw_tick;
rconnorlawson 0:cf4396614a79 177 Timer timer;
rconnorlawson 0:cf4396614a79 178 timer.start();
rconnorlawson 0:cf4396614a79 179 tick = timer.read_ms();
rconnorlawson 0:cf4396614a79 180 phys_tick = tick;
rconnorlawson 0:cf4396614a79 181 draw_tick = tick;
rconnorlawson 0:cf4396614a79 182
rconnorlawson 0:cf4396614a79 183 // Initialize debug counters
rconnorlawson 0:cf4396614a79 184 int count = 0;
rconnorlawson 0:cf4396614a79 185 int count2 = 0;
rconnorlawson 0:cf4396614a79 186
abraha2d 2:2042f29de6b7 187 // Initialize checkpoint list
abraha2d 2:2042f29de6b7 188 DLinkedList* checkpoints = create_dlinkedlist();
abraha2d 2:2042f29de6b7 189
rconnorlawson 0:cf4396614a79 190 // Initial draw of the game
rconnorlawson 0:cf4396614a79 191 uLCD.background_color(BLACK);
rconnorlawson 0:cf4396614a79 192 uLCD.cls();
rconnorlawson 0:cf4396614a79 193
abraha2d 2:2042f29de6b7 194 // Save start time
abraha2d 2:2042f29de6b7 195 set_time(0);
abraha2d 2:2042f29de6b7 196 time_t startTime = time(NULL);
abraha2d 2:2042f29de6b7 197
rconnorlawson 0:cf4396614a79 198 ///////////////////
rconnorlawson 0:cf4396614a79 199 // Main game loop
rconnorlawson 0:cf4396614a79 200 ///////////////////
rconnorlawson 0:cf4396614a79 201 while(1) {
rconnorlawson 0:cf4396614a79 202 // Read timer to determine how long the last loop took
rconnorlawson 0:cf4396614a79 203 tick = timer.read_ms();
abraha2d 2:2042f29de6b7 204
rconnorlawson 0:cf4396614a79 205 ///////////////////
rconnorlawson 0:cf4396614a79 206 // Physics Update
rconnorlawson 0:cf4396614a79 207 ///////////////////
rconnorlawson 0:cf4396614a79 208 // Rate limit: 1 ms
rconnorlawson 1:c18c231cb299 209 int diff = tick - phys_tick;
rconnorlawson 1:c18c231cb299 210 if (diff < 1) continue;
rconnorlawson 0:cf4396614a79 211 phys_tick = tick;
rconnorlawson 0:cf4396614a79 212
rconnorlawson 0:cf4396614a79 213 // Compute elapsed time in milliseconds
rconnorlawson 1:c18c231cb299 214 float delta = diff*1e-3;
rconnorlawson 0:cf4396614a79 215
rconnorlawson 0:cf4396614a79 216 // Read inputs
rconnorlawson 0:cf4396614a79 217 GameInputs inputs = read_inputs();
rconnorlawson 0:cf4396614a79 218
rconnorlawson 0:cf4396614a79 219 // Update game state
abraha2d 2:2042f29de6b7 220 int done = update_game(arena, state, inputs, checkpoints, delta);
abraha2d 2:2042f29de6b7 221 if (done == 1) return 30 - (time(NULL) - startTime);
abraha2d 2:2042f29de6b7 222 if (done != 0) return done;
rconnorlawson 0:cf4396614a79 223
rconnorlawson 0:cf4396614a79 224 // Debug: Count physics updates
rconnorlawson 0:cf4396614a79 225 count2++;
rconnorlawson 0:cf4396614a79 226
rconnorlawson 0:cf4396614a79 227 //////////////////
rconnorlawson 0:cf4396614a79 228 // Render update
rconnorlawson 0:cf4396614a79 229 //////////////////
rconnorlawson 0:cf4396614a79 230 // Rate limit: 40ms
rconnorlawson 0:cf4396614a79 231 if(tick - draw_tick < 40) continue;
rconnorlawson 0:cf4396614a79 232 draw_tick = tick;
rconnorlawson 0:cf4396614a79 233
rconnorlawson 0:cf4396614a79 234 // Erase moving stuff
rconnorlawson 0:cf4396614a79 235 ArenaElement* elem = (ArenaElement*)getHead(arena);
rconnorlawson 0:cf4396614a79 236 do {
rconnorlawson 0:cf4396614a79 237 switch(elem->type) {
rconnorlawson 0:cf4396614a79 238 case BALL:
rconnorlawson 0:cf4396614a79 239 erase_ball((Ball*) elem);
rconnorlawson 0:cf4396614a79 240 break;
abraha2d 2:2042f29de6b7 241 default:
abraha2d 2:2042f29de6b7 242 break;
rconnorlawson 0:cf4396614a79 243 }
rconnorlawson 0:cf4396614a79 244 } while(elem = (ArenaElement*)getNext(arena));
rconnorlawson 0:cf4396614a79 245
rconnorlawson 0:cf4396614a79 246 // Draw everything
rconnorlawson 0:cf4396614a79 247 elem = (ArenaElement*)getHead(arena);
rconnorlawson 0:cf4396614a79 248 do {
rconnorlawson 0:cf4396614a79 249 switch(elem->type) {
rconnorlawson 0:cf4396614a79 250 case WALL:
rconnorlawson 0:cf4396614a79 251 draw_wall((Wall*) elem);
rconnorlawson 0:cf4396614a79 252 break;
rconnorlawson 0:cf4396614a79 253 case BALL:
rconnorlawson 0:cf4396614a79 254 draw_ball((Ball*) elem, state);
rconnorlawson 0:cf4396614a79 255 break;
abraha2d 2:2042f29de6b7 256 case HOLE:
abraha2d 2:2042f29de6b7 257 draw_hole((Hole*) elem);
abraha2d 2:2042f29de6b7 258 break;
abraha2d 2:2042f29de6b7 259 case GOAL:
abraha2d 2:2042f29de6b7 260 draw_goal((Goal*) elem);
abraha2d 2:2042f29de6b7 261 break;
rconnorlawson 0:cf4396614a79 262 default:
rconnorlawson 0:cf4396614a79 263 break;
rconnorlawson 0:cf4396614a79 264 }
rconnorlawson 0:cf4396614a79 265 } while(elem = (ArenaElement*)getNext(arena));
rconnorlawson 0:cf4396614a79 266
abraha2d 2:2042f29de6b7 267 uLCD.line(0, 0, 127, 0, 0);
abraha2d 2:2042f29de6b7 268 uLCD.line(0, 0, (30 - (time(NULL) - startTime)) * (127/30), 0, GREEN);
abraha2d 2:2042f29de6b7 269
rconnorlawson 0:cf4396614a79 270 ///////////////
rconnorlawson 0:cf4396614a79 271 // Debug info
rconnorlawson 0:cf4396614a79 272 ///////////////
rconnorlawson 0:cf4396614a79 273 // Displays rate info in the top corner
rconnorlawson 0:cf4396614a79 274 // First number is total time to update and render this frame
rconnorlawson 0:cf4396614a79 275 // Second number is how many physics iterations between drawing frames
rconnorlawson 0:cf4396614a79 276 // Only displayed every 10th render update (roughly 2.5 Hz)
rconnorlawson 0:cf4396614a79 277 // TODO: Take this out before you turn your code in!
abraha2d 2:2042f29de6b7 278 //if ((count = (count+1)%10) == 0) {
abraha2d 2:2042f29de6b7 279 // uLCD.locate(0, 0);
abraha2d 2:2042f29de6b7 280 // uLCD.printf("%d %d \r\n", timer.read_ms()-tick, count2);
abraha2d 2:2042f29de6b7 281 //}
abraha2d 2:2042f29de6b7 282
rconnorlawson 0:cf4396614a79 283 // Reset physics iteration counter after every render update
rconnorlawson 0:cf4396614a79 284 count2 = 0;
rconnorlawson 0:cf4396614a79 285 }
rconnorlawson 0:cf4396614a79 286 }