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