Jay Balar / Mbed 2 deprecated 4180_Project_3

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

Committer:
jstephens78
Date:
Thu Dec 01 01:43:39 2022 +0000
Revision:
17:3517251daf96
Parent:
16:6cf744b2623a
Child:
20:73e4f12277bd
Cleaned up air hockey gameplay logic and put uLCD accesses behind mutex locks.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jstephens78 9:4e6fae5f9b23 1 #include "hockey.h"
jstephens78 12:5d913b57da7c 2 #include "globals.h"
jstephens78 9:4e6fae5f9b23 3
jstephens78 9:4e6fae5f9b23 4 #define PHYSAC_NO_THREADS
jstephens78 9:4e6fae5f9b23 5 #define PHYSAC_STANDALONE
jstephens78 9:4e6fae5f9b23 6 #define PHYSAC_IMPLEMENTATION
jstephens78 9:4e6fae5f9b23 7 #define _STDBOOL_H
jstephens78 9:4e6fae5f9b23 8 #include "physac.h"
jstephens78 9:4e6fae5f9b23 9
jstephens78 12:5d913b57da7c 10 #define SCREEN_WIDTH 128
jstephens78 12:5d913b57da7c 11 #define SCREEN_HEIGHT 128
jstephens78 12:5d913b57da7c 12
jstephens78 12:5d913b57da7c 13 // Controls size of gamepieces in the hockey arena. This influences both
jstephens78 12:5d913b57da7c 14 // rendering and collision, so be careful adjusting dimensions too small
jstephens78 12:5d913b57da7c 15 #define HOCKEY_PUCK_RADIUS 4
jstephens78 12:5d913b57da7c 16 #define HOCKEY_PADDLE_W 8
jstephens78 12:5d913b57da7c 17 #define HOCKEY_PADDLE_H 24
jstephens78 9:4e6fae5f9b23 18
jstephens78 17:3517251daf96 19 // Physics sim properties.
jstephens78 17:3517251daf96 20 // HOCKEY_PHYSICS_STEPS number of physics ticks between frames
jstephens78 17:3517251daf96 21 // HOCKEY_PHYSICS_DELTA how many ms the physics engine believes pass per
jstephens78 17:3517251daf96 22 // update. This is arbitrary. Pick what behaves well.
jstephens78 17:3517251daf96 23 // HOCKEY_PUCK_VELOCITY how fact the puck moves in one physics tick
jstephens78 17:3517251daf96 24 #define HOCKEY_PHYSICS_STEPS 4
jstephens78 17:3517251daf96 25 #define HOCKEY_PHYSICS_DELTA 1.66
jstephens78 17:3517251daf96 26 #define HOCKEY_PUCK_VELOCITY (5.0f / HOCKEY_PHYSICS_STEPS)
jstephens78 17:3517251daf96 27
jstephens78 12:5d913b57da7c 28 // Controls the dimensions of the arena. You can adjust the screen margin above
jstephens78 12:5d913b57da7c 29 // and below the court, and the width of the goal.
jstephens78 12:5d913b57da7c 30 #define HOCKEY_ARENA_TOP 16
jstephens78 12:5d913b57da7c 31 #define HOCKEY_ARENA_BOT 127
jstephens78 12:5d913b57da7c 32 #define HOCKEY_GOAL_HEIGHT 32
jstephens78 12:5d913b57da7c 33
jstephens78 12:5d913b57da7c 34 // Properties derived from other macros
jstephens78 12:5d913b57da7c 35 #define _HOCKEY_ARENA_H (HOCKEY_ARENA_BOT - HOCKEY_ARENA_TOP)
jstephens78 17:3517251daf96 36 #define _HOCKEY_ARENA_MID ((HOCKEY_ARENA_BOT + HOCKEY_ARENA_TOP)/2)
jstephens78 12:5d913b57da7c 37 #define _HOCKEY_GOAL_TOP ((_HOCKEY_ARENA_H - HOCKEY_GOAL_HEIGHT)/2 + HOCKEY_ARENA_TOP)
jstephens78 12:5d913b57da7c 38 #define _HOCKEY_GOAL_BOT (_HOCKEY_GOAL_TOP + HOCKEY_GOAL_HEIGHT)
jstephens78 9:4e6fae5f9b23 39
jstephens78 17:3517251daf96 40
jstephens78 12:5d913b57da7c 41
jstephens78 12:5d913b57da7c 42 PhysicsBody puck;
jstephens78 12:5d913b57da7c 43 PhysicsBody paddle_a;
jstephens78 12:5d913b57da7c 44 PhysicsBody paddle_b;
jstephens78 12:5d913b57da7c 45
jstephens78 17:3517251daf96 46 int blue_score;
jstephens78 17:3517251daf96 47 int red_score;
jstephens78 17:3517251daf96 48 bool serve_direction; // 0 means toward blue, 1 means red
jstephens78 17:3517251daf96 49 float input_sensitivity = 4.00f;
jstephens78 9:4e6fae5f9b23 50
jstephens78 17:3517251daf96 51 // Helper functions
jstephens78 17:3517251daf96 52 // @{
jstephens78 12:5d913b57da7c 53 int maxOf(int a, int b)
jstephens78 12:5d913b57da7c 54 {
jstephens78 12:5d913b57da7c 55 return (a > b) ? a : b;
jstephens78 12:5d913b57da7c 56 }
jstephens78 12:5d913b57da7c 57 int minOf(int a, int b)
jstephens78 12:5d913b57da7c 58 {
jstephens78 12:5d913b57da7c 59 return (a < b) ? a : b;
jstephens78 12:5d913b57da7c 60 }
jstephens78 17:3517251daf96 61 int clamp(int a, int low, int upp)
jstephens78 17:3517251daf96 62 {
jstephens78 17:3517251daf96 63 return minOf(upp, maxOf(a, low));
jstephens78 17:3517251daf96 64 }
jstephens78 17:3517251daf96 65 // @}
jstephens78 12:5d913b57da7c 66
jstephens78 17:3517251daf96 67 /**
jstephens78 17:3517251daf96 68 * Sets up physics elements within the Physac library
jstephens78 17:3517251daf96 69 */
jstephens78 12:5d913b57da7c 70 void initPhysicsObjects()
jstephens78 12:5d913b57da7c 71 {
jstephens78 17:3517251daf96 72 SetPhysicsTimeStep(HOCKEY_PHYSICS_DELTA);
jstephens78 17:3517251daf96 73
jstephens78 12:5d913b57da7c 74 puck = CreatePhysicsBodyCircle((Vector2) {
jstephens78 12:5d913b57da7c 75 SCREEN_WIDTH/2, SCREEN_HEIGHT/2
jstephens78 12:5d913b57da7c 76 }, HOCKEY_PUCK_RADIUS, 1);
jstephens78 9:4e6fae5f9b23 77 puck->enabled = true;
jstephens78 9:4e6fae5f9b23 78 puck->useGravity = false;
jstephens78 9:4e6fae5f9b23 79 puck->restitution = 1.0;
jstephens78 17:3517251daf96 80 puck->dynamicFriction = 0;
jstephens78 9:4e6fae5f9b23 81 puck->velocity = (Vector2) {
jstephens78 17:3517251daf96 82 HOCKEY_PUCK_VELOCITY, 0
jstephens78 9:4e6fae5f9b23 83 };
jstephens78 9:4e6fae5f9b23 84
jstephens78 12:5d913b57da7c 85 paddle_a = CreatePhysicsBodyRectangle((Vector2) {
jstephens78 17:3517251daf96 86 32, _HOCKEY_ARENA_MID
jstephens78 12:5d913b57da7c 87 }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100);
jstephens78 9:4e6fae5f9b23 88 paddle_a->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions)
jstephens78 9:4e6fae5f9b23 89 paddle_a->useGravity = false;
jstephens78 9:4e6fae5f9b23 90 paddle_a->restitution = 1.0;
jstephens78 9:4e6fae5f9b23 91 SetPhysicsBodyRotation(paddle_a, 3.14159 / 6);
jstephens78 9:4e6fae5f9b23 92
jstephens78 12:5d913b57da7c 93 paddle_b = CreatePhysicsBodyRectangle((Vector2) {
jstephens78 17:3517251daf96 94 96, _HOCKEY_ARENA_MID
jstephens78 12:5d913b57da7c 95 }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100);
jstephens78 9:4e6fae5f9b23 96 paddle_b->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions)
jstephens78 9:4e6fae5f9b23 97 paddle_b->useGravity = false;
jstephens78 9:4e6fae5f9b23 98 paddle_b->restitution = 1.0;
jstephens78 9:4e6fae5f9b23 99 SetPhysicsBodyRotation(paddle_b, 3.14159 / 6);
jstephens78 12:5d913b57da7c 100 }
jstephens78 9:4e6fae5f9b23 101
jstephens78 12:5d913b57da7c 102 /**
jstephens78 12:5d913b57da7c 103 * Draws the fixed graphics of the game. This is the border of the arena
jstephens78 17:3517251daf96 104 *
jstephens78 17:3517251daf96 105 * note: locks `uLCD_mutex`
jstephens78 12:5d913b57da7c 106 */
jstephens78 12:5d913b57da7c 107 void drawStaticEnvironment()
jstephens78 12:5d913b57da7c 108 {
jstephens78 17:3517251daf96 109 uLCD_mutex.lock();
jstephens78 17:3517251daf96 110
jstephens78 17:3517251daf96 111 // Clear screen
jstephens78 17:3517251daf96 112 uLCD.cls();
jstephens78 17:3517251daf96 113
jstephens78 17:3517251daf96 114 // Draw arena border
jstephens78 12:5d913b57da7c 115 uLCD.line(0, _HOCKEY_GOAL_TOP, 0, HOCKEY_ARENA_TOP, BLUE);
jstephens78 12:5d913b57da7c 116 uLCD.line(0, _HOCKEY_GOAL_BOT, 0, HOCKEY_ARENA_BOT, BLUE);
jstephens78 12:5d913b57da7c 117 uLCD.line(0, HOCKEY_ARENA_TOP, 63, HOCKEY_ARENA_TOP, BLUE);
jstephens78 12:5d913b57da7c 118 uLCD.line(0, HOCKEY_ARENA_BOT, 63, HOCKEY_ARENA_BOT, BLUE);
jstephens78 12:5d913b57da7c 119 uLCD.line(127, _HOCKEY_GOAL_TOP, 127, HOCKEY_ARENA_TOP, RED);
jstephens78 12:5d913b57da7c 120 uLCD.line(127, _HOCKEY_GOAL_BOT, 127, HOCKEY_ARENA_BOT, RED);
jstephens78 12:5d913b57da7c 121 uLCD.line(64, HOCKEY_ARENA_TOP, 127, HOCKEY_ARENA_TOP, RED);
jstephens78 12:5d913b57da7c 122 uLCD.line(64, HOCKEY_ARENA_BOT, 127, HOCKEY_ARENA_BOT, RED);
jstephens78 17:3517251daf96 123
jstephens78 17:3517251daf96 124 // Draw score
jstephens78 17:3517251daf96 125 uLCD.color(BLUE);
jstephens78 17:3517251daf96 126 uLCD.locate(0, 0);
jstephens78 17:3517251daf96 127 uLCD.printf("%i", blue_score);
jstephens78 17:3517251daf96 128 uLCD.color(RED);
jstephens78 17:3517251daf96 129 uLCD.locate(17, 0);
jstephens78 17:3517251daf96 130 uLCD.printf("%i", red_score);
jstephens78 17:3517251daf96 131
jstephens78 17:3517251daf96 132 // Draw serve indicator
jstephens78 17:3517251daf96 133 uLCD.filled_circle(
jstephens78 17:3517251daf96 134 serve_direction ? SCREEN_WIDTH - 16 : 16,
jstephens78 17:3517251daf96 135 HOCKEY_ARENA_TOP / 2,
jstephens78 17:3517251daf96 136 HOCKEY_ARENA_TOP / 6,
jstephens78 17:3517251daf96 137 serve_direction ? RED : BLUE);
jstephens78 17:3517251daf96 138
jstephens78 17:3517251daf96 139 uLCD_mutex.unlock();
jstephens78 12:5d913b57da7c 140 }
jstephens78 12:5d913b57da7c 141
jstephens78 12:5d913b57da7c 142 /**
jstephens78 12:5d913b57da7c 143 * Redraws the puck and paddles
jstephens78 12:5d913b57da7c 144 * Each elements is erased, updated, and redrawn in as short of a window as
jstephens78 12:5d913b57da7c 145 * possible.
jstephens78 17:3517251daf96 146 *
jstephens78 17:3517251daf96 147 * note: locks `uLCD_mutex`
jstephens78 12:5d913b57da7c 148 */
jstephens78 12:5d913b57da7c 149 void drawDynamicObjects()
jstephens78 12:5d913b57da7c 150 {
jstephens78 12:5d913b57da7c 151 static int puck_x = SCREEN_WIDTH / 2,
jstephens78 17:3517251daf96 152 puck_y = _HOCKEY_ARENA_MID;
jstephens78 12:5d913b57da7c 153
jstephens78 17:3517251daf96 154 uLCD_mutex.lock();
jstephens78 9:4e6fae5f9b23 155
jstephens78 17:3517251daf96 156 // Redraw puck
jstephens78 17:3517251daf96 157 uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, BLACK);
jstephens78 17:3517251daf96 158 puck_x = puck->position.x;
jstephens78 17:3517251daf96 159 puck_y = puck->position.y;
jstephens78 17:3517251daf96 160 uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, GREEN);
jstephens78 12:5d913b57da7c 161
jstephens78 12:5d913b57da7c 162 // Redraw blue paddle
jstephens78 12:5d913b57da7c 163 static int pa_x1 = 64,
jstephens78 12:5d913b57da7c 164 pa_x2 = 64,
jstephens78 12:5d913b57da7c 165 pa_y1 = 64,
jstephens78 12:5d913b57da7c 166 pa_y2 = 64;
jstephens78 12:5d913b57da7c 167 float sinA = sin(-paddle_a->orient) / 2;
jstephens78 12:5d913b57da7c 168 float cosA = cos(-paddle_a->orient) / 2;
jstephens78 12:5d913b57da7c 169 uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLACK);
jstephens78 12:5d913b57da7c 170 pa_x1 = paddle_a->position.x + HOCKEY_PADDLE_H * sinA;
jstephens78 12:5d913b57da7c 171 pa_x2 = paddle_a->position.x - HOCKEY_PADDLE_H * sinA;
jstephens78 12:5d913b57da7c 172 pa_y1 = paddle_a->position.y + HOCKEY_PADDLE_H * cosA;
jstephens78 12:5d913b57da7c 173 pa_y2 = paddle_a->position.y - HOCKEY_PADDLE_H * cosA;
jstephens78 12:5d913b57da7c 174 uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLUE);
jstephens78 12:5d913b57da7c 175
jstephens78 12:5d913b57da7c 176 // Redraw red paddle
jstephens78 12:5d913b57da7c 177 static int pb_x1 = 64,
jstephens78 12:5d913b57da7c 178 pb_x2 = 64,
jstephens78 12:5d913b57da7c 179 pb_y1 = 64,
jstephens78 12:5d913b57da7c 180 pb_y2 = 64;
jstephens78 12:5d913b57da7c 181 float sinB = sin(-paddle_b->orient) / 2;
jstephens78 12:5d913b57da7c 182 float cosB = cos(-paddle_b->orient) / 2;
jstephens78 12:5d913b57da7c 183 uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, BLACK);
jstephens78 12:5d913b57da7c 184 pb_x1 = paddle_b->position.x + HOCKEY_PADDLE_H * sinB;
jstephens78 12:5d913b57da7c 185 pb_x2 = paddle_b->position.x - HOCKEY_PADDLE_H * sinB;
jstephens78 12:5d913b57da7c 186 pb_y1 = paddle_b->position.y + HOCKEY_PADDLE_H * cosB;
jstephens78 12:5d913b57da7c 187 pb_y2 = paddle_b->position.y - HOCKEY_PADDLE_H * cosB;
jstephens78 12:5d913b57da7c 188 uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, RED);
jstephens78 17:3517251daf96 189
jstephens78 17:3517251daf96 190 uLCD_mutex.unlock();
jstephens78 12:5d913b57da7c 191 }
jstephens78 9:4e6fae5f9b23 192
jstephens78 17:3517251daf96 193 /**
jstephens78 17:3517251daf96 194 * Reset the game after a goal.
jstephens78 17:3517251daf96 195 * If the game will continue, re-draw and reset the pieces.
jstephens78 17:3517251daf96 196 * If the game is over, display end scene and then suspend the game loop until
jstephens78 17:3517251daf96 197 * re-launched.
jstephens78 17:3517251daf96 198 */
jstephens78 12:5d913b57da7c 199 void resetGame()
jstephens78 12:5d913b57da7c 200 {
jstephens78 17:3517251daf96 201 // If game over, draw an end-game screen
jstephens78 12:5d913b57da7c 202 if (red_score >= 5 || blue_score >= 5) {
jstephens78 17:3517251daf96 203 uLCD_mutex.lock();
jstephens78 12:5d913b57da7c 204 uLCD.cls();
jstephens78 17:3517251daf96 205 uLCD.locate(5, 3);
jstephens78 17:3517251daf96 206 uLCD.color(GREEN);
jstephens78 12:5d913b57da7c 207 uLCD.printf("Game Over");
jstephens78 12:5d913b57da7c 208
jstephens78 12:5d913b57da7c 209 if (red_score > blue_score) {
jstephens78 17:3517251daf96 210 uLCD.locate(5, 5);
jstephens78 17:3517251daf96 211 uLCD.color(RED);
jstephens78 17:3517251daf96 212 uLCD.printf("Red Wins!");
jstephens78 12:5d913b57da7c 213 } else {
jstephens78 17:3517251daf96 214 uLCD.locate(5, 5);
jstephens78 17:3517251daf96 215 uLCD.color(BLUE);
jstephens78 17:3517251daf96 216 uLCD.printf("Blue Wins!");
jstephens78 9:4e6fae5f9b23 217 }
jstephens78 9:4e6fae5f9b23 218
jstephens78 12:5d913b57da7c 219 Thread::wait(2000);
jstephens78 12:5d913b57da7c 220
jstephens78 12:5d913b57da7c 221 game2 = false;
jstephens78 17:3517251daf96 222 uLCD_mutex.unlock();
jstephens78 17:3517251daf96 223 }
jstephens78 17:3517251daf96 224
jstephens78 17:3517251daf96 225 // Otherwise re-draw the game board and reset the pieces
jstephens78 17:3517251daf96 226 else {
jstephens78 12:5d913b57da7c 227 drawStaticEnvironment();
jstephens78 9:4e6fae5f9b23 228
jstephens78 12:5d913b57da7c 229 puck->position.x = SCREEN_WIDTH/2;
jstephens78 17:3517251daf96 230 puck->position.y = _HOCKEY_ARENA_MID;
jstephens78 17:3517251daf96 231 puck->velocity.x = HOCKEY_PUCK_VELOCITY * (serve_direction ? 1 : -1);
jstephens78 17:3517251daf96 232 puck->velocity.y = (float)(rand() % 50) / 100;
jstephens78 17:3517251daf96 233
jstephens78 12:5d913b57da7c 234 paddle_a->position.x = 32;
jstephens78 17:3517251daf96 235 paddle_a->position.y = _HOCKEY_ARENA_MID;
jstephens78 12:5d913b57da7c 236 SetPhysicsBodyRotation(paddle_a, 0);
jstephens78 12:5d913b57da7c 237
jstephens78 12:5d913b57da7c 238 paddle_b->position.x = 96;
jstephens78 17:3517251daf96 239 paddle_b->position.y = _HOCKEY_ARENA_MID;
jstephens78 12:5d913b57da7c 240 SetPhysicsBodyRotation(paddle_b, 0);
jstephens78 12:5d913b57da7c 241 }
jstephens78 12:5d913b57da7c 242 }
jstephens78 12:5d913b57da7c 243
jstephens78 12:5d913b57da7c 244 /**
jstephens78 17:3517251daf96 245 * Handles puck bouncing off walls, goal scoring, player input, and end-game
jstephens78 17:3517251daf96 246 * conditions
jstephens78 12:5d913b57da7c 247 */
jstephens78 12:5d913b57da7c 248 void runGameLogic()
jstephens78 12:5d913b57da7c 249 {
jstephens78 12:5d913b57da7c 250 // If puck hits the ceiling or floor, reflect across the y component of
jstephens78 12:5d913b57da7c 251 // the velocity
jstephens78 12:5d913b57da7c 252 if (puck->position.y < HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1) {
jstephens78 12:5d913b57da7c 253 puck->velocity.y *= -1;
jstephens78 12:5d913b57da7c 254 puck->position.y = maxOf(
jstephens78 12:5d913b57da7c 255 puck->position.y,
jstephens78 12:5d913b57da7c 256 HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1);
jstephens78 12:5d913b57da7c 257 } else if (puck->position.y > HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1) {
jstephens78 12:5d913b57da7c 258 puck->velocity.y *= -1;
jstephens78 12:5d913b57da7c 259 puck->position.y = minOf(
jstephens78 12:5d913b57da7c 260 puck->position.y,
jstephens78 12:5d913b57da7c 261 HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1);
jstephens78 12:5d913b57da7c 262 }
jstephens78 12:5d913b57da7c 263
jstephens78 12:5d913b57da7c 264 // true if the puck is in the y range corresponding to the goal
jstephens78 12:5d913b57da7c 265 bool puckInGoalRange =
jstephens78 12:5d913b57da7c 266 puck->position.y > _HOCKEY_GOAL_TOP &&
jstephens78 12:5d913b57da7c 267 puck->position.y < _HOCKEY_GOAL_BOT;
jstephens78 12:5d913b57da7c 268
jstephens78 12:5d913b57da7c 269 // Puck collides with left or right walls
jstephens78 12:5d913b57da7c 270 if (puckInGoalRange == false) {
jstephens78 17:3517251daf96 271 if (puck->position.x < HOCKEY_PUCK_RADIUS + 1 && puck->position.x > 0) {
jstephens78 12:5d913b57da7c 272 puck->velocity.x *= -1;
jstephens78 12:5d913b57da7c 273 puck->position.x = maxOf(
jstephens78 12:5d913b57da7c 274 puck->position.x,
jstephens78 12:5d913b57da7c 275 HOCKEY_PUCK_RADIUS + 1);
jstephens78 17:3517251daf96 276 } else if (puck->position.x > SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 1 && puck->position.x < SCREEN_WIDTH) {
jstephens78 12:5d913b57da7c 277 puck->velocity.x *= -1;
jstephens78 12:5d913b57da7c 278 puck->position.x = minOf(
jstephens78 12:5d913b57da7c 279 puck->position.x,
jstephens78 12:5d913b57da7c 280 SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 2);
jstephens78 9:4e6fae5f9b23 281 }
jstephens78 12:5d913b57da7c 282 }
jstephens78 12:5d913b57da7c 283
jstephens78 12:5d913b57da7c 284 // Puck in goals
jstephens78 12:5d913b57da7c 285 else {
jstephens78 12:5d913b57da7c 286 // SCORE RED
jstephens78 17:3517251daf96 287 if (puck->position.x <= -HOCKEY_PUCK_RADIUS * 2) {
jstephens78 12:5d913b57da7c 288 red_score += 1;
jstephens78 17:3517251daf96 289 serve_direction = 0;
jstephens78 17:3517251daf96 290 uLCD.locate(4, 1);
jstephens78 17:3517251daf96 291 uLCD.color(RED);
jstephens78 17:3517251daf96 292 uLCD.printf("Red Scores!");
jstephens78 12:5d913b57da7c 293 Thread::wait(2000);
jstephens78 12:5d913b57da7c 294 resetGame();
jstephens78 12:5d913b57da7c 295 }
jstephens78 12:5d913b57da7c 296
jstephens78 12:5d913b57da7c 297 // SCORE BLUE
jstephens78 17:3517251daf96 298 else if (puck->position.x >= SCREEN_WIDTH + HOCKEY_PUCK_RADIUS * 2) {
jstephens78 12:5d913b57da7c 299 blue_score += 1;
jstephens78 17:3517251daf96 300 serve_direction = 1;
jstephens78 17:3517251daf96 301 uLCD.locate(3, 1);
jstephens78 17:3517251daf96 302 uLCD.color(BLUE);
jstephens78 17:3517251daf96 303 uLCD.printf("Blue Scores!");
jstephens78 12:5d913b57da7c 304 Thread::wait(2000);
jstephens78 12:5d913b57da7c 305 resetGame();
jstephens78 12:5d913b57da7c 306 }
jstephens78 12:5d913b57da7c 307 }
jstephens78 12:5d913b57da7c 308 }
jstephens78 12:5d913b57da7c 309
jstephens78 17:3517251daf96 310 /**
jstephens78 17:3517251daf96 311 * Process user input and update game state
jstephens78 17:3517251daf96 312 */
jstephens78 17:3517251daf96 313 void handleInput()
jstephens78 17:3517251daf96 314 {
jstephens78 17:3517251daf96 315 // Process input from the game
jstephens78 17:3517251daf96 316 blue.parseMessage();
jstephens78 17:3517251daf96 317 if (blue.button[BUTTON_UP]) {
jstephens78 17:3517251daf96 318 paddle_a->position.y -= input_sensitivity;
jstephens78 17:3517251daf96 319 }
jstephens78 17:3517251daf96 320 if (blue.button[BUTTON_DOWN]) {
jstephens78 17:3517251daf96 321 paddle_a->position.y += input_sensitivity;
jstephens78 17:3517251daf96 322 }
jstephens78 17:3517251daf96 323 if (blue.button[BUTTON_LEFT]) {
jstephens78 17:3517251daf96 324 paddle_a->position.x -= input_sensitivity;
jstephens78 17:3517251daf96 325 }
jstephens78 17:3517251daf96 326 if (blue.button[BUTTON_RIGHT]) {
jstephens78 17:3517251daf96 327 paddle_a->position.x += input_sensitivity;
jstephens78 17:3517251daf96 328 }
jstephens78 17:3517251daf96 329 if (blue.button[BUTTON_A]) {
jstephens78 17:3517251daf96 330 SetPhysicsBodyRotation(paddle_a, paddle_a->orient - input_sensitivity * 0.05);
jstephens78 17:3517251daf96 331 }
jstephens78 17:3517251daf96 332 if (blue.button[BUTTON_B]) {
jstephens78 17:3517251daf96 333 SetPhysicsBodyRotation(paddle_a, paddle_a->orient + input_sensitivity * 0.05);
jstephens78 17:3517251daf96 334 }
jstephens78 17:3517251daf96 335
jstephens78 17:3517251daf96 336 // Player 2 Input
jstephens78 17:3517251daf96 337 if (!(navSwitch & 0b00001)) { // Up
jstephens78 17:3517251daf96 338 paddle_b->position.y -= input_sensitivity;
jstephens78 17:3517251daf96 339 }
jstephens78 17:3517251daf96 340 if (!(navSwitch & 0b01000)) { // down
jstephens78 17:3517251daf96 341 paddle_b->position.y += input_sensitivity;
jstephens78 17:3517251daf96 342 }
jstephens78 17:3517251daf96 343 if (!(navSwitch & 0b00100)) { // left
jstephens78 17:3517251daf96 344 paddle_b->position.x -= input_sensitivity;
jstephens78 17:3517251daf96 345 }
jstephens78 17:3517251daf96 346 if (!(navSwitch & 0b10000)) { // right
jstephens78 17:3517251daf96 347 paddle_b->position.x += input_sensitivity;
jstephens78 17:3517251daf96 348 }
jstephens78 17:3517251daf96 349 if (!(navSwitch & 0b00010)) { // rotate
jstephens78 17:3517251daf96 350 SetPhysicsBodyRotation(paddle_b, paddle_b->orient + 3.14159 / 4);
jstephens78 17:3517251daf96 351 }
jstephens78 17:3517251daf96 352
jstephens78 17:3517251daf96 353 // Bounds checking. Don't let users steer paddles out of the arena
jstephens78 17:3517251daf96 354 paddle_a->position.y = clamp(paddle_a->position.y, HOCKEY_ARENA_TOP, HOCKEY_ARENA_BOT);
jstephens78 17:3517251daf96 355 paddle_a->position.x = clamp(paddle_a->position.x, 1, SCREEN_WIDTH - 1);
jstephens78 17:3517251daf96 356
jstephens78 17:3517251daf96 357 paddle_b->position.y = clamp(paddle_b->position.y, HOCKEY_ARENA_TOP, HOCKEY_ARENA_BOT);
jstephens78 17:3517251daf96 358 paddle_b->position.x = clamp(paddle_b->position.x, 1, SCREEN_WIDTH - 1);
jstephens78 17:3517251daf96 359 }
jstephens78 17:3517251daf96 360
jstephens78 17:3517251daf96 361 /**
jstephens78 17:3517251daf96 362 * The primary game loop for the air hockey game
jstephens78 17:3517251daf96 363 */
jstephens78 12:5d913b57da7c 364 void hockeyGame(void)
jstephens78 12:5d913b57da7c 365 {
jstephens78 17:3517251daf96 366 // Set up Physac objects & simulation
jstephens78 17:3517251daf96 367 initPhysicsObjects();
jstephens78 17:3517251daf96 368
jstephens78 12:5d913b57da7c 369 while (true) {
jstephens78 17:3517251daf96 370
jstephens78 17:3517251daf96 371 // Wait until the game starts
jstephens78 12:5d913b57da7c 372 while (game2 == false) {
jstephens78 12:5d913b57da7c 373 printf("Waiting thread 2\r\n");
jstephens78 17:3517251daf96 374 Thread::wait(100);
jstephens78 17:3517251daf96 375 game2 = true;
jstephens78 9:4e6fae5f9b23 376 }
jstephens78 17:3517251daf96 377
jstephens78 17:3517251daf96 378 // Reset game state
jstephens78 12:5d913b57da7c 379 red_score = 0;
jstephens78 12:5d913b57da7c 380 blue_score = 0;
jstephens78 17:3517251daf96 381 serve_direction = rand() % 2;
jstephens78 17:3517251daf96 382 resetGame();
jstephens78 9:4e6fae5f9b23 383
jstephens78 12:5d913b57da7c 384 // Reset screen, draw arena
jstephens78 12:5d913b57da7c 385 drawStaticEnvironment();
jstephens78 12:5d913b57da7c 386
jstephens78 12:5d913b57da7c 387 Timer timer;
jstephens78 12:5d913b57da7c 388 timer.start();
jstephens78 12:5d913b57da7c 389
jstephens78 12:5d913b57da7c 390 while (game2) {
jstephens78 12:5d913b57da7c 391 float dt = timer.read() * 1000;
jstephens78 12:5d913b57da7c 392 timer.reset();
jstephens78 9:4e6fae5f9b23 393
jstephens78 12:5d913b57da7c 394 // Update the physics of the game
jstephens78 17:3517251daf96 395 for (int i = 0; i < HOCKEY_PHYSICS_STEPS; i++) {
jstephens78 12:5d913b57da7c 396 PhysicsStep();
jstephens78 17:3517251daf96 397 runGameLogic();
jstephens78 17:3517251daf96 398 if (game2 == false) break;
jstephens78 17:3517251daf96 399 }
jstephens78 12:5d913b57da7c 400
jstephens78 17:3517251daf96 401 // Exit loop early if game over after the logic step
jstephens78 17:3517251daf96 402 if (game2 == false) continue;
jstephens78 17:3517251daf96 403
jstephens78 17:3517251daf96 404 handleInput();
jstephens78 9:4e6fae5f9b23 405
jstephens78 12:5d913b57da7c 406 // Render the game
jstephens78 12:5d913b57da7c 407 drawDynamicObjects();
jstephens78 17:3517251daf96 408
jstephens78 16:6cf744b2623a 409 Thread::yield();
jstephens78 12:5d913b57da7c 410 }
jstephens78 17:3517251daf96 411 }
jstephens78 12:5d913b57da7c 412
jstephens78 17:3517251daf96 413 ClosePhysics();
jstephens78 9:4e6fae5f9b23 414 }