Jay Balar / Mbed 2 deprecated 4180_Project_3

Dependencies:   4DGL-uLCD-SE Physac-MBED PinDetect SDFileSystem mbed-rtos mbed

Revision:
12:5d913b57da7c
Parent:
9:4e6fae5f9b23
Child:
16:6cf744b2623a
--- a/hockey/hockey.cpp	Tue Nov 29 23:05:30 2022 +0000
+++ b/hockey/hockey.cpp	Wed Nov 30 21:20:21 2022 +0000
@@ -1,7 +1,5 @@
-#include "mbed.h"
-#include "rtos.h"
 #include "hockey.h"
-#include "uLCD_4DGL.h"
+#include "globals.h"
 
 #define PHYSAC_NO_THREADS
 #define PHYSAC_STANDALONE
@@ -9,123 +7,316 @@
 #define _STDBOOL_H
 #include "physac.h"
 
-uLCD_4DGL uLCD(p9,p10,p30);
-Serial pc(USBTX, USBRX);
+#define SCREEN_WIDTH 128
+#define SCREEN_HEIGHT 128
+
+// Controls size of gamepieces in the hockey arena. This influences both
+// rendering and collision, so be careful adjusting dimensions too small
+#define HOCKEY_PUCK_RADIUS 4
+#define HOCKEY_PADDLE_W 8
+#define HOCKEY_PADDLE_H 24
 
-void thread2(void)
-{
-    uLCD.baudrate(BAUD_3000000);
-    wait(.05);
+// Controls the dimensions of the arena. You can adjust the screen margin above
+// and below the court, and the width of the goal.
+#define HOCKEY_ARENA_TOP 16
+#define HOCKEY_ARENA_BOT 127
+#define HOCKEY_GOAL_HEIGHT 32
+
+// Properties derived from other macros
+#define _HOCKEY_ARENA_H (HOCKEY_ARENA_BOT - HOCKEY_ARENA_TOP)
+#define _HOCKEY_GOAL_TOP ((_HOCKEY_ARENA_H - HOCKEY_GOAL_HEIGHT)/2 + HOCKEY_ARENA_TOP)
+#define _HOCKEY_GOAL_BOT (_HOCKEY_GOAL_TOP + HOCKEY_GOAL_HEIGHT)
 
-    //--------------------------------------------------------------------------------------
-    int screenWidth = 128;
-    int screenHeight = 128;
+int blue_score = 0;
+int red_score = 0;
+
+PhysicsBody puck;
+PhysicsBody paddle_a;
+PhysicsBody paddle_b;
+
+float input_sensitivity = 0.01f;
 
-    PhysicsBody puck = CreatePhysicsBodyCircle((Vector2) {
-        screenWidth/2, screenHeight/2
-    }, 4, 10);
+int maxOf(int a, int b)
+{
+    return (a > b) ? a : b;
+}
+
+int minOf(int a, int b)
+{
+    return (a < b) ? a : b;
+}
+
+void initPhysicsObjects()
+{
+    puck = CreatePhysicsBodyCircle((Vector2) {
+        SCREEN_WIDTH/2, SCREEN_HEIGHT/2
+    }, HOCKEY_PUCK_RADIUS, 1);
     puck->enabled = true;
     puck->useGravity = false;
     puck->restitution = 1.0;
+    puck->dynamicFriction = 0.0;
     puck->velocity = (Vector2) {
         5, 0
     };
 
-
-
-    // Create paddle_a rectangle physics body
-    PhysicsBody paddle_a = CreatePhysicsBodyRectangle((Vector2) {
+    paddle_a = CreatePhysicsBodyRectangle((Vector2) {
         32, 64
-    }, 8, 24, 10);
+    }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100);
     paddle_a->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions)
     paddle_a->useGravity = false;
     paddle_a->restitution = 1.0;
     SetPhysicsBodyRotation(paddle_a, 3.14159 / 6);
 
-    PhysicsBody paddle_b = CreatePhysicsBodyRectangle((Vector2) {
+    paddle_b = CreatePhysicsBodyRectangle((Vector2) {
         96, 64
-    }, 8, 24, 10);
+    }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100);
     paddle_b->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions)
     paddle_b->useGravity = false;
     paddle_b->restitution = 1.0;
     SetPhysicsBodyRotation(paddle_b, 3.14159 / 6);
