Retro game that let's the player steer a ball through a hole filled maze. Has multiple levels of increasing difficulty.

Dependencies:   LCD_ST7735 MusicEngine RETRO_BallsAndThings mbed

Ball and Holes

In this game I attempted to create somewhat natural movement of the ball by implementing gravity and friction which combined over time determine the speed of the ball. Playing with the settings (aka. the magic numbers) that are spread out all over game.cpp, gives different effects, such as an icy, rough or liquid-like surface.

It took some time to figure out how to post my very first youtube video. Sorry for the shaky recording. Trying to record the video with my phone while playing the game in one hand was quite challenging, but here it is;

The left and right buttons are used to cheat: restart the current or go to the next level. Up and down control the game-tick. During game-play the robot-button shows the accelerator graph and the ship-button mutes the sound.

BTW. If your ball happens to get stuck, tilting the console in the opposite direction will set it free. For sake of argument: these magnetic wall-ends are in the words of Bob Ross "a happy accident". Since there is no specific code for it, others might call it a bug. As it results in more interesting game-play, I didn't attempt to fix it, but left a comment for those who dare to look at the mess I call code.

Committer:
maxint
Date:
Thu Feb 05 14:41:21 2015 +0000
Revision:
5:67e75a4f0b52
Parent:
4:4a5f33d845d9
Child:
6:e2eead4e53fb
added MusicEngine for more tunes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
maxint 0:87ab172a74b4 1 #include "Game.h"
maxint 0:87ab172a74b4 2
maxint 3:ca8b21da67dc 3 const char* Game::LOSE_1 = "Game over.";
maxint 0:87ab172a74b4 4 const char* Game::LOSE_2 = "Press ship to restart.";
maxint 2:d4de5a5866fe 5 const char* Game::SPLASH_1 = "-*- Balls and paddle -*-";
maxint 2:d4de5a5866fe 6 const char* Game::SPLASH_2 = "Press ship to start.";
maxint 2:d4de5a5866fe 7 const char* Game::SPLASH_3 = "Made by Maxint";
maxint 0:87ab172a74b4 8
maxint 0:87ab172a74b4 9
maxint 0:87ab172a74b4 10 #define WHITE Color565::White
maxint 0:87ab172a74b4 11 #define BLACK Color565::Black
maxint 0:87ab172a74b4 12 #define BLUE Color565::Blue
maxint 0:87ab172a74b4 13 #define RED Color565::Red
maxint 0:87ab172a74b4 14 #define YELLOW Color565::Yellow
maxint 0:87ab172a74b4 15
maxint 0:87ab172a74b4 16 #define CHAR_WIDTH 8
maxint 0:87ab172a74b4 17 #define CHAR_HEIGHT 8
maxint 0:87ab172a74b4 18 #define HEIGHT this->disp.getHeight()
maxint 0:87ab172a74b4 19 #define WIDTH this->disp.getWidth()
maxint 0:87ab172a74b4 20
maxint 0:87ab172a74b4 21
maxint 0:87ab172a74b4 22
maxint 0:87ab172a74b4 23 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),
maxint 2:d4de5a5866fe 24 ain(P0_15), i2c(P0_5, P0_4), disp(P0_19, P0_20, P0_7, P0_21, P0_22, P1_15, P0_2, LCD_ST7735::RGB), accel(this->I2C_ADDR, &disp), vGravity(0, 0.1), ball(&disp), paddle(&disp)
maxint 0:87ab172a74b4 25 {
maxint 1:c1ee4c699517 26 this->disp.setOrientation(LCD_ST7735::Rotate270, false);
maxint 1:c1ee4c699517 27 this->disp.setForegroundColor(WHITE);
maxint 1:c1ee4c699517 28 this->disp.setBackgroundColor(BLACK);
maxint 1:c1ee4c699517 29 this->disp.clearScreen();
maxint 1:c1ee4c699517 30
maxint 0:87ab172a74b4 31 srand(this->ain.read_u16());
maxint 0:87ab172a74b4 32
maxint 0:87ab172a74b4 33 this->lastUp = false;
maxint 0:87ab172a74b4 34 this->lastDown = false;
maxint 3:ca8b21da67dc 35 this->mode = true; // mode: true=game, false=graph
maxint 0:87ab172a74b4 36
maxint 3:ca8b21da67dc 37 this->nGameTickDelay=25; // game tickdelay can be adjusted using up/down
maxint 2:d4de5a5866fe 38
maxint 2:d4de5a5866fe 39 //this->aBalls[2]={ Ball(&disp), Ball(&disp) };
maxint 2:d4de5a5866fe 40 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 41 this->aBalls[i]=Ball(&(this->disp));
maxint 5:67e75a4f0b52 42
maxint 5:67e75a4f0b52 43 this->snd.reset();
maxint 0:87ab172a74b4 44 }
maxint 0:87ab172a74b4 45
maxint 2:d4de5a5866fe 46 void Game::printDouble(double value, int x, int y)
maxint 2:d4de5a5866fe 47 {
maxint 0:87ab172a74b4 48 char buffer[10];
maxint 0:87ab172a74b4 49 int len = sprintf(buffer, "%.1f ", value);
maxint 0:87ab172a74b4 50
maxint 1:c1ee4c699517 51 this->disp.drawString(font_oem, x, y, buffer);
maxint 0:87ab172a74b4 52 }
maxint 0:87ab172a74b4 53
maxint 1:c1ee4c699517 54 void Game::initialize()
maxint 1:c1ee4c699517 55 {
maxint 0:87ab172a74b4 56 this->disp.clearScreen();
maxint 0:87ab172a74b4 57
maxint 2:d4de5a5866fe 58 this->snd.reset();
maxint 3:ca8b21da67dc 59 this->nBalls = 4;
maxint 1:c1ee4c699517 60 this->nScore = 0;
maxint 3:ca8b21da67dc 61 this->nTopWall = 8;
maxint 5:67e75a4f0b52 62 this->fDrawTopWall=true;
maxint 0:87ab172a74b4 63
maxint 5:67e75a4f0b52 64 // this->tWait.start(); // start the timer
maxint 5:67e75a4f0b52 65
maxint 5:67e75a4f0b52 66 this->initializePaddle();
maxint 5:67e75a4f0b52 67 this->setNoBalls(); // reset all balls
maxint 5:67e75a4f0b52 68 this->newBall(); // start first ball
maxint 5:67e75a4f0b52 69 this->snd.play("T240 L16 O5 D E F");
maxint 0:87ab172a74b4 70 }
maxint 2:d4de5a5866fe 71
maxint 2:d4de5a5866fe 72
maxint 2:d4de5a5866fe 73 void Game::initializePaddle()
maxint 2:d4de5a5866fe 74 {
maxint 2:d4de5a5866fe 75 this->paddle.initialize(WIDTH / 2 - Game::PADDLE_WIDTH/2, HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT);
maxint 3:ca8b21da67dc 76 this->fDrawPaddle=true;
maxint 2:d4de5a5866fe 77 }
maxint 2:d4de5a5866fe 78
maxint 2:d4de5a5866fe 79
maxint 2:d4de5a5866fe 80 void Game::updatePaddle()
maxint 2:d4de5a5866fe 81 {
maxint 2:d4de5a5866fe 82 if (!this->left.read()) // note: read is LOW (0) when button pressed
maxint 2:d4de5a5866fe 83 this->paddle.move(Vector(-1 * Game::PADDLE_SPEED, 0));
maxint 2:d4de5a5866fe 84 else if (!this->right.read())
maxint 2:d4de5a5866fe 85 this->paddle.move(Vector(Game::PADDLE_SPEED, 0));
maxint 2:d4de5a5866fe 86 else
maxint 2:d4de5a5866fe 87 {
maxint 2:d4de5a5866fe 88 int i=this->checkTilt();
maxint 2:d4de5a5866fe 89 if(i>0)
maxint 2:d4de5a5866fe 90 this->paddle.move(Vector(Game::PADDLE_SPEED, 0));
maxint 2:d4de5a5866fe 91 else if(i<0)
maxint 2:d4de5a5866fe 92 this->paddle.move(Vector(-1 * Game::PADDLE_SPEED, 0));
maxint 2:d4de5a5866fe 93 else if(this->paddle.hasChanged())
maxint 2:d4de5a5866fe 94 paddle.move(Vector(0, 0)); // move to same place to restrict redraws
maxint 2:d4de5a5866fe 95 }
maxint 2:d4de5a5866fe 96 }
maxint 2:d4de5a5866fe 97
maxint 3:ca8b21da67dc 98 void Game::redrawPaddle()
maxint 3:ca8b21da67dc 99 { // redraw the paddle when moved, or when forced by this->fDrawPaddle (set at bounce)
maxint 3:ca8b21da67dc 100 this->paddle.redraw(this->fDrawPaddle);
maxint 3:ca8b21da67dc 101 this->fDrawPaddle=false;
maxint 0:87ab172a74b4 102 }
maxint 2:d4de5a5866fe 103
maxint 2:d4de5a5866fe 104 void Game::setNoBalls()
maxint 3:ca8b21da67dc 105 { // make sure no balls are active
maxint 2:d4de5a5866fe 106 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 107 this->aBalls[i].fActive=false;
maxint 2:d4de5a5866fe 108 }
maxint 2:d4de5a5866fe 109
maxint 2:d4de5a5866fe 110 void Game::newBall()
maxint 3:ca8b21da67dc 111 { // add a new ball to the game
maxint 2:d4de5a5866fe 112 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 113 {
maxint 2:d4de5a5866fe 114 if(this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 115 continue;
maxint 2:d4de5a5866fe 116 else
maxint 2:d4de5a5866fe 117 {
maxint 5:67e75a4f0b52 118 this->aBalls[i].initialize(WIDTH / 2 - Game::BALL_RADIUS, this->nTopWall + (HEIGHT-this->nTopWall) / 4 - Game::BALL_RADIUS, Game::BALL_RADIUS, Color565::fromRGB(i==0?0xFF:0x33, i==1?0xFF:0x33, i==2?0xFF:0x33));
maxint 2:d4de5a5866fe 119 //float ftRandX=rand() % 2 ? 1 : -1;
maxint 2:d4de5a5866fe 120 //float ftRandY=rand() % 2 ? 1 : -1;
maxint 2:d4de5a5866fe 121 //this->aBalls[i].setSpeed(ftRandX, ftRandY);
maxint 3:ca8b21da67dc 122 float ftRandX=((rand() % 20) - 10)/5.0; // left/right at random speed
maxint 3:ca8b21da67dc 123 float ftRandY=((rand() % 10) - 10)/5.0; // up at random speed
maxint 2:d4de5a5866fe 124 this->aBalls[i].vSpeed.set(ftRandX, ftRandY);
maxint 2:d4de5a5866fe 125 this->aBalls[i].fActive=true;
maxint 2:d4de5a5866fe 126 break;
maxint 2:d4de5a5866fe 127 }
maxint 2:d4de5a5866fe 128 }
maxint 0:87ab172a74b4 129 }
maxint 0:87ab172a74b4 130
maxint 2:d4de5a5866fe 131 void Game::updateBalls()
maxint 2:d4de5a5866fe 132 {
maxint 2:d4de5a5866fe 133 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 134 {
maxint 2:d4de5a5866fe 135 if(!this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 136 continue;
maxint 2:d4de5a5866fe 137
maxint 2:d4de5a5866fe 138 this->aBalls[i].update(); // update the ball position
maxint 2:d4de5a5866fe 139
maxint 2:d4de5a5866fe 140 // add downward gravity
maxint 3:ca8b21da67dc 141 if(this->aBalls[i].vSpeed.getSize()<10.0)
maxint 2:d4de5a5866fe 142 this->aBalls[i].vSpeed.add(this->vGravity); // add some gravity
maxint 2:d4de5a5866fe 143
maxint 2:d4de5a5866fe 144 }
maxint 2:d4de5a5866fe 145 }
maxint 2:d4de5a5866fe 146
maxint 2:d4de5a5866fe 147 void Game::redrawBalls()
maxint 2:d4de5a5866fe 148 {
maxint 2:d4de5a5866fe 149 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 150 {
maxint 2:d4de5a5866fe 151 if(!this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 152 continue;
maxint 2:d4de5a5866fe 153 this->aBalls[i].redraw(); // update the ball position
maxint 2:d4de5a5866fe 154 }
maxint 2:d4de5a5866fe 155 }
maxint 2:d4de5a5866fe 156
maxint 2:d4de5a5866fe 157 int Game::countBalls()
maxint 2:d4de5a5866fe 158 {
maxint 2:d4de5a5866fe 159 int nResult=0;
maxint 2:d4de5a5866fe 160 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 161 {
maxint 2:d4de5a5866fe 162 if(this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 163 nResult++;
maxint 2:d4de5a5866fe 164 }
maxint 2:d4de5a5866fe 165 return(nResult);
maxint 2:d4de5a5866fe 166 }
maxint 2:d4de5a5866fe 167
maxint 2:d4de5a5866fe 168
maxint 2:d4de5a5866fe 169
maxint 2:d4de5a5866fe 170
maxint 2:d4de5a5866fe 171
maxint 2:d4de5a5866fe 172 void Game::tick()
maxint 2:d4de5a5866fe 173 {
maxint 0:87ab172a74b4 174 this->checkButtons();
maxint 0:87ab172a74b4 175
maxint 0:87ab172a74b4 176 if (this->mode) {
maxint 0:87ab172a74b4 177 /*
maxint 0:87ab172a74b4 178 if(this->tWait.read_ms()>100)
maxint 0:87ab172a74b4 179 {
maxint 0:87ab172a74b4 180 this->updatePaddle();
maxint 0:87ab172a74b4 181 this->tWait.reset();
maxint 0:87ab172a74b4 182 }
maxint 0:87ab172a74b4 183 */
maxint 2:d4de5a5866fe 184
maxint 2:d4de5a5866fe 185 this->updateBalls(); // update the ball positions
maxint 0:87ab172a74b4 186 this->updatePaddle();
maxint 0:87ab172a74b4 187
maxint 2:d4de5a5866fe 188 this->checkPaddle();
maxint 2:d4de5a5866fe 189 this->checkBallsCollision();
maxint 5:67e75a4f0b52 190
maxint 2:d4de5a5866fe 191 this->redrawBalls();
maxint 3:ca8b21da67dc 192 this->redrawPaddle();
maxint 5:67e75a4f0b52 193 this->redrawTopWall();
maxint 0:87ab172a74b4 194
maxint 5:67e75a4f0b52 195 // this->snd.checkPwm();
maxint 1:c1ee4c699517 196 //this->checkScore();
maxint 3:ca8b21da67dc 197 this->checkBalls();
maxint 0:87ab172a74b4 198
maxint 3:ca8b21da67dc 199 wait_ms(this->nGameTickDelay); // can be adjusted using up/down
maxint 0:87ab172a74b4 200 }
maxint 1:c1ee4c699517 201 else {
maxint 1:c1ee4c699517 202 this->accel.updateGraph();
maxint 0:87ab172a74b4 203 wait_ms(100);
maxint 0:87ab172a74b4 204 }
maxint 0:87ab172a74b4 205 }
maxint 0:87ab172a74b4 206
maxint 0:87ab172a74b4 207 int Game::checkTilt()
maxint 0:87ab172a74b4 208 { // move the paddle by tilting the board left or righr
maxint 0:87ab172a74b4 209 double x, y, z;
maxint 0:87ab172a74b4 210 //int nStart=this->tWait.read_ms();
maxint 0:87ab172a74b4 211 this->accel.getXYZ(x, y, z);
maxint 0:87ab172a74b4 212
maxint 0:87ab172a74b4 213 //printDouble((double)this->tWait.read_ms()-nStart, 10, 10);
maxint 0:87ab172a74b4 214 /*
maxint 0:87ab172a74b4 215 printDouble(x, 0, 0);
maxint 0:87ab172a74b4 216 char buf[256];
maxint 0:87ab172a74b4 217 sprintf(buf,"tilt:%0.1f", x);
maxint 0:87ab172a74b4 218 this->drawString(buf, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2 + 4*DisplayN18::CHAR_HEIGHT );
maxint 0:87ab172a74b4 219 */
maxint 0:87ab172a74b4 220
maxint 0:87ab172a74b4 221 if(x<-0.1) return(-1);
maxint 0:87ab172a74b4 222 else if(x>0.1) return(1);
maxint 0:87ab172a74b4 223 else return(0);
maxint 0:87ab172a74b4 224 }
maxint 0:87ab172a74b4 225
maxint 0:87ab172a74b4 226 void Game::checkButtons()
maxint 0:87ab172a74b4 227 {
maxint 3:ca8b21da67dc 228 if(!this->square.read()) // note: button.read() is false (LOW/0) when pressed
maxint 0:87ab172a74b4 229 {
maxint 3:ca8b21da67dc 230 wait_ms(250); // el-cheapo deboounce
maxint 0:87ab172a74b4 231 this->mode = !this->mode;
maxint 0:87ab172a74b4 232
maxint 0:87ab172a74b4 233 //this->disp.clear();
maxint 0:87ab172a74b4 234 this->disp.clearScreen();
maxint 0:87ab172a74b4 235
maxint 0:87ab172a74b4 236 if (!this->mode)
maxint 0:87ab172a74b4 237 {
maxint 1:c1ee4c699517 238 this->accel.resetGraph();
maxint 0:87ab172a74b4 239 }
maxint 0:87ab172a74b4 240
maxint 0:87ab172a74b4 241 this->led1.write(this->mode);
maxint 0:87ab172a74b4 242 this->led2.write(!this->mode);
maxint 0:87ab172a74b4 243 }
maxint 3:ca8b21da67dc 244 else if(!this->circle.read() && this->mode) // note: button.read() is false (LOW/0) when pressed
maxint 3:ca8b21da67dc 245 {
maxint 3:ca8b21da67dc 246 bool fMute=this->snd.getMute();
maxint 3:ca8b21da67dc 247 fMute=!fMute;
maxint 3:ca8b21da67dc 248 this->snd.setMute(fMute);
maxint 3:ca8b21da67dc 249 this->led2.write(fMute);
maxint 3:ca8b21da67dc 250 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 251 }
maxint 0:87ab172a74b4 252 else
maxint 0:87ab172a74b4 253 {
maxint 0:87ab172a74b4 254 bool isUp = !this->up.read();
maxint 0:87ab172a74b4 255 bool isDown = !this->down.read();
maxint 0:87ab172a74b4 256
maxint 0:87ab172a74b4 257 if (isUp && isDown) goto end;
maxint 0:87ab172a74b4 258 if (!isUp && !isDown) goto end;
maxint 0:87ab172a74b4 259
maxint 0:87ab172a74b4 260 if (isUp && this->lastUp) goto end;
maxint 0:87ab172a74b4 261 if (isDown && this->lastDown) goto end;
maxint 0:87ab172a74b4 262
maxint 0:87ab172a74b4 263 if (isUp)
maxint 0:87ab172a74b4 264 {
maxint 3:ca8b21da67dc 265 if(this->nGameTickDelay<1000) this->nGameTickDelay=(float)this->nGameTickDelay*1.20;
maxint 3:ca8b21da67dc 266 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 267 }
maxint 0:87ab172a74b4 268 else if (isDown)
maxint 0:87ab172a74b4 269 {
maxint 3:ca8b21da67dc 270 if(this->nGameTickDelay>5) this->nGameTickDelay=(float)this->nGameTickDelay/1.20;
maxint 3:ca8b21da67dc 271 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 272 }
maxint 0:87ab172a74b4 273
maxint 0:87ab172a74b4 274 end:
maxint 0:87ab172a74b4 275 this->lastUp = isUp;
maxint 0:87ab172a74b4 276 this->lastDown = isDown;
maxint 0:87ab172a74b4 277 }
maxint 0:87ab172a74b4 278 }
maxint 0:87ab172a74b4 279
maxint 1:c1ee4c699517 280 void Game::drawString(const char* str, int y)
maxint 1:c1ee4c699517 281 {
maxint 1:c1ee4c699517 282 uint8_t width;
maxint 1:c1ee4c699517 283 uint8_t height;
maxint 1:c1ee4c699517 284
maxint 1:c1ee4c699517 285 this->disp.measureString(font_oem, str, width, height);
maxint 1:c1ee4c699517 286 this->disp.drawString(font_oem, WIDTH / 2 - width / 2, y, str);
maxint 1:c1ee4c699517 287
maxint 0:87ab172a74b4 288 }
maxint 0:87ab172a74b4 289
maxint 0:87ab172a74b4 290 void Game::showSplashScreen() {
maxint 0:87ab172a74b4 291 this->drawString(Game::SPLASH_1, HEIGHT / 2 - CHAR_HEIGHT / 2);
maxint 0:87ab172a74b4 292 this->drawString(Game::SPLASH_2, HEIGHT / 2 + CHAR_HEIGHT / 2);
maxint 5:67e75a4f0b52 293 this->drawString(Game::SPLASH_3, HEIGHT / 2 + CHAR_HEIGHT / 2 + 2*CHAR_HEIGHT);
maxint 0:87ab172a74b4 294
maxint 0:87ab172a74b4 295 while (this->circle.read())
maxint 0:87ab172a74b4 296 {
maxint 0:87ab172a74b4 297 int i=this->checkTilt();
maxint 0:87ab172a74b4 298 char buf[256];
maxint 1:c1ee4c699517 299 sprintf(buf," tilt:%d ", i);
maxint 5:67e75a4f0b52 300 this->drawString(buf, HEIGHT / 2 + CHAR_HEIGHT / 2 + (4*CHAR_HEIGHT) );
maxint 0:87ab172a74b4 301
maxint 0:87ab172a74b4 302 wait_ms(1);
maxint 0:87ab172a74b4 303 }
maxint 3:ca8b21da67dc 304 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 305
maxint 2:d4de5a5866fe 306 //this->disp.clearScreen();
maxint 2:d4de5a5866fe 307 this->initialize(); // start a new game
maxint 0:87ab172a74b4 308 }
maxint 0:87ab172a74b4 309
maxint 0:87ab172a74b4 310
maxint 2:d4de5a5866fe 311
maxint 2:d4de5a5866fe 312 void Game::checkBallsCollision()
maxint 2:d4de5a5866fe 313 {
maxint 3:ca8b21da67dc 314 Rectangle rTop=Rectangle(0, -10, WIDTH, this->nTopWall); // Rectangle(0, 0, WIDTH, 1); // top wall
maxint 2:d4de5a5866fe 315 Rectangle rBottom=Rectangle(0, HEIGHT, WIDTH, HEIGHT+10); // Rectangle(0, HEIGHT, WIDTH, HEIGHT); // bottom gap
maxint 2:d4de5a5866fe 316 Rectangle rLeft=Rectangle(-10, 0, 0, HEIGHT); // Rectangle(0, 0, 0, HEIGHT); // left wall
maxint 2:d4de5a5866fe 317 Rectangle rRight=Rectangle(WIDTH, 0, WIDTH+10, HEIGHT); // Rectangle(WIDTH, 0, WIDTH, HEIGHT); // right wall
maxint 2:d4de5a5866fe 318 Rectangle rPaddle=Rectangle(paddle.pos.getX(), paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH, HEIGHT+10); // Rectangle(this->paddleX, HEIGHT - Game::PADDLE_HEIGHT, this->paddleX + Game::PADDLE_WIDTH, HEIGHT); // paddle
maxint 2:d4de5a5866fe 319 Rectangle rPaddleLeft=Rectangle(paddle.pos.getX(), paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH/3, HEIGHT+10); // paddle left part
maxint 2:d4de5a5866fe 320 Rectangle rPaddleRight=Rectangle(paddle.pos.getX()+ Game::PADDLE_WIDTH/3 + Game::PADDLE_WIDTH/3, paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH, HEIGHT+10); // paddle right part
maxint 2:d4de5a5866fe 321
maxint 2:d4de5a5866fe 322 Ball* pBall;
maxint 2:d4de5a5866fe 323 for(int i=0; i<NUM_BALLS; i++)
maxint 0:87ab172a74b4 324 {
maxint 2:d4de5a5866fe 325 if(!this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 326 continue;
maxint 2:d4de5a5866fe 327
maxint 2:d4de5a5866fe 328 pBall=&(this->aBalls[i]);
maxint 2:d4de5a5866fe 329
maxint 2:d4de5a5866fe 330 if(pBall->collides(rTop) && pBall->vSpeed.isUp()) // top wall
maxint 2:d4de5a5866fe 331 {
maxint 2:d4de5a5866fe 332 pBall->Bounce(Vector(1,-1)); // bounce vertical
maxint 2:d4de5a5866fe 333 this->snd.beepShort();
maxint 5:67e75a4f0b52 334 this->fDrawTopWall=true;
maxint 2:d4de5a5866fe 335 }
maxint 2:d4de5a5866fe 336 if(pBall->collides(rRight) && pBall->vSpeed.isRight()) // right wall
maxint 2:d4de5a5866fe 337 {
maxint 2:d4de5a5866fe 338 pBall->Bounce(Vector(-1,1)); // bounce horizontal
maxint 2:d4de5a5866fe 339 this->snd.beepShort();
maxint 2:d4de5a5866fe 340 }
maxint 2:d4de5a5866fe 341 if(pBall->collides(rLeft) && pBall->vSpeed.isLeft()) // left wall
maxint 2:d4de5a5866fe 342 {
maxint 2:d4de5a5866fe 343 pBall->Bounce(Vector(-1,1)); // bounce horizontal
maxint 2:d4de5a5866fe 344 this->snd.beepShort();
maxint 2:d4de5a5866fe 345 }
maxint 2:d4de5a5866fe 346 if(pBall->collides(rPaddle) && pBall->vSpeed.isDown()) // paddle
maxint 2:d4de5a5866fe 347 {
maxint 5:67e75a4f0b52 348 if(pBall->collides(rPaddleLeft)) pBall->vSpeed.add(Vector(-1.3,0)); // left side of paddle has bias to the left
maxint 5:67e75a4f0b52 349 if(pBall->collides(rPaddleRight)) pBall->vSpeed.add(Vector(1.3,0)); // right side of paddle has bias to the right
maxint 2:d4de5a5866fe 350
maxint 3:ca8b21da67dc 351 // bounce the ball
maxint 2:d4de5a5866fe 352 // increase the speed of the ball when hitting the paddle to increase difficulty
maxint 2:d4de5a5866fe 353 float ftSpeedMax=3.0;
maxint 2:d4de5a5866fe 354 if(this->nScore>50)
maxint 2:d4de5a5866fe 355 ftSpeedMax=5.0;
maxint 2:d4de5a5866fe 356 if(this->nScore>100)
maxint 2:d4de5a5866fe 357 ftSpeedMax=10.0;
maxint 2:d4de5a5866fe 358 if(this->nScore>150)
maxint 2:d4de5a5866fe 359 ftSpeedMax=999.0;
maxint 5:67e75a4f0b52 360 if(pBall->vSpeed.getSize()<ftSpeedMax)
maxint 2:d4de5a5866fe 361 pBall->Bounce(Vector(1,-1.02)); // bounce from paddle at higher speed
maxint 2:d4de5a5866fe 362 else
maxint 2:d4de5a5866fe 363 pBall->Bounce(Vector(1,-1)); // bounce vertical at same speed
maxint 2:d4de5a5866fe 364
maxint 3:ca8b21da67dc 365 // force drawing the paddle after redrawing the bounced ball
maxint 3:ca8b21da67dc 366 this->fDrawPaddle=true;
maxint 3:ca8b21da67dc 367
maxint 3:ca8b21da67dc 368 // make sound and update the score
maxint 2:d4de5a5866fe 369 this->snd.beepLong();
maxint 2:d4de5a5866fe 370 this->nScore++;
maxint 2:d4de5a5866fe 371 this->printf(100, 0, "Score: %d ", this->nScore);
maxint 2:d4de5a5866fe 372
maxint 3:ca8b21da67dc 373 // add a new ball every 10 points
maxint 2:d4de5a5866fe 374 if(this->nScore>0 && this->nScore%10==0)
maxint 2:d4de5a5866fe 375 {
maxint 2:d4de5a5866fe 376 this->newBall();
maxint 3:ca8b21da67dc 377 this->nBalls++;
maxint 5:67e75a4f0b52 378 this->snd.play("T240 L16 O5 D E F");
maxint 2:d4de5a5866fe 379 }
maxint 3:ca8b21da67dc 380
maxint 3:ca8b21da67dc 381 // lower the ceiling every 25 points
maxint 3:ca8b21da67dc 382 if(this->nScore>0 && this->nScore%25==0)
maxint 3:ca8b21da67dc 383 {
maxint 5:67e75a4f0b52 384 this->nTopWall+=3;
maxint 5:67e75a4f0b52 385 this->fDrawTopWall=true;
maxint 5:67e75a4f0b52 386 //this->snd.play("T240 L32 O5 GFEDC");
maxint 5:67e75a4f0b52 387 this->snd.play("T240 L16 O5 CDEFG");
maxint 3:ca8b21da67dc 388 }
maxint 3:ca8b21da67dc 389
maxint 2:d4de5a5866fe 390 }
maxint 2:d4de5a5866fe 391 if(pBall->collides(rBottom) && pBall->vSpeed.isDown()) // bottom gap
maxint 2:d4de5a5866fe 392 {
maxint 2:d4de5a5866fe 393 pBall->clearPrev(); // clear the ball from its previous position
maxint 2:d4de5a5866fe 394 pBall->clear(); // clear the ball from its current position
maxint 2:d4de5a5866fe 395 pBall->vSpeed.set(0,0);
maxint 2:d4de5a5866fe 396 pBall->fActive=false;
maxint 3:ca8b21da67dc 397 this->nBalls--;
maxint 2:d4de5a5866fe 398 if(countBalls()==0)
maxint 2:d4de5a5866fe 399 {
maxint 2:d4de5a5866fe 400 this->newBall(); // start a new ball
maxint 2:d4de5a5866fe 401 this->snd.beepLow();
maxint 2:d4de5a5866fe 402 }
maxint 2:d4de5a5866fe 403 }
maxint 0:87ab172a74b4 404 }
maxint 0:87ab172a74b4 405 }
maxint 0:87ab172a74b4 406
maxint 5:67e75a4f0b52 407 void Game::redrawTopWall()
maxint 5:67e75a4f0b52 408 {
maxint 5:67e75a4f0b52 409 if(this->fDrawTopWall)
maxint 5:67e75a4f0b52 410 {
maxint 5:67e75a4f0b52 411 int nTop=max(this->nTopWall-2, 8);
maxint 5:67e75a4f0b52 412 this->disp.fillRect(0, 8, WIDTH, nTop, Color565::Black);
maxint 5:67e75a4f0b52 413 this->disp.fillRect(0, nTop, WIDTH, this->nTopWall, Color565::Purple);
maxint 5:67e75a4f0b52 414 this->fDrawTopWall=false;
maxint 5:67e75a4f0b52 415 }
maxint 5:67e75a4f0b52 416 }
maxint 5:67e75a4f0b52 417
maxint 2:d4de5a5866fe 418 void Game::checkPaddle()
maxint 2:d4de5a5866fe 419 {
maxint 2:d4de5a5866fe 420 Rectangle rScreen=Rectangle(0,0, WIDTH, HEIGHT); // screen boundary
maxint 2:d4de5a5866fe 421
maxint 2:d4de5a5866fe 422 this->paddle.checkBoundary(rScreen);
maxint 2:d4de5a5866fe 423 }
maxint 2:d4de5a5866fe 424
maxint 0:87ab172a74b4 425
maxint 1:c1ee4c699517 426 void Game::printf(int x, int y, const char *szFormat, ...)
maxint 0:87ab172a74b4 427 {
maxint 0:87ab172a74b4 428 char szBuffer[256];
maxint 0:87ab172a74b4 429 va_list args;
maxint 0:87ab172a74b4 430
maxint 0:87ab172a74b4 431 va_start(args, szFormat);
maxint 0:87ab172a74b4 432 vsprintf(szBuffer, szFormat, args);
maxint 0:87ab172a74b4 433 va_end(args);
maxint 1:c1ee4c699517 434 this->disp.drawString(font_oem, x, y, szBuffer);
maxint 0:87ab172a74b4 435 }
maxint 0:87ab172a74b4 436
maxint 0:87ab172a74b4 437
maxint 3:ca8b21da67dc 438 void Game::checkBalls()
maxint 3:ca8b21da67dc 439 {
maxint 3:ca8b21da67dc 440 if (this->nBalls == 0)
maxint 3:ca8b21da67dc 441 { // game over
maxint 3:ca8b21da67dc 442 char buf[256];
maxint 0:87ab172a74b4 443 this->disp.clearScreen();
maxint 3:ca8b21da67dc 444
maxint 0:87ab172a74b4 445 this->drawString(Game::LOSE_1, HEIGHT / 2 - CHAR_HEIGHT);
maxint 0:87ab172a74b4 446 this->drawString(Game::LOSE_2, HEIGHT / 2);
maxint 3:ca8b21da67dc 447 sprintf(buf,"Your score: %d ", this->nScore);
maxint 3:ca8b21da67dc 448 this->drawString(buf, HEIGHT / 2 + CHAR_HEIGHT / 2 + CHAR_HEIGHT );
maxint 0:87ab172a74b4 449
maxint 2:d4de5a5866fe 450 this->snd.playTune();
maxint 0:87ab172a74b4 451 while (this->circle.read())
maxint 0:87ab172a74b4 452 wait_ms(1);
maxint 3:ca8b21da67dc 453 wait_ms(250); // el-cheapo deboounce
maxint 0:87ab172a74b4 454 this->initialize();
maxint 0:87ab172a74b4 455 }
maxint 3:ca8b21da67dc 456 else
maxint 3:ca8b21da67dc 457 {
maxint 3:ca8b21da67dc 458 this->printf(0, 0, "Balls: %d ", this->nBalls);
maxint 0:87ab172a74b4 459 }
maxint 0:87ab172a74b4 460 }