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
Committer:
maxint
Date:
Sun Mar 01 13:58:47 2015 +0000
Revision:
5:8441b390a15f
Parent:
4:8643d2d93a5f
Child:
6:1f5862465b5d
ready for submission?

Who changed what in which revision?

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