+}
 
+/**
+ * Draws the fixed graphics of the game. This is the border of the arena
+ */
+void drawStaticEnvironment()
+{
+    uLCD.line(0, _HOCKEY_GOAL_TOP, 0, HOCKEY_ARENA_TOP, BLUE);
+    uLCD.line(0, _HOCKEY_GOAL_BOT, 0, HOCKEY_ARENA_BOT, BLUE);
+    uLCD.line(0, HOCKEY_ARENA_TOP, 63, HOCKEY_ARENA_TOP, BLUE);
+    uLCD.line(0, HOCKEY_ARENA_BOT, 63, HOCKEY_ARENA_BOT, BLUE);
 
-    // Simulation Loop
-    Timer timer;
-    timer.start();
+    uLCD.line(127, _HOCKEY_GOAL_TOP, 127, HOCKEY_ARENA_TOP, RED);
+    uLCD.line(127, _HOCKEY_GOAL_BOT, 127, HOCKEY_ARENA_BOT, RED);
+    uLCD.line(64, HOCKEY_ARENA_TOP, 127, HOCKEY_ARENA_TOP, RED);
+    uLCD.line(64, HOCKEY_ARENA_BOT, 127, HOCKEY_ARENA_BOT, RED);
+}
+
+/**
+ * Redraws the puck and paddles
+ * Each elements is erased, updated, and redrawn in as short of a window as
+ * possible.
+ */
+void drawDynamicObjects()
+{
+    static int puck_x = SCREEN_WIDTH / 2,
+               puck_y = SCREEN_WIDTH / 2;
+
+    // Redraw puck if moved
+    if (puck_x != puck->position.x || puck_y != puck->position.y) {
+        // erase
+        uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, BLACK);
 
-    deltaTime = 1.66;
+        // update
+        puck_x = puck->position.x;
+        puck_y = puck->position.y;
+
+        // redraw
+        uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, GREEN);
+    }
+
+    // Redraw blue paddle
+    static int pa_x1 = 64,
+               pa_x2 = 64,
+               pa_y1 = 64,
+               pa_y2 = 64;
 
