new mods upon mods by devhammer: - Added paddle control using tilting of the console - Finished mute function - Reduced flickering See game.cpp for full info.

Dependencies:   mbed

Fork of RETRO_Pong_Mod by G. Andrew Duthie

This is a mod of the official Pong game released with the RETRO game console.

Committer:
maxint
Date:
Thu Jan 15 14:34:59 2015 +0000
Revision:
4:9ad3bc45b6ce
Parent:
3:2f09c90a732d
mod150115; - Added paddle control using tilting of the console; - Reduced flickering; - Finished mute function

Who changed what in which revision?

UserRevisionLine numberNew contents of line
devhammer 3:2f09c90a732d 1 // Updated version of the official firmware for the Outrageous Circuits RETRO
maxint 4:9ad3bc45b6ce 2 //
maxint 4:9ad3bc45b6ce 3 // mod150106 - Modified by G. Andrew Duthie (devhammer)
devhammer 3:2f09c90a732d 4 // Changes:
devhammer 3:2f09c90a732d 5 // - Added sounds for all ball bounces
devhammer 3:2f09c90a732d 6 // - Changed ball from square to circle
devhammer 3:2f09c90a732d 7 // - Adjusted collision detection to add ball speed every 10 paddle hits
devhammer 3:2f09c90a732d 8 // - Added scoring
devhammer 3:2f09c90a732d 9 // - Added mute function (not fully implemented...needs to be set up on a button).
maxint 4:9ad3bc45b6ce 10 //
maxint 4:9ad3bc45b6ce 11 // mod150115 - Modified by Maxint
maxint 4:9ad3bc45b6ce 12 // Changes:
maxint 4:9ad3bc45b6ce 13 // - Upped the I2C frequency to make the Accelerometer useable in actual gameplay
maxint 4:9ad3bc45b6ce 14 // - Added paddle control using tilting of the console
maxint 4:9ad3bc45b6ce 15 // - Changed left-right button control to make it a bit more logical
maxint 4:9ad3bc45b6ce 16 // - tied mute function to the circle button and added el cheapo debouncing
maxint 4:9ad3bc45b6ce 17 // - reduced flickering by only redrawing paddle and ball when changed position
devhammer 3:2f09c90a732d 18
john_ghielec 1:cd8a3926f263 19 #include "Game.h"
john_ghielec 1:cd8a3926f263 20
john_ghielec 1:cd8a3926f263 21 const char* Game::LOSE_1 = "You lose.";
john_ghielec 1:cd8a3926f263 22 const char* Game::LOSE_2 = "Press ship to restart.";
john_ghielec 2:6ab46f2e851a 23 const char* Game::SPLASH_1 = "Press ship to start.";
john_ghielec 2:6ab46f2e851a 24 const char* Game::SPLASH_2 = "Press robot to switch.";
devhammer 3:2f09c90a732d 25 const char* Game::LIVES = "Lives: ";
devhammer 3:2f09c90a732d 26 const char* Game::SCORE = "Score: ";
john_ghielec 1:cd8a3926f263 27
john_ghielec 1:cd8a3926f263 28 Game::Game() : left(P0_14, PullUp), right(P0_11, PullUp), down(P0_12, PullUp), up(P0_13, PullUp), square(P0_16, PullUp), circle(P0_1, PullUp), led1(P0_9), led2(P0_8), pwm(P0_18), ain(P0_15), i2c(P0_5, P0_4) {
john_ghielec 1:cd8a3926f263 29 srand(this->ain.read_u16());
john_ghielec 1:cd8a3926f263 30
john_ghielec 2:6ab46f2e851a 31 this->lastUp = false;
john_ghielec 2:6ab46f2e851a 32 this->lastDown = false;
maxint 4:9ad3bc45b6ce 33 this->mode = true; // true=game, false=accelerometer
john_ghielec 2:6ab46f2e851a 34
maxint 4:9ad3bc45b6ce 35 //this->i2c.frequency(400); // Really? Is this a joke? 400 Hz is much too slow. Reading the XYZ now takes 210 ms
maxint 4:9ad3bc45b6ce 36 this->i2c.frequency(400000); // fast I2C is 400 KHz, not 400 Hz. Default frequency is 100 KHz, but the faster, the less delay...
maxint 4:9ad3bc45b6ce 37
john_ghielec 2:6ab46f2e851a 38 this->writeRegister(0x2A, 0x01);
john_ghielec 2:6ab46f2e851a 39
john_ghielec 2:6ab46f2e851a 40 this->colors[0] = DisplayN18::RED;
john_ghielec 2:6ab46f2e851a 41 this->colors[1] = DisplayN18::GREEN;
john_ghielec 2:6ab46f2e851a 42 this->colors[2] = DisplayN18::BLUE;
john_ghielec 2:6ab46f2e851a 43
john_ghielec 1:cd8a3926f263 44 this->initialize();
john_ghielec 1:cd8a3926f263 45 }
john_ghielec 1:cd8a3926f263 46
john_ghielec 2:6ab46f2e851a 47 void Game::readRegisters(char address, char* buffer, int len) {
john_ghielec 2:6ab46f2e851a 48 this->i2c.write(Game::I2C_ADDR, &address, 1, true);
john_ghielec 2:6ab46f2e851a 49 this->i2c.read(Game::I2C_ADDR | 1, buffer, len);
john_ghielec 2:6ab46f2e851a 50 }
john_ghielec 2:6ab46f2e851a 51
john_ghielec 2:6ab46f2e851a 52 int Game::writeRegister(char address, char value) {
john_ghielec 2:6ab46f2e851a 53 char buffer[2] = { address, value };
john_ghielec 2:6ab46f2e851a 54
john_ghielec 2:6ab46f2e851a 55 return this->i2c.write(Game::I2C_ADDR, buffer, 2);
john_ghielec 2:6ab46f2e851a 56 }
john_ghielec 2:6ab46f2e851a 57
john_ghielec 2:6ab46f2e851a 58 double Game::convert(char* buffer) {
john_ghielec 2:6ab46f2e851a 59 double val = ((buffer[0] << 2) | (buffer[1] >> 6));
john_ghielec 2:6ab46f2e851a 60
john_ghielec 2:6ab46f2e851a 61 if (val > 511.0)
john_ghielec 2:6ab46f2e851a 62 val -= 1024.0;
john_ghielec 2:6ab46f2e851a 63
john_ghielec 2:6ab46f2e851a 64 return val / 512.0;
john_ghielec 2:6ab46f2e851a 65 }
john_ghielec 2:6ab46f2e851a 66
john_ghielec 2:6ab46f2e851a 67 void Game::getXYZ(double& x, double& y, double& z) {
john_ghielec 2:6ab46f2e851a 68 char buffer[6];
john_ghielec 2:6ab46f2e851a 69
john_ghielec 2:6ab46f2e851a 70 this->readRegisters(0x01, buffer, 6);
john_ghielec 2:6ab46f2e851a 71
john_ghielec 2:6ab46f2e851a 72 x = this->convert(buffer);
john_ghielec 2:6ab46f2e851a 73 y = this->convert(buffer + 2);
john_ghielec 2:6ab46f2e851a 74 z = this->convert(buffer + 4);
john_ghielec 2:6ab46f2e851a 75 }
john_ghielec 2:6ab46f2e851a 76
john_ghielec 2:6ab46f2e851a 77 void Game::printDouble(double value, int x, int y) {
john_ghielec 2:6ab46f2e851a 78 char buffer[10];
john_ghielec 2:6ab46f2e851a 79 int len = sprintf(buffer, "%.1f", value);
john_ghielec 2:6ab46f2e851a 80
john_ghielec 2:6ab46f2e851a 81 this->disp.drawString(x, y, buffer, DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 2:6ab46f2e851a 82 }
john_ghielec 2:6ab46f2e851a 83
john_ghielec 2:6ab46f2e851a 84 void Game::drawAxes() {
john_ghielec 2:6ab46f2e851a 85 for (int i = 0; i < 3; i++) {
john_ghielec 2:6ab46f2e851a 86 this->disp.drawLine(0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING), 0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT, DisplayN18::WHITE);
john_ghielec 2:6ab46f2e851a 87 this->disp.drawLine(0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT / 2, DisplayN18::WIDTH, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT / 2, DisplayN18::WHITE);
john_ghielec 2:6ab46f2e851a 88 }
john_ghielec 2:6ab46f2e851a 89 }
john_ghielec 2:6ab46f2e851a 90
john_ghielec 2:6ab46f2e851a 91 void Game::drawPoint(int axis, double value) {
john_ghielec 2:6ab46f2e851a 92 if (value < -1.0)
john_ghielec 2:6ab46f2e851a 93 value = -1.0;
john_ghielec 2:6ab46f2e851a 94
john_ghielec 2:6ab46f2e851a 95 if (value > 1.0)
john_ghielec 2:6ab46f2e851a 96 value = 1.0;
john_ghielec 2:6ab46f2e851a 97
john_ghielec 2:6ab46f2e851a 98 value += 1.0;
john_ghielec 2:6ab46f2e851a 99 value /= 2.0;
john_ghielec 2:6ab46f2e851a 100 value = 1.0 - value;
john_ghielec 2:6ab46f2e851a 101 value *= Game::GRAPH_HEIGHT;
john_ghielec 2:6ab46f2e851a 102
john_ghielec 2:6ab46f2e851a 103 this->disp.setPixel(this->graphX, axis * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + (int)value, this->colors[axis]);
john_ghielec 2:6ab46f2e851a 104 }
john_ghielec 2:6ab46f2e851a 105
john_ghielec 2:6ab46f2e851a 106 void Game::checkGraphReset() {
john_ghielec 2:6ab46f2e851a 107 if (this->graphX > DisplayN18::WIDTH) {
john_ghielec 2:6ab46f2e851a 108 this->graphX = 0;
john_ghielec 2:6ab46f2e851a 109 this->disp.clear();
john_ghielec 2:6ab46f2e851a 110 this->drawAxes();
john_ghielec 2:6ab46f2e851a 111 }
john_ghielec 2:6ab46f2e851a 112 }
john_ghielec 2:6ab46f2e851a 113
john_ghielec 1:cd8a3926f263 114 void Game::initialize() {
john_ghielec 1:cd8a3926f263 115 this->initializeBall();
john_ghielec 1:cd8a3926f263 116
john_ghielec 1:cd8a3926f263 117 this->paddleX = DisplayN18::WIDTH / 2 - Game::PADDLE_WIDTH / 2;
maxint 4:9ad3bc45b6ce 118 this->paddleXprev=this->paddleX;
john_ghielec 1:cd8a3926f263 119 this->pwmTicksLeft = 0;
john_ghielec 1:cd8a3926f263 120 this->lives = 4;
devhammer 3:2f09c90a732d 121 this->score = 0;
devhammer 3:2f09c90a732d 122 this->muted = false;
john_ghielec 1:cd8a3926f263 123
devhammer 3:2f09c90a732d 124 this->pwm.period(1);
john_ghielec 1:cd8a3926f263 125 this->pwm.write(0.00);
john_ghielec 1:cd8a3926f263 126
john_ghielec 1:cd8a3926f263 127 this->disp.clear();
john_ghielec 1:cd8a3926f263 128 }
john_ghielec 1:cd8a3926f263 129
john_ghielec 1:cd8a3926f263 130 void Game::initializeBall() {
john_ghielec 1:cd8a3926f263 131 this->ballX = DisplayN18::WIDTH / 2 - Game::BALL_RADIUS;
john_ghielec 1:cd8a3926f263 132 this->ballY = DisplayN18::HEIGHT / 4 - Game::BALL_RADIUS;
maxint 4:9ad3bc45b6ce 133 this->ballXprev=this->ballX;
maxint 4:9ad3bc45b6ce 134 this->ballYprev=this->ballY;
john_ghielec 1:cd8a3926f263 135
devhammer 3:2f09c90a732d 136 this->ballSpeedX = Game::BALL_STARTING_SPEED;
devhammer 3:2f09c90a732d 137 this->ballSpeedY = Game::BALL_STARTING_SPEED;
devhammer 3:2f09c90a732d 138
devhammer 3:2f09c90a732d 139 this->ballSpeedX *= (rand() % 2 ? 1 : -1);
devhammer 3:2f09c90a732d 140 this->ballSpeedY *= (rand() % 2 ? 1 : -1);
john_ghielec 2:6ab46f2e851a 141 }
john_ghielec 2:6ab46f2e851a 142
john_ghielec 2:6ab46f2e851a 143 void Game::tick() {
john_ghielec 2:6ab46f2e851a 144 this->checkButtons();
john_ghielec 1:cd8a3926f263 145
john_ghielec 2:6ab46f2e851a 146 if (this->mode) {
maxint 4:9ad3bc45b6ce 147 //this->clearPaddle();
maxint 4:9ad3bc45b6ce 148 //this->clearBall();
john_ghielec 2:6ab46f2e851a 149
john_ghielec 2:6ab46f2e851a 150 this->updatePaddle();
john_ghielec 2:6ab46f2e851a 151 this->updateBall();
john_ghielec 1:cd8a3926f263 152
john_ghielec 2:6ab46f2e851a 153 this->checkCollision();
john_ghielec 2:6ab46f2e851a 154
maxint 4:9ad3bc45b6ce 155 this->redrawPaddle();
maxint 4:9ad3bc45b6ce 156 this->redrawBall();
john_ghielec 2:6ab46f2e851a 157
john_ghielec 2:6ab46f2e851a 158 this->checkPwm();
john_ghielec 2:6ab46f2e851a 159 this->checkLives();
john_ghielec 2:6ab46f2e851a 160
john_ghielec 2:6ab46f2e851a 161 wait_ms(25);
john_ghielec 2:6ab46f2e851a 162 }
john_ghielec 2:6ab46f2e851a 163 else {
john_ghielec 2:6ab46f2e851a 164 double x, y, z;
john_ghielec 2:6ab46f2e851a 165
john_ghielec 2:6ab46f2e851a 166 this->getXYZ(x, y, z);
john_ghielec 2:6ab46f2e851a 167
john_ghielec 2:6ab46f2e851a 168 this->checkGraphReset();
john_ghielec 2:6ab46f2e851a 169 this->drawPoint(0, x);
john_ghielec 2:6ab46f2e851a 170 this->drawPoint(1, y);
john_ghielec 2:6ab46f2e851a 171 this->drawPoint(2, z);
john_ghielec 2:6ab46f2e851a 172 this->graphX++;
maxint 4:9ad3bc45b6ce 173
maxint 4:9ad3bc45b6ce 174 wait_ms(100); // added delay after upping the I2C frequency to a usable value
john_ghielec 2:6ab46f2e851a 175 }
john_ghielec 1:cd8a3926f263 176 }
john_ghielec 1:cd8a3926f263 177
maxint 4:9ad3bc45b6ce 178
maxint 4:9ad3bc45b6ce 179 int Game::checkTilt()
maxint 4:9ad3bc45b6ce 180 { // check the orientation of the console to allow tilt-control
maxint 4:9ad3bc45b6ce 181 double x, y, z;
maxint 4:9ad3bc45b6ce 182
maxint 4:9ad3bc45b6ce 183 this->getXYZ(x, y, z);
maxint 4:9ad3bc45b6ce 184
maxint 4:9ad3bc45b6ce 185 if(x<-0.07) return(-1); // Using 0.1 requires too much an angle for nice gameplay. 0.07 is more subtle.
maxint 4:9ad3bc45b6ce 186 else if(x>0.07) return(1);
maxint 4:9ad3bc45b6ce 187 else return(0);
maxint 4:9ad3bc45b6ce 188 }
maxint 4:9ad3bc45b6ce 189
john_ghielec 2:6ab46f2e851a 190 void Game::checkButtons() {
john_ghielec 2:6ab46f2e851a 191 if (!this->square.read()) {
john_ghielec 2:6ab46f2e851a 192 this->mode = !this->mode;
john_ghielec 2:6ab46f2e851a 193
john_ghielec 2:6ab46f2e851a 194 this->disp.clear();
john_ghielec 2:6ab46f2e851a 195
john_ghielec 2:6ab46f2e851a 196 if (!this->mode) {
john_ghielec 2:6ab46f2e851a 197 this->graphX = 0;
john_ghielec 2:6ab46f2e851a 198
john_ghielec 2:6ab46f2e851a 199 this->drawAxes();
john_ghielec 2:6ab46f2e851a 200 }
john_ghielec 2:6ab46f2e851a 201
maxint 4:9ad3bc45b6ce 202 this->led1.write(!this->mode);
maxint 4:9ad3bc45b6ce 203 }
maxint 4:9ad3bc45b6ce 204 else if(!this->circle.read()) {
maxint 4:9ad3bc45b6ce 205 // use ship-button to mute
maxint 4:9ad3bc45b6ce 206 this->muted = !this->muted;
maxint 4:9ad3bc45b6ce 207 this->led2.write(this->muted);
maxint 4:9ad3bc45b6ce 208 wait_ms(250); // el-cheapo deboounce
maxint 4:9ad3bc45b6ce 209 }
john_ghielec 2:6ab46f2e851a 210
john_ghielec 2:6ab46f2e851a 211 bool xDir = this->ballSpeedX > 0;
john_ghielec 2:6ab46f2e851a 212 bool yDir = this->ballSpeedY > 0;
john_ghielec 2:6ab46f2e851a 213 bool isUp = !this->up.read();
john_ghielec 2:6ab46f2e851a 214 bool isDown = !this->down.read();
john_ghielec 1:cd8a3926f263 215
john_ghielec 2:6ab46f2e851a 216 if (isUp && isDown) goto end;
john_ghielec 2:6ab46f2e851a 217 if (!isUp && !isDown) goto end;
john_ghielec 2:6ab46f2e851a 218
john_ghielec 2:6ab46f2e851a 219 if (isUp && this->lastUp) goto end;
john_ghielec 2:6ab46f2e851a 220 if (isDown && this->lastDown) goto end;
john_ghielec 2:6ab46f2e851a 221
john_ghielec 2:6ab46f2e851a 222 if (!xDir) this->ballSpeedX *= -1;
john_ghielec 2:6ab46f2e851a 223 if (!yDir) this->ballSpeedY *= -1;
john_ghielec 1:cd8a3926f263 224
john_ghielec 2:6ab46f2e851a 225 if (isUp) {
john_ghielec 2:6ab46f2e851a 226 if (++this->ballSpeedX > 5) this->ballSpeedX = 5;
john_ghielec 2:6ab46f2e851a 227 if (++this->ballSpeedY > 5) this->ballSpeedY = 5;
john_ghielec 2:6ab46f2e851a 228 }
john_ghielec 2:6ab46f2e851a 229 else if (isDown) {
john_ghielec 2:6ab46f2e851a 230 if (--this->ballSpeedX == 0) this->ballSpeedX = 1;
john_ghielec 2:6ab46f2e851a 231 if (--this->ballSpeedY == 0) this->ballSpeedY = 1;
john_ghielec 2:6ab46f2e851a 232 }
john_ghielec 1:cd8a3926f263 233
john_ghielec 2:6ab46f2e851a 234 if (!xDir) this->ballSpeedX *= -1;
john_ghielec 2:6ab46f2e851a 235 if (!yDir) this->ballSpeedY *= -1;
john_ghielec 2:6ab46f2e851a 236
john_ghielec 2:6ab46f2e851a 237 end:
john_ghielec 2:6ab46f2e851a 238 this->lastUp = isUp;
john_ghielec 2:6ab46f2e851a 239 this->lastDown = isDown;
john_ghielec 1:cd8a3926f263 240 }
john_ghielec 1:cd8a3926f263 241
john_ghielec 1:cd8a3926f263 242 void Game::drawString(const char* str, int y) {
john_ghielec 1:cd8a3926f263 243 this->disp.drawString(DisplayN18::WIDTH / 2 - (DisplayN18::CHAR_WIDTH + DisplayN18::CHAR_SPACING) * strlen(str) / 2, y, str, DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 244 }
john_ghielec 1:cd8a3926f263 245
john_ghielec 1:cd8a3926f263 246 void Game::showSplashScreen() {
john_ghielec 2:6ab46f2e851a 247 this->drawString(Game::SPLASH_1, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2);
john_ghielec 2:6ab46f2e851a 248 this->drawString(Game::SPLASH_2, DisplayN18::HEIGHT / 2 + DisplayN18::CHAR_HEIGHT / 2);
john_ghielec 1:cd8a3926f263 249
john_ghielec 1:cd8a3926f263 250 while (this->circle.read())
john_ghielec 1:cd8a3926f263 251 wait_ms(1);
maxint 4:9ad3bc45b6ce 252 wait_ms(250); // el-cheapo deboounce
john_ghielec 1:cd8a3926f263 253
john_ghielec 1:cd8a3926f263 254 this->disp.clear();
john_ghielec 1:cd8a3926f263 255 }
john_ghielec 1:cd8a3926f263 256
john_ghielec 1:cd8a3926f263 257 void Game::clearPaddle() {
john_ghielec 1:cd8a3926f263 258 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 259 }
john_ghielec 1:cd8a3926f263 260
john_ghielec 1:cd8a3926f263 261 void Game::drawPaddle() {
john_ghielec 1:cd8a3926f263 262 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLUE);
john_ghielec 1:cd8a3926f263 263 }
john_ghielec 1:cd8a3926f263 264
maxint 4:9ad3bc45b6ce 265 void Game::redrawPaddle()
maxint 4:9ad3bc45b6ce 266 { // draw the paddle, but only clear when changed to reduce flickering
maxint 4:9ad3bc45b6ce 267 if(this->paddleXprev!=this->paddleX)
maxint 4:9ad3bc45b6ce 268 {
maxint 4:9ad3bc45b6ce 269 this->disp.fillRect(this->paddleXprev, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLACK);
maxint 4:9ad3bc45b6ce 270 }
maxint 4:9ad3bc45b6ce 271 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLUE);
maxint 4:9ad3bc45b6ce 272 }
maxint 4:9ad3bc45b6ce 273
john_ghielec 1:cd8a3926f263 274 void Game::updatePaddle() {
maxint 4:9ad3bc45b6ce 275 // see if the paddle position needs changing
maxint 4:9ad3bc45b6ce 276 this->paddleXprev=this->paddleX;
maxint 4:9ad3bc45b6ce 277 if(!this->left.read()) // note: button.read() is LOW (0) when button pressed
maxint 4:9ad3bc45b6ce 278 this->paddleX -= Game::PADDLE_SPEED;
maxint 4:9ad3bc45b6ce 279 else if(!this->right.read())
john_ghielec 1:cd8a3926f263 280 this->paddleX += Game::PADDLE_SPEED;
maxint 4:9ad3bc45b6ce 281 else
maxint 4:9ad3bc45b6ce 282 {
maxint 4:9ad3bc45b6ce 283 int nTilt=this->checkTilt(); // don't call too often as this I2C is slow and will delay the game
maxint 4:9ad3bc45b6ce 284 if(nTilt>0)
maxint 4:9ad3bc45b6ce 285 this->paddleX += Game::PADDLE_SPEED;
maxint 4:9ad3bc45b6ce 286 else if(nTilt<0)
maxint 4:9ad3bc45b6ce 287 this->paddleX -= Game::PADDLE_SPEED;
maxint 4:9ad3bc45b6ce 288 }
john_ghielec 1:cd8a3926f263 289 }
john_ghielec 1:cd8a3926f263 290
john_ghielec 1:cd8a3926f263 291 void Game::clearBall() {
devhammer 3:2f09c90a732d 292 //this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::BLACK);
devhammer 3:2f09c90a732d 293 //this->disp.fillCircle(this->ballX - Game::BALL_RADIUS, this->ballY - Game::BALL_RADIUS, Game::BALL_RADIUS, DisplayN18::BLACK);
devhammer 3:2f09c90a732d 294 this->disp.fillCircle(this->ballX, this->ballY, Game::BALL_RADIUS, DisplayN18::BLACK);
devhammer 3:2f09c90a732d 295 this->disp.setPixel(this->ballX, this->ballY, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 296 }
john_ghielec 1:cd8a3926f263 297
maxint 4:9ad3bc45b6ce 298 void Game::clearBallPrev()
maxint 4:9ad3bc45b6ce 299 { // clear the ball from previous position
maxint 4:9ad3bc45b6ce 300 this->disp.fillCircle(this->ballXprev, this->ballYprev, Game::BALL_RADIUS, DisplayN18::BLACK);
maxint 4:9ad3bc45b6ce 301 this->disp.setPixel(this->ballXprev, this->ballYprev, DisplayN18::BLACK);
maxint 4:9ad3bc45b6ce 302 }
maxint 4:9ad3bc45b6ce 303
john_ghielec 1:cd8a3926f263 304 void Game::drawBall() {
devhammer 3:2f09c90a732d 305 //this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::RED);
devhammer 3:2f09c90a732d 306 //this->disp.fillCircle(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS, DisplayN18::RED);
devhammer 3:2f09c90a732d 307 this->disp.fillCircle(this->ballX, ballY, Game::BALL_RADIUS, DisplayN18::RED);
devhammer 3:2f09c90a732d 308 this->disp.setPixel(this->ballX, this->ballY, DisplayN18::GREEN);
john_ghielec 1:cd8a3926f263 309 }
john_ghielec 1:cd8a3926f263 310
maxint 4:9ad3bc45b6ce 311 void Game::redrawBall()
maxint 4:9ad3bc45b6ce 312 { // redraw the ball, but only clear when changed to reduce flickering
maxint 4:9ad3bc45b6ce 313 if(this->ballX!=this->ballXprev || this->ballY!=this->ballYprev)
maxint 4:9ad3bc45b6ce 314 {
maxint 4:9ad3bc45b6ce 315 this->disp.fillCircle(this->ballXprev, this->ballYprev, Game::BALL_RADIUS, DisplayN18::BLACK);
maxint 4:9ad3bc45b6ce 316 this->disp.setPixel(this->ballXprev, this->ballYprev, DisplayN18::BLACK);
maxint 4:9ad3bc45b6ce 317 }
maxint 4:9ad3bc45b6ce 318 this->disp.fillCircle(this->ballX, ballY, Game::BALL_RADIUS, DisplayN18::RED);
maxint 4:9ad3bc45b6ce 319 this->disp.setPixel(this->ballX, this->ballY, DisplayN18::GREEN);
maxint 4:9ad3bc45b6ce 320 }
maxint 4:9ad3bc45b6ce 321
john_ghielec 1:cd8a3926f263 322 void Game::updateBall() {
maxint 4:9ad3bc45b6ce 323 this->ballXprev=this->ballX;
maxint 4:9ad3bc45b6ce 324 this->ballYprev=this->ballY;
john_ghielec 1:cd8a3926f263 325 this->ballX += this->ballSpeedX;
john_ghielec 1:cd8a3926f263 326 this->ballY += this->ballSpeedY;
john_ghielec 1:cd8a3926f263 327 }
john_ghielec 1:cd8a3926f263 328
john_ghielec 1:cd8a3926f263 329 void Game::checkCollision() {
john_ghielec 1:cd8a3926f263 330 if (this->paddleX < 0)
john_ghielec 1:cd8a3926f263 331 this->paddleX = 0;
john_ghielec 1:cd8a3926f263 332
john_ghielec 1:cd8a3926f263 333 if (this->paddleX + Game::PADDLE_WIDTH > DisplayN18::WIDTH)
john_ghielec 1:cd8a3926f263 334 this->paddleX = DisplayN18::WIDTH - Game::PADDLE_WIDTH;
john_ghielec 1:cd8a3926f263 335
devhammer 3:2f09c90a732d 336 //if ((this->ballX - Game::BALL_RADIUS < 0 && this->ballSpeedX < 0) || (this->ballX + Game::BALL_RADIUS >= DisplayN18::WIDTH && this->ballSpeedX > 0)) {
devhammer 3:2f09c90a732d 337 if ((this->ballX - Game::BALL_RADIUS < 0 && this->ballSpeedX < 0) || (this->ballX + Game::BALL_RADIUS * 2 >= DisplayN18::WIDTH && this->ballSpeedX > 0)) {
john_ghielec 1:cd8a3926f263 338 this->ballSpeedX *= -1;
devhammer 3:2f09c90a732d 339 if(!this->muted) {
devhammer 3:2f09c90a732d 340 this->pwm.period_ms(2);
devhammer 3:2f09c90a732d 341 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS;
devhammer 3:2f09c90a732d 342 }
devhammer 3:2f09c90a732d 343 }
john_ghielec 1:cd8a3926f263 344
devhammer 3:2f09c90a732d 345 if (this->ballY - Game::BALL_RADIUS < (0 + DisplayN18::CHAR_HEIGHT) && this->ballSpeedY < 0){
john_ghielec 1:cd8a3926f263 346 this->ballSpeedY *= -1;
devhammer 3:2f09c90a732d 347 if(!this->muted) {
devhammer 3:2f09c90a732d 348 this->pwm.period_ms(2);
devhammer 3:2f09c90a732d 349 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS;
devhammer 3:2f09c90a732d 350 }
devhammer 3:2f09c90a732d 351 }
john_ghielec 1:cd8a3926f263 352
john_ghielec 1:cd8a3926f263 353 if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT - Game::PADDLE_HEIGHT && this->ballSpeedY > 0) {
john_ghielec 1:cd8a3926f263 354 if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT) {
maxint 4:9ad3bc45b6ce 355 this->clearBallPrev();
john_ghielec 1:cd8a3926f263 356 this->initializeBall();
john_ghielec 1:cd8a3926f263 357
john_ghielec 1:cd8a3926f263 358 this->lives--;
devhammer 3:2f09c90a732d 359
devhammer 3:2f09c90a732d 360 if(this->lives > 0) {
devhammer 3:2f09c90a732d 361 if(!this->muted) {
devhammer 3:2f09c90a732d 362 this->pwm.period(1.0/220);
devhammer 3:2f09c90a732d 363 this->pwm.write(0.5);
devhammer 3:2f09c90a732d 364 wait_ms(150);
devhammer 3:2f09c90a732d 365 this->pwm.write(0.0);
devhammer 3:2f09c90a732d 366 }
devhammer 3:2f09c90a732d 367 }
devhammer 3:2f09c90a732d 368
john_ghielec 1:cd8a3926f263 369 }
john_ghielec 1:cd8a3926f263 370 else if (this->ballX > this->paddleX && this->ballX < this->paddleX + Game::PADDLE_WIDTH) {
john_ghielec 1:cd8a3926f263 371 this->ballSpeedY *= -1;
john_ghielec 1:cd8a3926f263 372
devhammer 3:2f09c90a732d 373 if(!this->muted){
devhammer 3:2f09c90a732d 374 this->pwm.period_ms(1);
devhammer 3:2f09c90a732d 375 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS;
devhammer 3:2f09c90a732d 376 }
devhammer 3:2f09c90a732d 377 this->score = this->score + 10;
devhammer 3:2f09c90a732d 378 if(this->score % 100 == 0) {
devhammer 3:2f09c90a732d 379 if(this->ballSpeedX < 0){
devhammer 3:2f09c90a732d 380 this->ballSpeedX -= 1;
devhammer 3:2f09c90a732d 381 }
devhammer 3:2f09c90a732d 382 else {
devhammer 3:2f09c90a732d 383 this->ballSpeedX += 1;
devhammer 3:2f09c90a732d 384 }
devhammer 3:2f09c90a732d 385 this->ballSpeedY -= 1;
devhammer 3:2f09c90a732d 386 }
john_ghielec 1:cd8a3926f263 387 }
john_ghielec 1:cd8a3926f263 388 }
devhammer 3:2f09c90a732d 389 char buf[10];
devhammer 3:2f09c90a732d 390 int a = this->score;
devhammer 3:2f09c90a732d 391 sprintf(buf, "%d", a);
devhammer 3:2f09c90a732d 392 this->disp.drawString(DisplayN18::WIDTH - (DisplayN18::CHAR_WIDTH * 12), 0, Game::SCORE, DisplayN18::WHITE, DisplayN18::BLACK);
devhammer 3:2f09c90a732d 393 this->disp.drawString(DisplayN18::WIDTH - (DisplayN18::CHAR_WIDTH * 4), 0, buf, DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 394 }
john_ghielec 1:cd8a3926f263 395
john_ghielec 1:cd8a3926f263 396 void Game::checkPwm() {
john_ghielec 1:cd8a3926f263 397 if (this->pwmTicksLeft == 0) {
devhammer 3:2f09c90a732d 398 this->pwm.write(0.0);
john_ghielec 1:cd8a3926f263 399 }
john_ghielec 1:cd8a3926f263 400 else {
john_ghielec 1:cd8a3926f263 401 this->pwmTicksLeft--;
john_ghielec 1:cd8a3926f263 402 this->pwm.write(0.5);
john_ghielec 1:cd8a3926f263 403 }
john_ghielec 1:cd8a3926f263 404 }
john_ghielec 1:cd8a3926f263 405
john_ghielec 1:cd8a3926f263 406 void Game::checkLives() {
john_ghielec 1:cd8a3926f263 407 if (this->lives == 0) {
john_ghielec 1:cd8a3926f263 408 this->disp.clear();
devhammer 3:2f09c90a732d 409
john_ghielec 1:cd8a3926f263 410 this->drawString(Game::LOSE_1, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT);
john_ghielec 1:cd8a3926f263 411 this->drawString(Game::LOSE_2, DisplayN18::HEIGHT / 2);
john_ghielec 1:cd8a3926f263 412
devhammer 3:2f09c90a732d 413 if(!this->muted) {
devhammer 3:2f09c90a732d 414 this->pwm.period(1.0/220);
devhammer 3:2f09c90a732d 415 this->pwm.write(0.5);
devhammer 3:2f09c90a732d 416 wait_ms(150);
devhammer 3:2f09c90a732d 417 this->pwm.write(0.0);
devhammer 3:2f09c90a732d 418
devhammer 3:2f09c90a732d 419 this->pwm.period(1.0/196);
devhammer 3:2f09c90a732d 420 this->pwm.write(0.5);
devhammer 3:2f09c90a732d 421 wait_ms(150);
devhammer 3:2f09c90a732d 422 this->pwm.write(0.0);
devhammer 3:2f09c90a732d 423
devhammer 3:2f09c90a732d 424 this->pwm.period(1.0/164.81);
devhammer 3:2f09c90a732d 425 this->pwm.write(0.5);
devhammer 3:2f09c90a732d 426 wait_ms(150);
devhammer 3:2f09c90a732d 427 this->pwm.write(0.0);
devhammer 3:2f09c90a732d 428 }
devhammer 3:2f09c90a732d 429
john_ghielec 1:cd8a3926f263 430 while (this->circle.read())
john_ghielec 1:cd8a3926f263 431 wait_ms(1);
john_ghielec 1:cd8a3926f263 432
john_ghielec 1:cd8a3926f263 433 this->initialize();
john_ghielec 1:cd8a3926f263 434 }
john_ghielec 1:cd8a3926f263 435 else {
devhammer 3:2f09c90a732d 436 this->disp.drawString(0, 0, Game::LIVES, DisplayN18::WHITE, DisplayN18::BLACK);
devhammer 3:2f09c90a732d 437 this->disp.drawCharacter(DisplayN18::CHAR_WIDTH * 8, 0, static_cast<char>(this->lives + '0'), DisplayN18::WHITE, DisplayN18::BLACK);
john_ghielec 1:cd8a3926f263 438 }
john_ghielec 1:cd8a3926f263 439 }