Modified version of official firmware for Outrageous Circuits' RETRO. See Game.cpp for change history.
Fork of Official_RETRO by
Game.cpp
00001 // Updated version of the official firmware for the Outrageous Circuits RETRO 00002 // Modified by G. Andrew Duthie (devhammer) 00003 // Changes: 00004 // - Added sounds for all ball bounces 00005 // - Changed ball from square to circle 00006 // - Adjusted collision detection to add ball speed every 10 paddle hits 00007 // - Added scoring 00008 // - Added mute function (not fully implemented...needs to be set up on a button). 00009 00010 #include "Game.h" 00011 00012 const char* Game::LOSE_1 = "You lose."; 00013 const char* Game::LOSE_2 = "Press ship to restart."; 00014 const char* Game::SPLASH_1 = "Press ship to start."; 00015 const char* Game::SPLASH_2 = "Press robot to switch."; 00016 const char* Game::LIVES = "Lives: "; 00017 const char* Game::SCORE = "Score: "; 00018 00019 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) { 00020 srand(this->ain.read_u16()); 00021 00022 this->lastUp = false; 00023 this->lastDown = false; 00024 this->mode = true; 00025 00026 this->i2c.frequency(400); 00027 this->writeRegister(0x2A, 0x01); 00028 00029 this->colors[0] = DisplayN18::RED; 00030 this->colors[1] = DisplayN18::GREEN; 00031 this->colors[2] = DisplayN18::BLUE; 00032 00033 this->initialize(); 00034 } 00035 00036 void Game::readRegisters(char address, char* buffer, int len) { 00037 this->i2c.write(Game::I2C_ADDR, &address, 1, true); 00038 this->i2c.read(Game::I2C_ADDR | 1, buffer, len); 00039 } 00040 00041 int Game::writeRegister(char address, char value) { 00042 char buffer[2] = { address, value }; 00043 00044 return this->i2c.write(Game::I2C_ADDR, buffer, 2); 00045 } 00046 00047 double Game::convert(char* buffer) { 00048 double val = ((buffer[0] << 2) | (buffer[1] >> 6)); 00049 00050 if (val > 511.0) 00051 val -= 1024.0; 00052 00053 return val / 512.0; 00054 } 00055 00056 void Game::getXYZ(double& x, double& y, double& z) { 00057 char buffer[6]; 00058 00059 this->readRegisters(0x01, buffer, 6); 00060 00061 x = this->convert(buffer); 00062 y = this->convert(buffer + 2); 00063 z = this->convert(buffer + 4); 00064 } 00065 00066 void Game::printDouble(double value, int x, int y) { 00067 char buffer[10]; 00068 int len = sprintf(buffer, "%.1f", value); 00069 00070 this->disp.drawString(x, y, buffer, DisplayN18::WHITE, DisplayN18::BLACK); 00071 } 00072 00073 void Game::drawAxes() { 00074 for (int i = 0; i < 3; i++) { 00075 this->disp.drawLine(0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING), 0, i * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + Game::GRAPH_HEIGHT, DisplayN18::WHITE); 00076 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); 00077 } 00078 } 00079 00080 void Game::drawPoint(int axis, double value) { 00081 if (value < -1.0) 00082 value = -1.0; 00083 00084 if (value > 1.0) 00085 value = 1.0; 00086 00087 value += 1.0; 00088 value /= 2.0; 00089 value = 1.0 - value; 00090 value *= Game::GRAPH_HEIGHT; 00091 00092 this->disp.setPixel(this->graphX, axis * (Game::GRAPH_HEIGHT + Game::GRAPH_SPACING) + (int)value, this->colors[axis]); 00093 } 00094 00095 void Game::checkGraphReset() { 00096 if (this->graphX > DisplayN18::WIDTH) { 00097 this->graphX = 0; 00098 this->disp.clear(); 00099 this->drawAxes(); 00100 } 00101 } 00102 00103 void Game::initialize() { 00104 this->initializeBall(); 00105 00106 this->paddleX = DisplayN18::WIDTH / 2 - Game::PADDLE_WIDTH / 2; 00107 this->pwmTicksLeft = 0; 00108 this->lives = 4; 00109 this->score = 0; 00110 this->muted = false; 00111 00112 this->pwm.period(1); 00113 this->pwm.write(0.00); 00114 00115 this->disp.clear(); 00116 } 00117 00118 void Game::initializeBall() { 00119 this->ballX = DisplayN18::WIDTH / 2 - Game::BALL_RADIUS; 00120 this->ballY = DisplayN18::HEIGHT / 4 - Game::BALL_RADIUS; 00121 00122 this->ballSpeedX = Game::BALL_STARTING_SPEED; 00123 this->ballSpeedY = Game::BALL_STARTING_SPEED; 00124 00125 this->ballSpeedX *= (rand() % 2 ? 1 : -1); 00126 this->ballSpeedY *= (rand() % 2 ? 1 : -1); 00127 } 00128 00129 void Game::tick() { 00130 this->checkButtons(); 00131 00132 if (this->mode) { 00133 this->clearPaddle(); 00134 this->clearBall(); 00135 00136 this->updatePaddle(); 00137 this->updateBall(); 00138 00139 this->checkCollision(); 00140 00141 this->drawPaddle(); 00142 this->drawBall(); 00143 00144 this->checkPwm(); 00145 this->checkLives(); 00146 00147 wait_ms(25); 00148 } 00149 else { 00150 double x, y, z; 00151 00152 this->getXYZ(x, y, z); 00153 00154 this->checkGraphReset(); 00155 this->drawPoint(0, x); 00156 this->drawPoint(1, y); 00157 this->drawPoint(2, z); 00158 this->graphX++; 00159 } 00160 } 00161 00162 void Game::checkButtons() { 00163 if (!this->square.read()) { 00164 //this->muted = !this->muted; 00165 this->mode = !this->mode; 00166 00167 this->disp.clear(); 00168 00169 if (!this->mode) { 00170 this->graphX = 0; 00171 00172 this->drawAxes(); 00173 } 00174 00175 //this->led1.write(this->muted); 00176 //this->led2.write(!this->muted); 00177 this->led1.write(this->mode); 00178 this->led2.write(!this->mode); 00179 } 00180 00181 bool xDir = this->ballSpeedX > 0; 00182 bool yDir = this->ballSpeedY > 0; 00183 bool isUp = !this->up.read(); 00184 bool isDown = !this->down.read(); 00185 00186 if (isUp && isDown) goto end; 00187 if (!isUp && !isDown) goto end; 00188 00189 if (isUp && this->lastUp) goto end; 00190 if (isDown && this->lastDown) goto end; 00191 00192 if (!xDir) this->ballSpeedX *= -1; 00193 if (!yDir) this->ballSpeedY *= -1; 00194 00195 if (isUp) { 00196 if (++this->ballSpeedX > 5) this->ballSpeedX = 5; 00197 if (++this->ballSpeedY > 5) this->ballSpeedY = 5; 00198 } 00199 else if (isDown) { 00200 if (--this->ballSpeedX == 0) this->ballSpeedX = 1; 00201 if (--this->ballSpeedY == 0) this->ballSpeedY = 1; 00202 } 00203 00204 if (!xDir) this->ballSpeedX *= -1; 00205 if (!yDir) this->ballSpeedY *= -1; 00206 00207 end: 00208 this->lastUp = isUp; 00209 this->lastDown = isDown; 00210 } 00211 00212 void Game::drawString(const char* str, int y) { 00213 this->disp.drawString(DisplayN18::WIDTH / 2 - (DisplayN18::CHAR_WIDTH + DisplayN18::CHAR_SPACING) * strlen(str) / 2, y, str, DisplayN18::WHITE, DisplayN18::BLACK); 00214 } 00215 00216 void Game::showSplashScreen() { 00217 this->drawString(Game::SPLASH_1, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2); 00218 this->drawString(Game::SPLASH_2, DisplayN18::HEIGHT / 2 + DisplayN18::CHAR_HEIGHT / 2); 00219 00220 while (this->circle.read()) 00221 wait_ms(1); 00222 00223 this->disp.clear(); 00224 } 00225 00226 void Game::clearPaddle() { 00227 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLACK); 00228 } 00229 00230 void Game::drawPaddle() { 00231 this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLUE); 00232 } 00233 00234 void Game::updatePaddle() { 00235 if (this->left.read()) 00236 this->paddleX += Game::PADDLE_SPEED; 00237 00238 if (this->right.read()) 00239 this->paddleX -= Game::PADDLE_SPEED; 00240 } 00241 00242 void Game::clearBall() { 00243 //this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::BLACK); 00244 //this->disp.fillCircle(this->ballX - Game::BALL_RADIUS, this->ballY - Game::BALL_RADIUS, Game::BALL_RADIUS, DisplayN18::BLACK); 00245 this->disp.fillCircle(this->ballX, this->ballY, Game::BALL_RADIUS, DisplayN18::BLACK); 00246 this->disp.setPixel(this->ballX, this->ballY, DisplayN18::BLACK); 00247 } 00248 00249 void Game::drawBall() { 00250 //this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::RED); 00251 //this->disp.fillCircle(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS, DisplayN18::RED); 00252 this->disp.fillCircle(this->ballX, ballY, Game::BALL_RADIUS, DisplayN18::RED); 00253 this->disp.setPixel(this->ballX, this->ballY, DisplayN18::GREEN); 00254 } 00255 00256 void Game::updateBall() { 00257 this->ballX += this->ballSpeedX; 00258 this->ballY += this->ballSpeedY; 00259 } 00260 00261 void Game::checkCollision() { 00262 if (this->paddleX < 0) 00263 this->paddleX = 0; 00264 00265 if (this->paddleX + Game::PADDLE_WIDTH > DisplayN18::WIDTH) 00266 this->paddleX = DisplayN18::WIDTH - Game::PADDLE_WIDTH; 00267 00268 //if ((this->ballX - Game::BALL_RADIUS < 0 && this->ballSpeedX < 0) || (this->ballX + Game::BALL_RADIUS >= DisplayN18::WIDTH && this->ballSpeedX > 0)) { 00269 if ((this->ballX - Game::BALL_RADIUS < 0 && this->ballSpeedX < 0) || (this->ballX + Game::BALL_RADIUS * 2 >= DisplayN18::WIDTH && this->ballSpeedX > 0)) { 00270 this->ballSpeedX *= -1; 00271 if(!this->muted) { 00272 this->pwm.period_ms(2); 00273 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS; 00274 } 00275 } 00276 00277 if (this->ballY - Game::BALL_RADIUS < (0 + DisplayN18::CHAR_HEIGHT) && this->ballSpeedY < 0){ 00278 this->ballSpeedY *= -1; 00279 if(!this->muted) { 00280 this->pwm.period_ms(2); 00281 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS; 00282 } 00283 } 00284 00285 if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT - Game::PADDLE_HEIGHT && this->ballSpeedY > 0) { 00286 if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT) { 00287 this->initializeBall(); 00288 00289 this->lives--; 00290 00291 if(this->lives > 0) { 00292 if(!this->muted) { 00293 this->pwm.period(1.0/220); 00294 this->pwm.write(0.5); 00295 wait_ms(150); 00296 this->pwm.write(0.0); 00297 } 00298 } 00299 00300 } 00301 else if (this->ballX > this->paddleX && this->ballX < this->paddleX + Game::PADDLE_WIDTH) { 00302 this->ballSpeedY *= -1; 00303 00304 if(!this->muted){ 00305 this->pwm.period_ms(1); 00306 this->pwmTicksLeft = Game::BOUNCE_SOUND_TICKS; 00307 } 00308 this->score = this->score + 10; 00309 if(this->score % 100 == 0) { 00310 if(this->ballSpeedX < 0){ 00311 this->ballSpeedX -= 1; 00312 } 00313 else { 00314 this->ballSpeedX += 1; 00315 } 00316 this->ballSpeedY -= 1; 00317 } 00318 } 00319 } 00320 char buf[10]; 00321 int a = this->score; 00322 sprintf(buf, "%d", a); 00323 this->disp.drawString(DisplayN18::WIDTH - (DisplayN18::CHAR_WIDTH * 12), 0, Game::SCORE, DisplayN18::WHITE, DisplayN18::BLACK); 00324 this->disp.drawString(DisplayN18::WIDTH - (DisplayN18::CHAR_WIDTH * 4), 0, buf, DisplayN18::WHITE, DisplayN18::BLACK); 00325 } 00326 00327 void Game::checkPwm() { 00328 if (this->pwmTicksLeft == 0) { 00329 this->pwm.write(0.0); 00330 } 00331 else { 00332 this->pwmTicksLeft--; 00333 this->pwm.write(0.5); 00334 } 00335 } 00336 00337 void Game::checkLives() { 00338 if (this->lives == 0) { 00339 this->disp.clear(); 00340 00341 this->drawString(Game::LOSE_1, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT); 00342 this->drawString(Game::LOSE_2, DisplayN18::HEIGHT / 2); 00343 00344 if(!this->muted) { 00345 this->pwm.period(1.0/220); 00346 this->pwm.write(0.5); 00347 wait_ms(150); 00348 this->pwm.write(0.0); 00349 00350 this->pwm.period(1.0/196); 00351 this->pwm.write(0.5); 00352 wait_ms(150); 00353 this->pwm.write(0.0); 00354 00355 this->pwm.period(1.0/164.81); 00356 this->pwm.write(0.5); 00357 wait_ms(150); 00358 this->pwm.write(0.0); 00359 } 00360 00361 while (this->circle.read()) 00362 wait_ms(1); 00363 00364 this->initialize(); 00365 } 00366 else { 00367 this->disp.drawString(0, 0, Game::LIVES, DisplayN18::WHITE, DisplayN18::BLACK); 00368 this->disp.drawCharacter(DisplayN18::CHAR_WIDTH * 8, 0, static_cast<char>(this->lives + '0'), DisplayN18::WHITE, DisplayN18::BLACK); 00369 } 00370 }
Generated on Sat Jul 16 2022 11:28:40 by 1.7.2