-    while (true) {
-        float dt = timer.read() * 1000;
-        timer.reset();
+    float sinA = sin(-paddle_a->orient) / 2;
+    float cosA = cos(-paddle_a->orient) / 2;
+    uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLACK);
+    pa_x1 = paddle_a->position.x + HOCKEY_PADDLE_H * sinA;
+    pa_x2 = paddle_a->position.x - HOCKEY_PADDLE_H * sinA;
+    pa_y1 = paddle_a->position.y + HOCKEY_PADDLE_H * cosA;
+    pa_y2 = paddle_a->position.y - HOCKEY_PADDLE_H * cosA;
+    uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLUE);
+
+    // Redraw red paddle
+    static int pb_x1 = 64,
+               pb_x2 = 64,
+               pb_y1 = 64,
+               pb_y2 = 64;
+    float sinB = sin(-paddle_b->orient) / 2;
+    float cosB = cos(-paddle_b->orient) / 2;
+    uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, BLACK);
+    pb_x1 = paddle_b->position.x + HOCKEY_PADDLE_H * sinB;
+    pb_x2 = paddle_b->position.x - HOCKEY_PADDLE_H * sinB;
+    pb_y1 = paddle_b->position.y + HOCKEY_PADDLE_H * cosB;
+    pb_y2 = paddle_b->position.y - HOCKEY_PADDLE_H * cosB;
+    uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, RED);
+}
 
 
-        accumulator += dt;
-        if (accumulator >= deltaTime) {
-            PhysicsStep();
-            accumulator -= deltaTime;
+void resetGame()
+{
+    if (red_score >= 5 || blue_score >= 5) {
+        uLCD.cls();
+        uLCD.printf("Game Over");
+
+        if (red_score > blue_score) {
+            uLCD.printf("Red Wins");
+        } else {
+            uLCD.printf("Blue Wins");
         }
 
-        if (puck->position.y < 6 || puck->position.y > 122) {
-            puck->velocity.y *= -1;
-        } else if ((puck->position.y < 42 || puck->position.y > 86) &&
-                   (puck->position.x < 6 || puck->position.x > 122)) {
-            puck->velocity.x *= -1;
-        }
+        Thread::wait(2000);
+
+        game2 = false;
+    } else {
+        uLCD.cls();
+        drawStaticEnvironment();
 
-        float phys_time = timer.read() * 1000;
+        puck->position.x = SCREEN_WIDTH/2;
+        puck->position.y = SCREEN_HEIGHT/2;
+        paddle_a->position.x = 32;
+        paddle_a->position.y = 64;
+        SetPhysicsBodyRotation(paddle_a, 0);
+
+        paddle_b->position.x = 96;
+        paddle_b->position.y = 64;
+        SetPhysicsBodyRotation(paddle_b, 0);
+    }
+}
+
 
 
-        // Draw created physics bodies
-        int a_count = GetPhysicsShapeVerticesCount(paddle_a->id);
-        for (int j = 0; j < a_count; j++) {
-            Vector2 vertexA = GetPhysicsShapeVertex(paddle_a, j);
-            int jj = (((j + 1) < a_count) ? (j + 1) : 0);
-            Vector2 vertexB = GetPhysicsShapeVertex(paddle_a, jj);
-            uLCD.line(vertexA.x, vertexA.y, vertexB.x, vertexB.y, BLUE);
+/**
+ *
+ */
+void runGameLogic()
+{
+    // If puck hits the ceiling or floor, reflect across the y component of
+    // the velocity
+    if (puck->position.y < HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1) {
+        puck->velocity.y *= -1;
+        puck->position.y = maxOf(
+                               puck->position.y,
+                               HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1);
+    } else if (puck->position.y > HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1) {
+        puck->velocity.y *= -1;
+        puck->position.y = minOf(
+                               puck->position.y,
+                               HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1);
+    }
+
+    // true if the puck is in the y range corresponding to the goal
+    bool puckInGoalRange =
+        puck->position.y > _HOCKEY_GOAL_TOP &&
+        puck->position.y < _HOCKEY_GOAL_BOT;
+
+    // Puck collides with left or right walls
+    if (puckInGoalRange == false) {
+        if (puck->position.x < HOCKEY_PUCK_RADIUS + 1) {
+            puck->velocity.x *= -1;
+            puck->position.x = maxOf(
+                                   puck->position.x,
+                                   HOCKEY_PUCK_RADIUS + 1);
+        } else if (puck->position.x > SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 1) {
+            puck->velocity.x *= -1;
+            puck->position.x = minOf(
+                                   puck->position.x,
+                                   SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 2);
         }
-        int b_count = GetPhysicsShapeVerticesCount(paddle_b->id);
-        for (int j = 0; j < b_count; j++) {
-            Vector2 vertexA = GetPhysicsShapeVertex(paddle_b, j);
-            int jj = (((j + 1) < b_count) ? (j + 1) : 0);
-            Vector2 vertexB = GetPhysicsShapeVertex(paddle_b, jj);
-            uLCD.line(vertexA.x, vertexA.y, vertexB.x, vertexB.y, RED);
+    }
+
+    // Puck in goals
+    else {
+        // SCORE RED
+        if (puck->position.x < -HOCKEY_PUCK_RADIUS * 2) {
+            red_score += 1;
+            uLCD.printf("Red Scores");
+            uLCD.printf("   %i - %i", blue_score, red_score);
+            Thread::wait(2000);
+            resetGame();
+        }
+
+        // SCORE BLUE
+        else if (puck->position.x > SCREEN_WIDTH + HOCKEY_PUCK_RADIUS*2) {
+            blue_score += 1;
+            uLCD.printf("Blue Scores");
+            uLCD.printf("   %i - %i", blue_score, red_score);
+            Thread::wait(2000);
+            resetGame();
+        }
+    }
+}
+
+void hockeyGame(void)
+{
+    printf("Entering thread 2\r\n");
+    while (true) {
+        
+        while (game2 == false) {
+            printf("Waiting thread 2\r\n");
+            Thread::wait(500);
         }
         
-        uLCD.filled_circle(puck->position.x, puck->position.y, 4, GREEN);
+        printf("Starting Game 2 - Air Hockey\r\n");
+        
+        // Reset game variables
+        red_score = 0;
+        blue_score = 0;
 
-        /*int bodiesCount = GetPhysicsBodiesCount();
-        for (int i = 0; i < bodiesCount; i++) {
-            PhysicsBody body = GetPhysicsBody(i);
+        // Reset screen, draw arena
+        uLCD.baudrate(BAUD_3000000);
+        uLCD.cls();
+        drawStaticEnvironment();
+
+        // Set up Physac objects & simulation
+        initPhysicsObjects();
 
-            if (body != NULL) {
-                int vertexCount = GetPhysicsShapeVerticesCount(i);
-                for (int j = 0; j < vertexCount; j++) {
-                    // Get physics bodies shape vertices to draw lines
-                    // Note: GetPhysicsShapeVertex() already calculates rotation transformations
-                    Vector2 vertexA = GetPhysicsShapeVertex(body, j);
+        Timer timer;
+        timer.start();
+
+        deltaTime = 1.66;
+
+        while (game2) {
+            float dt = timer.read() * 1000;
+            timer.reset();
 
-                    int jj = (((j + 1) < vertexCount) ? (j + 1) : 0);   // Get next vertex or first to close the shape
-                    Vector2 vertexB = GetPhysicsShapeVertex(body, jj);
+            // Update the physics of the game
+            accumulator += dt;
+            if (accumulator >= deltaTime) {
+                PhysicsStep();
+                accumulator -= deltaTime;
+
+                runGameLogic();
+            }
+            float phys_time = timer.read() * 1000;
 
-                    uLCD.line(vertexA.x, vertexA.y, vertexB.x, vertexB.y, GREEN);     // Draw a line between two vertex positions
-                }
-            }
-        }*/
-        float render_time = timer.read()*1000 - phys_time;
-
+            // Render the game
+            drawDynamicObjects();
+            float render_time = timer.read()*1000 - phys_time;
 
-        pc.printf("[%2.2f] Phys: %4.4f/%4.4f Render: %4.4f  |  %4.2f %4.2f\r\n",
-                  dt,
-                  phys_time,
-                  accumulator,
-                  render_time,
-                  puck->position.x,
-                  puck->position.y);
+            // Process input from the game
+            blue.parseMessage();
+            if (blue.button[BUTTON_UP]) {
+                paddle_a->position.y -= dt * input_sensitivity;
+                printf("UP\r\n");
+            }
+            if (blue.button[BUTTON_DOWN]) {
+                paddle_a->position.y += dt * input_sensitivity;
+                printf("DOWN\r\n");
+            }
+            if (blue.button[BUTTON_LEFT]) {
+                paddle_a->position.x -= dt * input_sensitivity;
+                printf("LEFT\r\n");
+            }
+            if (blue.button[BUTTON_RIGHT]) {
+                paddle_a->position.x += dt * input_sensitivity;
+                printf("RIGHT\r\n");
+            }
+            if (blue.button[BUTTON_A]) {
+                SetPhysicsBodyRotation(paddle_a, paddle_a->orient - dt * input_sensitivity * 0.05);
+                printf("CW\r\n");
+            }
+            if (blue.button[BUTTON_B]) {
+                SetPhysicsBodyRotation(paddle_a, paddle_a->orient + dt * input_sensitivity * 0.05);
+                printf("CCW\r\n");
+            }
+
+            float input_time = timer.read()*1000 - render_time - phys_time;
+        }
+
+        ClosePhysics();       // Unitialize physics
     }
-
-    ClosePhysics();       // Unitialize physics
-
 }
\ No newline at end of file