ECE 2036 Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE

Revision:
2:2042f29de6b7
Parent:
1:c18c231cb299
--- 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;
     }