Jay Balar / Mbed 2 deprecated 4180_Project_3

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

Committer:
jstephens78
Date:
Mon Dec 05 20:51:36 2022 +0000
Revision:
20:73e4f12277bd
Parent:
17:3517251daf96
Child:
23:214c0c828d98
All four threads launch, air hockey is the default

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