Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: 4DGL-uLCD-SE Physac-MBED PinDetect SDFileSystem mbed-rtos mbed
hockey/hockey.cpp@23:214c0c828d98, 2022-12-07 (annotated)
- Committer:
- jsanchez307
- Date:
- Wed Dec 07 23:12:12 2022 +0000
- Revision:
- 23:214c0c828d98
- Parent:
- 20:73e4f12277bd
- Child:
- 26:163d7ca8c42d
Tetris and Hockey updated for Nav_Switch myNav
Who changed what in which revision?
User | Revision | Line number | New 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 | PhysicsBody puck; |
jstephens78 | 12:5d913b57da7c | 44 | PhysicsBody paddle_a; |
jstephens78 | 12:5d913b57da7c | 45 | PhysicsBody paddle_b; |
jstephens78 | 12:5d913b57da7c | 46 | |
jstephens78 | 17:3517251daf96 | 47 | int blue_score; |
jstephens78 | 17:3517251daf96 | 48 | int red_score; |
jstephens78 | 17:3517251daf96 | 49 | bool serve_direction; // 0 means toward blue, 1 means red |
jstephens78 | 17:3517251daf96 | 50 | float input_sensitivity = 4.00f; |
jstephens78 | 9:4e6fae5f9b23 | 51 | |
jstephens78 | 17:3517251daf96 | 52 | // Helper functions |
jstephens78 | 17:3517251daf96 | 53 | // @{ |
jstephens78 | 12:5d913b57da7c | 54 | int maxOf(int a, int b) |
jstephens78 | 12:5d913b57da7c | 55 | { |
jstephens78 | 12:5d913b57da7c | 56 | return (a > b) ? a : b; |
jstephens78 | 12:5d913b57da7c | 57 | } |
jstephens78 | 12:5d913b57da7c | 58 | int minOf(int a, int b) |
jstephens78 | 12:5d913b57da7c | 59 | { |
jstephens78 | 12:5d913b57da7c | 60 | return (a < b) ? a : b; |
jstephens78 | 12:5d913b57da7c | 61 | } |
jstephens78 | 17:3517251daf96 | 62 | int clamp(int a, int low, int upp) |
jstephens78 | 17:3517251daf96 | 63 | { |
jstephens78 | 17:3517251daf96 | 64 | return minOf(upp, maxOf(a, low)); |
jstephens78 | 17:3517251daf96 | 65 | } |
jstephens78 | 17:3517251daf96 | 66 | // @} |
jstephens78 | 12:5d913b57da7c | 67 | |
jstephens78 | 17:3517251daf96 | 68 | /** |
jstephens78 | 17:3517251daf96 | 69 | * Sets up physics elements within the Physac library |
jstephens78 | 17:3517251daf96 | 70 | */ |
jstephens78 | 12:5d913b57da7c | 71 | void initPhysicsObjects() |
jstephens78 | 12:5d913b57da7c | 72 | { |
jstephens78 | 17:3517251daf96 | 73 | SetPhysicsTimeStep(HOCKEY_PHYSICS_DELTA); |
jstephens78 | 17:3517251daf96 | 74 | |
jstephens78 | 12:5d913b57da7c | 75 | puck = CreatePhysicsBodyCircle((Vector2) { |
jstephens78 | 12:5d913b57da7c | 76 | SCREEN_WIDTH/2, SCREEN_HEIGHT/2 |
jstephens78 | 12:5d913b57da7c | 77 | }, HOCKEY_PUCK_RADIUS, 1); |
jstephens78 | 9:4e6fae5f9b23 | 78 | puck->enabled = true; |
jstephens78 | 9:4e6fae5f9b23 | 79 | puck->useGravity = false; |
jstephens78 | 9:4e6fae5f9b23 | 80 | puck->restitution = 1.0; |
jstephens78 | 17:3517251daf96 | 81 | puck->dynamicFriction = 0; |
jstephens78 | 9:4e6fae5f9b23 | 82 | puck->velocity = (Vector2) { |
jstephens78 | 17:3517251daf96 | 83 | HOCKEY_PUCK_VELOCITY, 0 |
jstephens78 | 9:4e6fae5f9b23 | 84 | }; |
jstephens78 | 9:4e6fae5f9b23 | 85 | |
jstephens78 | 12:5d913b57da7c | 86 | paddle_a = CreatePhysicsBodyRectangle((Vector2) { |
jstephens78 | 17:3517251daf96 | 87 | 32, _HOCKEY_ARENA_MID |
jstephens78 | 12:5d913b57da7c | 88 | }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100); |
jstephens78 | 9:4e6fae5f9b23 | 89 | paddle_a->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) |
jstephens78 | 9:4e6fae5f9b23 | 90 | paddle_a->useGravity = false; |
jstephens78 | 9:4e6fae5f9b23 | 91 | paddle_a->restitution = 1.0; |
jstephens78 | 9:4e6fae5f9b23 | 92 | SetPhysicsBodyRotation(paddle_a, 3.14159 / 6); |
jstephens78 | 9:4e6fae5f9b23 | 93 | |
jstephens78 | 12:5d913b57da7c | 94 | paddle_b = CreatePhysicsBodyRectangle((Vector2) { |
jstephens78 | 17:3517251daf96 | 95 | 96, _HOCKEY_ARENA_MID |
jstephens78 | 12:5d913b57da7c | 96 | }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100); |
jstephens78 | 9:4e6fae5f9b23 | 97 | paddle_b->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) |
jstephens78 | 9:4e6fae5f9b23 | 98 | paddle_b->useGravity = false; |
jstephens78 | 9:4e6fae5f9b23 | 99 | paddle_b->restitution = 1.0; |
jstephens78 | 9:4e6fae5f9b23 | 100 | SetPhysicsBodyRotation(paddle_b, 3.14159 / 6); |
jstephens78 | 12:5d913b57da7c | 101 | } |
jstephens78 | 9:4e6fae5f9b23 | 102 | |
jstephens78 | 12:5d913b57da7c | 103 | /** |
jstephens78 | 12:5d913b57da7c | 104 | * Draws the fixed graphics of the game. This is the border of the arena |
jstephens78 | 17:3517251daf96 | 105 | * |
jstephens78 | 17:3517251daf96 | 106 | * note: locks `uLCD_mutex` |
jstephens78 | 12:5d913b57da7c | 107 | */ |
jstephens78 | 12:5d913b57da7c | 108 | void drawStaticEnvironment() |
jstephens78 | 12:5d913b57da7c | 109 | { |
jstephens78 | 17:3517251daf96 | 110 | uLCD_mutex.lock(); |
jstephens78 | 17:3517251daf96 | 111 | |
jstephens78 | 17:3517251daf96 | 112 | // Clear screen |
jstephens78 | 17:3517251daf96 | 113 | uLCD.cls(); |
jstephens78 | 17:3517251daf96 | 114 | |
jstephens78 | 17:3517251daf96 | 115 | // Draw arena border |
jstephens78 | 12:5d913b57da7c | 116 | uLCD.line(0, _HOCKEY_GOAL_TOP, 0, HOCKEY_ARENA_TOP, BLUE); |
jstephens78 | 12:5d913b57da7c | 117 | uLCD.line(0, _HOCKEY_GOAL_BOT, 0, HOCKEY_ARENA_BOT, BLUE); |
jstephens78 | 12:5d913b57da7c | 118 | uLCD.line(0, HOCKEY_ARENA_TOP, 63, HOCKEY_ARENA_TOP, BLUE); |
jstephens78 | 12:5d913b57da7c | 119 | uLCD.line(0, HOCKEY_ARENA_BOT, 63, HOCKEY_ARENA_BOT, BLUE); |
jstephens78 | 12:5d913b57da7c | 120 | uLCD.line(127, _HOCKEY_GOAL_TOP, 127, HOCKEY_ARENA_TOP, RED); |
jstephens78 | 12:5d913b57da7c | 121 | uLCD.line(127, _HOCKEY_GOAL_BOT, 127, HOCKEY_ARENA_BOT, RED); |
jstephens78 | 12:5d913b57da7c | 122 | uLCD.line(64, HOCKEY_ARENA_TOP, 127, HOCKEY_ARENA_TOP, RED); |
jstephens78 | 12:5d913b57da7c | 123 | uLCD.line(64, HOCKEY_ARENA_BOT, 127, HOCKEY_ARENA_BOT, RED); |
jstephens78 | 17:3517251daf96 | 124 | |
jstephens78 | 17:3517251daf96 | 125 | // Draw score |
jstephens78 | 17:3517251daf96 | 126 | uLCD.color(BLUE); |
jstephens78 | 17:3517251daf96 | 127 | uLCD.locate(0, 0); |
jstephens78 | 17:3517251daf96 | 128 | uLCD.printf("%i", blue_score); |
jstephens78 | 17:3517251daf96 | 129 | uLCD.color(RED); |
jstephens78 | 17:3517251daf96 | 130 | uLCD.locate(17, 0); |
jstephens78 | 17:3517251daf96 | 131 | uLCD.printf("%i", red_score); |
jstephens78 | 17:3517251daf96 | 132 | |
jstephens78 | 17:3517251daf96 | 133 | // Draw serve indicator |
jstephens78 | 17:3517251daf96 | 134 | uLCD.filled_circle( |
jstephens78 | 17:3517251daf96 | 135 | serve_direction ? SCREEN_WIDTH - 16 : 16, |
jstephens78 | 17:3517251daf96 | 136 | HOCKEY_ARENA_TOP / 2, |
jstephens78 | 17:3517251daf96 | 137 | HOCKEY_ARENA_TOP / 6, |
jstephens78 | 17:3517251daf96 | 138 | serve_direction ? RED : BLUE); |
jstephens78 | 17:3517251daf96 | 139 | |
jstephens78 | 17:3517251daf96 | 140 | uLCD_mutex.unlock(); |
jstephens78 | 12:5d913b57da7c | 141 | } |
jstephens78 | 12:5d913b57da7c | 142 | |
jstephens78 | 12:5d913b57da7c | 143 | /** |
jstephens78 | 12:5d913b57da7c | 144 | * Redraws the puck and paddles |
jstephens78 | 12:5d913b57da7c | 145 | * Each elements is erased, updated, and redrawn in as short of a window as |
jstephens78 | 12:5d913b57da7c | 146 | * possible. |
jstephens78 | 17:3517251daf96 | 147 | * |
jstephens78 | 17:3517251daf96 | 148 | * note: locks `uLCD_mutex` |
jstephens78 | 12:5d913b57da7c | 149 | */ |
jstephens78 | 12:5d913b57da7c | 150 | void drawDynamicObjects() |
jstephens78 | 12:5d913b57da7c | 151 | { |
jstephens78 | 12:5d913b57da7c | 152 | static int puck_x = SCREEN_WIDTH / 2, |
jstephens78 | 17:3517251daf96 | 153 | puck_y = _HOCKEY_ARENA_MID; |
jstephens78 | 12:5d913b57da7c | 154 | |
jstephens78 | 17:3517251daf96 | 155 | uLCD_mutex.lock(); |
jstephens78 | 9:4e6fae5f9b23 | 156 | |
jstephens78 | 17:3517251daf96 | 157 | // Redraw puck |
jstephens78 | 17:3517251daf96 | 158 | uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, BLACK); |
jstephens78 | 17:3517251daf96 | 159 | puck_x = puck->position.x; |
jstephens78 | 17:3517251daf96 | 160 | puck_y = puck->position.y; |
jstephens78 | 17:3517251daf96 | 161 | uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, GREEN); |
jstephens78 | 12:5d913b57da7c | 162 | |
jstephens78 | 12:5d913b57da7c | 163 | // Redraw blue paddle |
jstephens78 | 12:5d913b57da7c | 164 | static int pa_x1 = 64, |
jstephens78 | 12:5d913b57da7c | 165 | pa_x2 = 64, |
jstephens78 | 12:5d913b57da7c | 166 | pa_y1 = 64, |
jstephens78 | 12:5d913b57da7c | 167 | pa_y2 = 64; |
jstephens78 | 12:5d913b57da7c | 168 | float sinA = sin(-paddle_a->orient) / 2; |
jstephens78 | 12:5d913b57da7c | 169 | float cosA = cos(-paddle_a->orient) / 2; |
jstephens78 | 12:5d913b57da7c | 170 | uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLACK); |
jstephens78 | 12:5d913b57da7c | 171 | pa_x1 = paddle_a->position.x + HOCKEY_PADDLE_H * sinA; |
jstephens78 | 12:5d913b57da7c | 172 | pa_x2 = paddle_a->position.x - HOCKEY_PADDLE_H * sinA; |
jstephens78 | 12:5d913b57da7c | 173 | pa_y1 = paddle_a->position.y + HOCKEY_PADDLE_H * cosA; |
jstephens78 | 12:5d913b57da7c | 174 | pa_y2 = paddle_a->position.y - HOCKEY_PADDLE_H * cosA; |
jstephens78 | 12:5d913b57da7c | 175 | uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLUE); |
jstephens78 | 12:5d913b57da7c | 176 | |
jstephens78 | 12:5d913b57da7c | 177 | // Redraw red paddle |
jstephens78 | 12:5d913b57da7c | 178 | static int pb_x1 = 64, |
jstephens78 | 12:5d913b57da7c | 179 | pb_x2 = 64, |
jstephens78 | 12:5d913b57da7c | 180 | pb_y1 = 64, |
jstephens78 | 12:5d913b57da7c | 181 | pb_y2 = 64; |
jstephens78 | 12:5d913b57da7c | 182 | float sinB = sin(-paddle_b->orient) / 2; |
jstephens78 | 12:5d913b57da7c | 183 | float cosB = cos(-paddle_b->orient) / 2; |
jstephens78 | 12:5d913b57da7c | 184 | uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, BLACK); |
jstephens78 | 12:5d913b57da7c | 185 | pb_x1 = paddle_b->position.x + HOCKEY_PADDLE_H * sinB; |
jstephens78 | 12:5d913b57da7c | 186 | pb_x2 = paddle_b->position.x - HOCKEY_PADDLE_H * sinB; |
jstephens78 | 12:5d913b57da7c | 187 | pb_y1 = paddle_b->position.y + HOCKEY_PADDLE_H * cosB; |
jstephens78 | 12:5d913b57da7c | 188 | pb_y2 = paddle_b->position.y - HOCKEY_PADDLE_H * cosB; |
jstephens78 | 12:5d913b57da7c | 189 | uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, RED); |
jstephens78 | 17:3517251daf96 | 190 | |
jstephens78 | 17:3517251daf96 | 191 | uLCD_mutex.unlock(); |
jstephens78 | 12:5d913b57da7c | 192 | } |
jstephens78 | 9:4e6fae5f9b23 | 193 | |
jstephens78 | 17:3517251daf96 | 194 | /** |
jstephens78 | 17:3517251daf96 | 195 | * Reset the game after a goal. |
jstephens78 | 17:3517251daf96 | 196 | * If the game will continue, re-draw and reset the pieces. |
jstephens78 | 17:3517251daf96 | 197 | * If the game is over, display end scene and then suspend the game loop until |
jstephens78 | 17:3517251daf96 | 198 | * re-launched. |
jstephens78 | 17:3517251daf96 | 199 | */ |
jstephens78 | 12:5d913b57da7c | 200 | void resetGame() |
jstephens78 | 12:5d913b57da7c | 201 | { |
jstephens78 | 17:3517251daf96 | 202 | // If game over, draw an end-game screen |
jstephens78 | 12:5d913b57da7c | 203 | if (red_score >= 5 || blue_score >= 5) { |
jstephens78 | 17:3517251daf96 | 204 | uLCD_mutex.lock(); |
jstephens78 | 12:5d913b57da7c | 205 | uLCD.cls(); |
jstephens78 | 17:3517251daf96 | 206 | uLCD.locate(5, 3); |
jstephens78 | 17:3517251daf96 | 207 | uLCD.color(GREEN); |
jstephens78 | 12:5d913b57da7c | 208 | uLCD.printf("Game Over"); |
jstephens78 | 12:5d913b57da7c | 209 | |
jstephens78 | 12:5d913b57da7c | 210 | if (red_score > blue_score) { |
jstephens78 | 17:3517251daf96 | 211 | uLCD.locate(5, 5); |
jstephens78 | 17:3517251daf96 | 212 | uLCD.color(RED); |
jstephens78 | 17:3517251daf96 | 213 | uLCD.printf("Red Wins!"); |
jstephens78 | 12:5d913b57da7c | 214 | } else { |
jstephens78 | 17:3517251daf96 | 215 | uLCD.locate(5, 5); |
jstephens78 | 17:3517251daf96 | 216 | uLCD.color(BLUE); |
jstephens78 | 17:3517251daf96 | 217 | uLCD.printf("Blue Wins!"); |
jstephens78 | 9:4e6fae5f9b23 | 218 | } |
jstephens78 | 9:4e6fae5f9b23 | 219 | |
jstephens78 | 12:5d913b57da7c | 220 | Thread::wait(2000); |
jstephens78 | 12:5d913b57da7c | 221 | |
jstephens78 | 12:5d913b57da7c | 222 | game2 = false; |
jstephens78 | 17:3517251daf96 | 223 | uLCD_mutex.unlock(); |
jstephens78 | 17:3517251daf96 | 224 | } |
jstephens78 | 17:3517251daf96 | 225 | |
jstephens78 | 17:3517251daf96 | 226 | // Otherwise re-draw the game board and reset the pieces |
jstephens78 | 17:3517251daf96 | 227 | else { |
jstephens78 | 12:5d913b57da7c | 228 | drawStaticEnvironment(); |
jstephens78 | 9:4e6fae5f9b23 | 229 | |
jstephens78 | 12:5d913b57da7c | 230 | puck->position.x = SCREEN_WIDTH/2; |
jstephens78 | 17:3517251daf96 | 231 | puck->position.y = _HOCKEY_ARENA_MID; |
jstephens78 | 17:3517251daf96 | 232 | puck->velocity.x = HOCKEY_PUCK_VELOCITY * (serve_direction ? 1 : -1); |
jstephens78 | 17:3517251daf96 | 233 | puck->velocity.y = (float)(rand() % 50) / 100; |
jstephens78 | 17:3517251daf96 | 234 | |
jstephens78 | 12:5d913b57da7c | 235 | paddle_a->position.x = 32; |
jstephens78 | 17:3517251daf96 | 236 | paddle_a->position.y = _HOCKEY_ARENA_MID; |
jstephens78 | 12:5d913b57da7c | 237 | SetPhysicsBodyRotation(paddle_a, 0); |
jstephens78 | 12:5d913b57da7c | 238 | |
jstephens78 | 12:5d913b57da7c | 239 | paddle_b->position.x = 96; |
jstephens78 | 17:3517251daf96 | 240 | paddle_b->position.y = _HOCKEY_ARENA_MID; |
jstephens78 | 12:5d913b57da7c | 241 | SetPhysicsBodyRotation(paddle_b, 0); |
jstephens78 | 12:5d913b57da7c | 242 | } |
jstephens78 | 12:5d913b57da7c | 243 | } |
jstephens78 | 12:5d913b57da7c | 244 | |
jstephens78 | 12:5d913b57da7c | 245 | /** |
jstephens78 | 17:3517251daf96 | 246 | * Handles puck bouncing off walls, goal scoring, player input, and end-game |
jstephens78 | 17:3517251daf96 | 247 | * conditions |
jstephens78 | 12:5d913b57da7c | 248 | */ |
jstephens78 | 12:5d913b57da7c | 249 | void runGameLogic() |
jstephens78 | 12:5d913b57da7c | 250 | { |
jstephens78 | 12:5d913b57da7c | 251 | // If puck hits the ceiling or floor, reflect across the y component of |
jstephens78 | 12:5d913b57da7c | 252 | // the velocity |
jstephens78 | 12:5d913b57da7c | 253 | if (puck->position.y < HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1) { |
jstephens78 | 12:5d913b57da7c | 254 | puck->velocity.y *= -1; |
jstephens78 | 12:5d913b57da7c | 255 | puck->position.y = maxOf( |
jstephens78 | 12:5d913b57da7c | 256 | puck->position.y, |
jstephens78 | 12:5d913b57da7c | 257 | HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1); |
jstephens78 | 12:5d913b57da7c | 258 | } else if (puck->position.y > HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1) { |
jstephens78 | 12:5d913b57da7c | 259 | puck->velocity.y *= -1; |
jstephens78 | 12:5d913b57da7c | 260 | puck->position.y = minOf( |
jstephens78 | 12:5d913b57da7c | 261 | puck->position.y, |
jstephens78 | 12:5d913b57da7c | 262 | HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1); |
jstephens78 | 12:5d913b57da7c | 263 | } |
jstephens78 | 12:5d913b57da7c | 264 | |
jstephens78 | 12:5d913b57da7c | 265 | // true if the puck is in the y range corresponding to the goal |
jstephens78 | 12:5d913b57da7c | 266 | bool puckInGoalRange = |
jstephens78 | 12:5d913b57da7c | 267 | puck->position.y > _HOCKEY_GOAL_TOP && |
jstephens78 | 12:5d913b57da7c | 268 | puck->position.y < _HOCKEY_GOAL_BOT; |
jstephens78 | 12:5d913b57da7c | 269 | |
jstephens78 | 12:5d913b57da7c | 270 | // Puck collides with left or right walls |
jstephens78 | 12:5d913b57da7c | 271 | if (puckInGoalRange == false) { |
jstephens78 | 17:3517251daf96 | 272 | if (puck->position.x < HOCKEY_PUCK_RADIUS + 1 && puck->position.x > 0) { |
jstephens78 | 12:5d913b57da7c | 273 | puck->velocity.x *= -1; |
jstephens78 | 12:5d913b57da7c | 274 | puck->position.x = maxOf( |
jstephens78 | 12:5d913b57da7c | 275 | puck->position.x, |
jstephens78 | 12:5d913b57da7c | 276 | HOCKEY_PUCK_RADIUS + 1); |
jstephens78 | 17:3517251daf96 | 277 | } else if (puck->position.x > SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 1 && puck->position.x < SCREEN_WIDTH) { |
jstephens78 | 12:5d913b57da7c | 278 | puck->velocity.x *= -1; |
jstephens78 | 12:5d913b57da7c | 279 | puck->position.x = minOf( |
jstephens78 | 12:5d913b57da7c | 280 | puck->position.x, |
jstephens78 | 12:5d913b57da7c | 281 | SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 2); |
jstephens78 | 9:4e6fae5f9b23 | 282 | } |
jstephens78 | 12:5d913b57da7c | 283 | } |
jstephens78 | 12:5d913b57da7c | 284 | |
jstephens78 | 12:5d913b57da7c | 285 | // Puck in goals |
jstephens78 | 12:5d913b57da7c | 286 | else { |
jstephens78 | 12:5d913b57da7c | 287 | // SCORE RED |
jstephens78 | 17:3517251daf96 | 288 | if (puck->position.x <= -HOCKEY_PUCK_RADIUS * 2) { |
jstephens78 | 12:5d913b57da7c | 289 | red_score += 1; |
jstephens78 | 17:3517251daf96 | 290 | serve_direction = 0; |
jstephens78 | 17:3517251daf96 | 291 | uLCD.locate(4, 1); |
jstephens78 | 17:3517251daf96 | 292 | uLCD.color(RED); |
jstephens78 | 17:3517251daf96 | 293 | uLCD.printf("Red Scores!"); |
jstephens78 | 12:5d913b57da7c | 294 | Thread::wait(2000); |
jstephens78 | 12:5d913b57da7c | 295 | resetGame(); |
jstephens78 | 12:5d913b57da7c | 296 | } |
jstephens78 | 12:5d913b57da7c | 297 | |
jstephens78 | 12:5d913b57da7c | 298 | // SCORE BLUE |
jstephens78 | 17:3517251daf96 | 299 | else if (puck->position.x >= SCREEN_WIDTH + HOCKEY_PUCK_RADIUS * 2) { |
jstephens78 | 12:5d913b57da7c | 300 | blue_score += 1; |
jstephens78 | 17:3517251daf96 | 301 | serve_direction = 1; |
jstephens78 | 17:3517251daf96 | 302 | uLCD.locate(3, 1); |
jstephens78 | 17:3517251daf96 | 303 | uLCD.color(BLUE); |
jstephens78 | 17:3517251daf96 | 304 | uLCD.printf("Blue Scores!"); |
jstephens78 | 12:5d913b57da7c | 305 | Thread::wait(2000); |
jstephens78 | 12:5d913b57da7c | 306 | resetGame(); |
jstephens78 | 12:5d913b57da7c | 307 | } |
jstephens78 | 12:5d913b57da7c | 308 | } |
jstephens78 | 12:5d913b57da7c | 309 | } |
jstephens78 | 12:5d913b57da7c | 310 | |
jstephens78 | 17:3517251daf96 | 311 | /** |
jstephens78 | 17:3517251daf96 | 312 | * Process user input and update game state |
jstephens78 | 17:3517251daf96 | 313 | */ |
jstephens78 | 17:3517251daf96 | 314 | void handleInput() |
jstephens78 | 17:3517251daf96 | 315 | { |
jstephens78 | 17:3517251daf96 | 316 | // Process input from the game |
jstephens78 | 17:3517251daf96 | 317 | blue.parseMessage(); |
jstephens78 | 17:3517251daf96 | 318 | if (blue.button[BUTTON_UP]) { |
jstephens78 | 17:3517251daf96 | 319 | paddle_a->position.y -= input_sensitivity; |
jstephens78 | 17:3517251daf96 | 320 | } |
jstephens78 | 17:3517251daf96 | 321 | if (blue.button[BUTTON_DOWN]) { |
jstephens78 | 17:3517251daf96 | 322 | paddle_a->position.y += input_sensitivity; |
jstephens78 | 17:3517251daf96 | 323 | } |
jstephens78 | 17:3517251daf96 | 324 | if (blue.button[BUTTON_LEFT]) { |
jstephens78 | 17:3517251daf96 | 325 | paddle_a->position.x -= input_sensitivity; |
jstephens78 | 17:3517251daf96 | 326 | } |
jstephens78 | 17:3517251daf96 | 327 | if (blue.button[BUTTON_RIGHT]) { |
jstephens78 | 17:3517251daf96 | 328 | paddle_a->position.x += input_sensitivity; |
jstephens78 | 17:3517251daf96 | 329 | } |
jstephens78 | 17:3517251daf96 | 330 | if (blue.button[BUTTON_A]) { |
jstephens78 | 17:3517251daf96 | 331 | SetPhysicsBodyRotation(paddle_a, paddle_a->orient - input_sensitivity * 0.05); |
jstephens78 | 17:3517251daf96 | 332 | } |
jstephens78 | 17:3517251daf96 | 333 | if (blue.button[BUTTON_B]) { |
jstephens78 | 17:3517251daf96 | 334 | SetPhysicsBodyRotation(paddle_a, paddle_a->orient + input_sensitivity * 0.05); |
jstephens78 | 17:3517251daf96 | 335 | } |
jstephens78 | 17:3517251daf96 | 336 | |
jsanchez307 | 23:214c0c828d98 | 337 | |
jsanchez307 | 23:214c0c828d98 | 338 | |
jsanchez307 | 23:214c0c828d98 | 339 | |
jstephens78 | 17:3517251daf96 | 340 | // Player 2 Input |
jsanchez307 | 23:214c0c828d98 | 341 | if (myNav.up()) { // Up |
jstephens78 | 17:3517251daf96 | 342 | paddle_b->position.y -= input_sensitivity; |
jstephens78 | 17:3517251daf96 | 343 | } |
jsanchez307 | 23:214c0c828d98 | 344 | if (myNav.down()) { // down |
jstephens78 | 17:3517251daf96 | 345 | paddle_b->position.y += input_sensitivity; |
jstephens78 | 17:3517251daf96 | 346 | } |
jsanchez307 | 23:214c0c828d98 | 347 | if (myNav.left()) { // left |
jstephens78 | 17:3517251daf96 | 348 | paddle_b->position.x -= input_sensitivity; |
jstephens78 | 17:3517251daf96 | 349 | } |
jsanchez307 | 23:214c0c828d98 | 350 | if (myNav.right()) { // right |
jstephens78 | 17:3517251daf96 | 351 | paddle_b->position.x += input_sensitivity; |
jstephens78 | 17:3517251daf96 | 352 | } |
jsanchez307 | 23:214c0c828d98 | 353 | if (myNav.fire()) { // rotate |
jstephens78 | 17:3517251daf96 | 354 | SetPhysicsBodyRotation(paddle_b, paddle_b->orient + 3.14159 / 4); |
jstephens78 | 17:3517251daf96 | 355 | } |
jstephens78 | 17:3517251daf96 | 356 | |
jstephens78 | 17:3517251daf96 | 357 | // Bounds checking. Don't let users steer paddles out of the arena |
jstephens78 | 17:3517251daf96 | 358 | paddle_a->position.y = clamp(paddle_a->position.y, HOCKEY_ARENA_TOP, HOCKEY_ARENA_BOT); |
jstephens78 | 17:3517251daf96 | 359 | paddle_a->position.x = clamp(paddle_a->position.x, 1, SCREEN_WIDTH - 1); |
jstephens78 | 17:3517251daf96 | 360 | |
jstephens78 | 17:3517251daf96 | 361 | paddle_b->position.y = clamp(paddle_b->position.y, HOCKEY_ARENA_TOP, HOCKEY_ARENA_BOT); |
jstephens78 | 17:3517251daf96 | 362 | paddle_b->position.x = clamp(paddle_b->position.x, 1, SCREEN_WIDTH - 1); |
jstephens78 | 17:3517251daf96 | 363 | } |
jstephens78 | 17:3517251daf96 | 364 | |
jstephens78 | 17:3517251daf96 | 365 | /** |
jstephens78 | 17:3517251daf96 | 366 | * The primary game loop for the air hockey game |
jstephens78 | 17:3517251daf96 | 367 | */ |
jstephens78 | 12:5d913b57da7c | 368 | void hockeyGame(void) |
jstephens78 | 12:5d913b57da7c | 369 | { |
jstephens78 | 17:3517251daf96 | 370 | // Set up Physac objects & simulation |
jstephens78 | 17:3517251daf96 | 371 | initPhysicsObjects(); |
jstephens78 | 17:3517251daf96 | 372 | |
jstephens78 | 20:73e4f12277bd | 373 | while (true) { |
jstephens78 | 17:3517251daf96 | 374 | // Wait until the game starts |
jstephens78 | 12:5d913b57da7c | 375 | while (game2 == false) { |
jstephens78 | 20:73e4f12277bd | 376 | |
jstephens78 | 20:73e4f12277bd | 377 | PRINTF("[HOCKEY] Idle\r\n"); |
jstephens78 | 20:73e4f12277bd | 378 | Thread::wait(500); |
jstephens78 | 9:4e6fae5f9b23 | 379 | } |
jstephens78 | 20:73e4f12277bd | 380 | |
jstephens78 | 17:3517251daf96 | 381 | // Reset game state |
jstephens78 | 12:5d913b57da7c | 382 | red_score = 0; |
jstephens78 | 12:5d913b57da7c | 383 | blue_score = 0; |
jstephens78 | 17:3517251daf96 | 384 | serve_direction = rand() % 2; |
jstephens78 | 17:3517251daf96 | 385 | resetGame(); |
jstephens78 | 9:4e6fae5f9b23 | 386 | |
jstephens78 | 12:5d913b57da7c | 387 | // Reset screen, draw arena |
jstephens78 | 12:5d913b57da7c | 388 | drawStaticEnvironment(); |
jstephens78 | 12:5d913b57da7c | 389 | |
jstephens78 | 12:5d913b57da7c | 390 | Timer timer; |
jstephens78 | 12:5d913b57da7c | 391 | timer.start(); |
jstephens78 | 12:5d913b57da7c | 392 | |
jstephens78 | 12:5d913b57da7c | 393 | while (game2) { |
jstephens78 | 12:5d913b57da7c | 394 | float dt = timer.read() * 1000; |
jstephens78 | 12:5d913b57da7c | 395 | timer.reset(); |
jstephens78 | 9:4e6fae5f9b23 | 396 | |
jstephens78 | 12:5d913b57da7c | 397 | // Update the physics of the game |
jstephens78 | 17:3517251daf96 | 398 | for (int i = 0; i < HOCKEY_PHYSICS_STEPS; i++) { |
jstephens78 | 12:5d913b57da7c | 399 | PhysicsStep(); |
jstephens78 | 17:3517251daf96 | 400 | runGameLogic(); |
jstephens78 | 17:3517251daf96 | 401 | if (game2 == false) break; |
jstephens78 | 17:3517251daf96 | 402 | } |
jstephens78 | 12:5d913b57da7c | 403 | |
jstephens78 | 17:3517251daf96 | 404 | // Exit loop early if game over after the logic step |
jstephens78 | 17:3517251daf96 | 405 | if (game2 == false) continue; |
jstephens78 | 17:3517251daf96 | 406 | |
jstephens78 | 17:3517251daf96 | 407 | handleInput(); |
jstephens78 | 9:4e6fae5f9b23 | 408 | |
jstephens78 | 12:5d913b57da7c | 409 | // Render the game |
jstephens78 | 12:5d913b57da7c | 410 | drawDynamicObjects(); |
jstephens78 | 17:3517251daf96 | 411 | |
jstephens78 | 20:73e4f12277bd | 412 | PRINTF("[HOCKEY] Delta %f\r\n", dt); |
jstephens78 | 20:73e4f12277bd | 413 | Thread::wait(100); |
jstephens78 | 12:5d913b57da7c | 414 | } |
jstephens78 | 17:3517251daf96 | 415 | } |
jstephens78 | 12:5d913b57da7c | 416 | |
jstephens78 | 17:3517251daf96 | 417 | ClosePhysics(); |
jstephens78 | 9:4e6fae5f9b23 | 418 | } |