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:
Wed Feb 04 13:10:36 2015 +0000
Revision:
3:ca8b21da67dc
Parent:
2:d4de5a5866fe
Child:
4:4a5f33d845d9
somehow this version fails. Too much ram usage?

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