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:
Sat Feb 28 16:32:20 2015 +0000
Revision:
7:6e7b789f4060
Parent:
6:e2eead4e53fb
Child:
8:b119501f4ef0
added holes and scoring

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 6:e2eead4e53fb 5 const char* Game::SPLASH_1 = "-*- Ball and holes -*-";
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 7:6e7b789f4060 24 ain(P0_15), 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), vFriction(-0.01, -0.01), ball(&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 6:e2eead4e53fb 36
maxint 3:ca8b21da67dc 37 this->nGameTickDelay=25; // game tickdelay can be adjusted using up/down
maxint 2:d4de5a5866fe 38
maxint 6:e2eead4e53fb 39 nTopWall=8;
maxint 6:e2eead4e53fb 40 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 41 aWalls[i]=Wall(&(this->disp));
maxint 7:6e7b789f4060 42 for(int i=0; i<NUM_HOLES; i++)
maxint 7:6e7b789f4060 43 aHoles[i]=Hole(&(this->disp));
maxint 5:67e75a4f0b52 44
maxint 5:67e75a4f0b52 45 this->snd.reset();
maxint 0:87ab172a74b4 46 }
maxint 0:87ab172a74b4 47
maxint 2:d4de5a5866fe 48 void Game::printDouble(double value, int x, int y)
maxint 2:d4de5a5866fe 49 {
maxint 0:87ab172a74b4 50 char buffer[10];
maxint 0:87ab172a74b4 51 int len = sprintf(buffer, "%.1f ", value);
maxint 0:87ab172a74b4 52
maxint 1:c1ee4c699517 53 this->disp.drawString(font_oem, x, y, buffer);
maxint 0:87ab172a74b4 54 }
maxint 0:87ab172a74b4 55
maxint 1:c1ee4c699517 56 void Game::initialize()
maxint 1:c1ee4c699517 57 {
maxint 0:87ab172a74b4 58 this->disp.clearScreen();
maxint 0:87ab172a74b4 59
maxint 2:d4de5a5866fe 60 this->snd.reset();
maxint 3:ca8b21da67dc 61 this->nBalls = 4;
maxint 1:c1ee4c699517 62 this->nScore = 0;
maxint 0:87ab172a74b4 63
maxint 7:6e7b789f4060 64 this->tWait.start(); // start the timer
maxint 5:67e75a4f0b52 65
maxint 6:e2eead4e53fb 66 //char sWalls[]="W010010A0";
maxint 6:e2eead4e53fb 67 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 68 {
maxint 6:e2eead4e53fb 69 aWalls[i]=Wall(&(this->disp));
maxint 6:e2eead4e53fb 70 }
maxint 6:e2eead4e53fb 71
maxint 6:e2eead4e53fb 72 // hor
maxint 6:e2eead4e53fb 73 addWall("01:1"); // top edge
maxint 6:e2eead4e53fb 74 addWall("0292");
maxint 6:e2eead4e53fb 75 addWall("0343");
maxint 6:e2eead4e53fb 76 addWall("63:3");
maxint 6:e2eead4e53fb 77 addWall("2484");
maxint 6:e2eead4e53fb 78 addWall("0545");
maxint 6:e2eead4e53fb 79 addWall("65:5");
maxint 6:e2eead4e53fb 80 addWall("1797");
maxint 6:e2eead4e53fb 81 //addWall("08:8"); // bottom
maxint 6:e2eead4e53fb 82
maxint 6:e2eead4e53fb 83 // vert
maxint 6:e2eead4e53fb 84 addWall("5257");
maxint 6:e2eead4e53fb 85
maxint 6:e2eead4e53fb 86 addWall("1617");
maxint 6:e2eead4e53fb 87 addWall("2526");
maxint 6:e2eead4e53fb 88 addWall("3637");
maxint 7:6e7b789f4060 89 //addWall("4546");
maxint 6:e2eead4e53fb 90
maxint 7:6e7b789f4060 91 //addWall("6566");
maxint 6:e2eead4e53fb 92 addWall("7677");
maxint 6:e2eead4e53fb 93 addWall("8586");
maxint 6:e2eead4e53fb 94 addWall("9697");
maxint 6:e2eead4e53fb 95
maxint 7:6e7b789f4060 96 addHole("0211");
maxint 7:6e7b789f4060 97 addHole("0312");
maxint 7:6e7b789f4060 98 addHole("9412");
maxint 7:6e7b789f4060 99 addHole("4612");
maxint 7:6e7b789f4060 100 addHole("5612");
maxint 7:6e7b789f4060 101
maxint 7:6e7b789f4060 102
maxint 6:e2eead4e53fb 103 this->setNoBall(); // reset all balls
maxint 5:67e75a4f0b52 104 this->newBall(); // start first ball
maxint 5:67e75a4f0b52 105 this->snd.play("T240 L16 O5 D E F");
maxint 2:d4de5a5866fe 106
maxint 6:e2eead4e53fb 107 drawWalls();
maxint 2:d4de5a5866fe 108 }
maxint 2:d4de5a5866fe 109
maxint 6:e2eead4e53fb 110 Point Game::getGridPos(char *sPos)
maxint 6:e2eead4e53fb 111 { // get item pos based on a grid definition of 16x16 pixel squares, layed out in a 10x8 grid
maxint 6:e2eead4e53fb 112 // sPos is a 2 character string containing the coordinates in decimal notation: xy
maxint 6:e2eead4e53fb 113 int x=(sPos[0]-'0')*16+8;
maxint 6:e2eead4e53fb 114 int y=(sPos[1]-'0')*16+8;
maxint 6:e2eead4e53fb 115 return(Point(x,y));
maxint 2:d4de5a5866fe 116 }
maxint 2:d4de5a5866fe 117
maxint 6:e2eead4e53fb 118 void Game::addWall(char *sWall)
maxint 6:e2eead4e53fb 119 { // add a wall based on a grid definition of 16x16 pixel squares, layed out in a 10x8 grid
maxint 6:e2eead4e53fb 120 // sWall is a 4 character string containing the edge coordinates in decimal notation: xyXY
maxint 6:e2eead4e53fb 121 // grid axis range from x: '0'-'9', ':'=10 - y: '0'-'8'
maxint 6:e2eead4e53fb 122 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 123 {
maxint 6:e2eead4e53fb 124 if(!aWalls[i].fActive)
maxint 6:e2eead4e53fb 125 {
maxint 6:e2eead4e53fb 126 int x1=sWall[0]-'0';
maxint 6:e2eead4e53fb 127 int y1=sWall[1]-'0';
maxint 6:e2eead4e53fb 128 int x2=sWall[2]-'0';
maxint 6:e2eead4e53fb 129 int y2=sWall[3]-'0';
maxint 7:6e7b789f4060 130 aWalls[i].setRect(Rectangle(x1*16,y1*16,x2*16+1,y2*16+1));
maxint 6:e2eead4e53fb 131 aWalls[i].fActive=true;
maxint 7:6e7b789f4060 132 //printf(0, 0, "W: %d,%d - %d,%d", x1, y1, x2, y2);
maxint 6:e2eead4e53fb 133 break;
maxint 2:d4de5a5866fe 134
maxint 6:e2eead4e53fb 135 //aWalls[i].draw();
maxint 6:e2eead4e53fb 136 //snd.beepShort();
maxint 2:d4de5a5866fe 137 }
maxint 2:d4de5a5866fe 138 }
maxint 0:87ab172a74b4 139 }
maxint 0:87ab172a74b4 140
maxint 7:6e7b789f4060 141
maxint 6:e2eead4e53fb 142 void Game::drawWalls()
maxint 2:d4de5a5866fe 143 {
maxint 6:e2eead4e53fb 144 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 145 if(aWalls[i].fActive)
maxint 6:e2eead4e53fb 146 {
maxint 6:e2eead4e53fb 147 aWalls[i].draw();
maxint 6:e2eead4e53fb 148 //snd.beepShort();
maxint 6:e2eead4e53fb 149 }
maxint 6:e2eead4e53fb 150 }
maxint 2:d4de5a5866fe 151
maxint 7:6e7b789f4060 152 void Game::addHole(char *sHole)
maxint 7:6e7b789f4060 153 { // add a wall based on a grid definition of 16x16 pixel squares, layed out in a 10x8 grid
maxint 7:6e7b789f4060 154 // sWall is a 4 character string containing the edge coordinates in decimal notation: xyXY
maxint 7:6e7b789f4060 155 // grid axis range from x: '0'-'9', ':'=10 - y: '0'-'8'
maxint 7:6e7b789f4060 156 for(int i=0; i<NUM_WALLS; i++)
maxint 7:6e7b789f4060 157 {
maxint 7:6e7b789f4060 158 if(!aHoles[i].fActive)
maxint 7:6e7b789f4060 159 {
maxint 7:6e7b789f4060 160 int x1=sHole[0]-'0';
maxint 7:6e7b789f4060 161 int y1=sHole[1]-'0';
maxint 7:6e7b789f4060 162 int r=sHole[2]-'0';
maxint 7:6e7b789f4060 163 int c=sHole[3]-'0';
maxint 7:6e7b789f4060 164 aHoles[i].setCirc(Circle(x1*16+8,y1*16+8, Game::HOLE_RADIUS));
maxint 7:6e7b789f4060 165 if(c==1) aHoles[i].setColor(Color565::Green);
maxint 7:6e7b789f4060 166 if(c==2) aHoles[i].setColor(Color565::Gray);
maxint 7:6e7b789f4060 167 if(c==3) aHoles[i].setColor(Color565::Red);
maxint 7:6e7b789f4060 168 aHoles[i].fActive=true;
maxint 7:6e7b789f4060 169 //printf(0, 0, "H: %d,%d - %d,%d", x1, y1, r, c);
maxint 7:6e7b789f4060 170 break;
maxint 7:6e7b789f4060 171
maxint 7:6e7b789f4060 172 //aWalls[i].draw();
maxint 7:6e7b789f4060 173 //snd.beepShort();
maxint 7:6e7b789f4060 174 }
maxint 7:6e7b789f4060 175 }
maxint 7:6e7b789f4060 176 }
maxint 7:6e7b789f4060 177
maxint 7:6e7b789f4060 178 void Game::drawHoles()
maxint 7:6e7b789f4060 179 {
maxint 7:6e7b789f4060 180 for(int i=0; i<NUM_HOLES; i++)
maxint 7:6e7b789f4060 181 if(aHoles[i].fActive)
maxint 7:6e7b789f4060 182 {
maxint 7:6e7b789f4060 183 aHoles[i].draw();
maxint 7:6e7b789f4060 184 //snd.beepShort();
maxint 7:6e7b789f4060 185 }
maxint 7:6e7b789f4060 186 }
maxint 7:6e7b789f4060 187
maxint 7:6e7b789f4060 188
maxint 2:d4de5a5866fe 189
maxint 6:e2eead4e53fb 190 void Game::setNoBall()
maxint 6:e2eead4e53fb 191 { // make sure no balls are active
maxint 6:e2eead4e53fb 192 /* for(int i=0; i<NUM_BALLS; i++)
maxint 6:e2eead4e53fb 193 this->aBalls[i].fActive=false;
maxint 6:e2eead4e53fb 194 */
maxint 2:d4de5a5866fe 195 }
maxint 2:d4de5a5866fe 196
maxint 6:e2eead4e53fb 197 void Game::newBall()
maxint 6:e2eead4e53fb 198 { // add a ball to the game
maxint 6:e2eead4e53fb 199 Point ptBall=getGridPos("01");
maxint 6:e2eead4e53fb 200 ball.initialize(ptBall.getX(), ptBall.getY(), Game::BALL_RADIUS, Color565::White);
maxint 6:e2eead4e53fb 201 //float ftRandX=rand() % 2 ? 1 : -1;
maxint 6:e2eead4e53fb 202 //float ftRandY=rand() % 2 ? 1 : -1;
maxint 6:e2eead4e53fb 203 //this->aBalls[i].setSpeed(ftRandX, ftRandY);
maxint 6:e2eead4e53fb 204 // float ftRandX=((rand() % 20) - 10)/5.0; // left/right at random speed
maxint 6:e2eead4e53fb 205 // float ftRandY=((rand() % 10) - 10)/5.0; // up at random speed
maxint 6:e2eead4e53fb 206 // ball.vSpeed.set(ftRandX, ftRandY);
maxint 6:e2eead4e53fb 207 //this->aBalls[i].fActive=true;
maxint 2:d4de5a5866fe 208 }
maxint 2:d4de5a5866fe 209
maxint 6:e2eead4e53fb 210 void Game::updateBall()
maxint 6:e2eead4e53fb 211 {
maxint 6:e2eead4e53fb 212 ball.update(); // update the ball position
maxint 6:e2eead4e53fb 213
maxint 6:e2eead4e53fb 214 // increase speed based on gravity
maxint 6:e2eead4e53fb 215 checkTilt();
maxint 6:e2eead4e53fb 216 if(ball.vSpeed.getSize()<1.0)
maxint 6:e2eead4e53fb 217 ball.vSpeed.add(this->vGravity); // add some gravity
maxint 6:e2eead4e53fb 218
maxint 6:e2eead4e53fb 219 // decrease speed based on friction
maxint 6:e2eead4e53fb 220 Vector vDecel=ball.vSpeed.getNormalized();
maxint 6:e2eead4e53fb 221 vDecel.multiply(vFriction);
maxint 6:e2eead4e53fb 222 ball.vSpeed.add(vDecel);
maxint 6:e2eead4e53fb 223 }
maxint 6:e2eead4e53fb 224
maxint 6:e2eead4e53fb 225 void Game::redrawBall()
maxint 6:e2eead4e53fb 226 {
maxint 6:e2eead4e53fb 227 ball.redraw(); // update the ball position
maxint 6:e2eead4e53fb 228 }
maxint 6:e2eead4e53fb 229
maxint 6:e2eead4e53fb 230 int Game::countBall()
maxint 2:d4de5a5866fe 231 {
maxint 2:d4de5a5866fe 232 int nResult=0;
maxint 6:e2eead4e53fb 233 /*
maxint 2:d4de5a5866fe 234 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 235 {
maxint 2:d4de5a5866fe 236 if(this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 237 nResult++;
maxint 2:d4de5a5866fe 238 }
maxint 6:e2eead4e53fb 239 */
maxint 2:d4de5a5866fe 240 return(nResult);
maxint 2:d4de5a5866fe 241 }
maxint 2:d4de5a5866fe 242
maxint 2:d4de5a5866fe 243
maxint 2:d4de5a5866fe 244
maxint 2:d4de5a5866fe 245
maxint 2:d4de5a5866fe 246
maxint 2:d4de5a5866fe 247 void Game::tick()
maxint 2:d4de5a5866fe 248 {
maxint 6:e2eead4e53fb 249 checkButtons();
maxint 0:87ab172a74b4 250
maxint 6:e2eead4e53fb 251 if(mode)
maxint 6:e2eead4e53fb 252 {
maxint 0:87ab172a74b4 253 /*
maxint 0:87ab172a74b4 254 if(this->tWait.read_ms()>100)
maxint 0:87ab172a74b4 255 {
maxint 0:87ab172a74b4 256 this->tWait.reset();
maxint 0:87ab172a74b4 257 }
maxint 0:87ab172a74b4 258 */
maxint 2:d4de5a5866fe 259
maxint 6:e2eead4e53fb 260 updateBall(); // update the ball positions
maxint 0:87ab172a74b4 261
maxint 6:e2eead4e53fb 262 checkBallCollision();
maxint 5:67e75a4f0b52 263
maxint 6:e2eead4e53fb 264 redrawBall();
maxint 6:e2eead4e53fb 265
maxint 7:6e7b789f4060 266 if(this->tWait.read_ms()>100)
maxint 7:6e7b789f4060 267 { // redraw walls and holes every tenth second
maxint 7:6e7b789f4060 268 drawWalls();
maxint 7:6e7b789f4060 269 drawHoles();
maxint 7:6e7b789f4060 270
maxint 7:6e7b789f4060 271 checkNumBalls();
maxint 7:6e7b789f4060 272
maxint 7:6e7b789f4060 273 this->tWait.reset();
maxint 7:6e7b789f4060 274 }
maxint 0:87ab172a74b4 275
maxint 5:67e75a4f0b52 276 // this->snd.checkPwm();
maxint 1:c1ee4c699517 277 //this->checkScore();
maxint 6:e2eead4e53fb 278 //this->checkBall();
maxint 0:87ab172a74b4 279
maxint 6:e2eead4e53fb 280 wait_ms(nGameTickDelay); // can be adjusted using up/down
maxint 0:87ab172a74b4 281 }
maxint 6:e2eead4e53fb 282 else
maxint 6:e2eead4e53fb 283 {
maxint 6:e2eead4e53fb 284 accel.updateGraph();
maxint 0:87ab172a74b4 285 wait_ms(100);
maxint 0:87ab172a74b4 286 }
maxint 0:87ab172a74b4 287 }
maxint 0:87ab172a74b4 288
maxint 6:e2eead4e53fb 289 void Game::checkTilt()
maxint 6:e2eead4e53fb 290 { // move the gravity direction and weight by tilting the board
maxint 0:87ab172a74b4 291 double x, y, z;
maxint 0:87ab172a74b4 292 //int nStart=this->tWait.read_ms();
maxint 0:87ab172a74b4 293 this->accel.getXYZ(x, y, z);
maxint 0:87ab172a74b4 294
maxint 6:e2eead4e53fb 295 vGravity=Vector(x,y);
maxint 6:e2eead4e53fb 296 // vGravity=vGravity.getNormalized();
maxint 6:e2eead4e53fb 297
maxint 0:87ab172a74b4 298 //printDouble((double)this->tWait.read_ms()-nStart, 10, 10);
maxint 0:87ab172a74b4 299 /*
maxint 0:87ab172a74b4 300 printDouble(x, 0, 0);
maxint 0:87ab172a74b4 301 char buf[256];
maxint 0:87ab172a74b4 302 sprintf(buf,"tilt:%0.1f", x);
maxint 0:87ab172a74b4 303 this->drawString(buf, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2 + 4*DisplayN18::CHAR_HEIGHT );
maxint 0:87ab172a74b4 304 */
maxint 0:87ab172a74b4 305
maxint 6:e2eead4e53fb 306 //return(Vector(0,0));
maxint 0:87ab172a74b4 307 }
maxint 0:87ab172a74b4 308
maxint 0:87ab172a74b4 309 void Game::checkButtons()
maxint 0:87ab172a74b4 310 {
maxint 3:ca8b21da67dc 311 if(!this->square.read()) // note: button.read() is false (LOW/0) when pressed
maxint 0:87ab172a74b4 312 {
maxint 3:ca8b21da67dc 313 wait_ms(250); // el-cheapo deboounce
maxint 0:87ab172a74b4 314 this->mode = !this->mode;
maxint 0:87ab172a74b4 315
maxint 0:87ab172a74b4 316 //this->disp.clear();
maxint 0:87ab172a74b4 317 this->disp.clearScreen();
maxint 0:87ab172a74b4 318
maxint 0:87ab172a74b4 319 if (!this->mode)
maxint 0:87ab172a74b4 320 {
maxint 1:c1ee4c699517 321 this->accel.resetGraph();
maxint 0:87ab172a74b4 322 }
maxint 0:87ab172a74b4 323
maxint 0:87ab172a74b4 324 this->led1.write(this->mode);
maxint 0:87ab172a74b4 325 this->led2.write(!this->mode);
maxint 0:87ab172a74b4 326 }
maxint 3:ca8b21da67dc 327 else if(!this->circle.read() && this->mode) // note: button.read() is false (LOW/0) when pressed
maxint 3:ca8b21da67dc 328 {
maxint 3:ca8b21da67dc 329 bool fMute=this->snd.getMute();
maxint 3:ca8b21da67dc 330 fMute=!fMute;
maxint 3:ca8b21da67dc 331 this->snd.setMute(fMute);
maxint 3:ca8b21da67dc 332 this->led2.write(fMute);
maxint 3:ca8b21da67dc 333 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 334 }
maxint 0:87ab172a74b4 335 else
maxint 0:87ab172a74b4 336 {
maxint 0:87ab172a74b4 337 bool isUp = !this->up.read();
maxint 0:87ab172a74b4 338 bool isDown = !this->down.read();
maxint 0:87ab172a74b4 339
maxint 0:87ab172a74b4 340 if (isUp && isDown) goto end;
maxint 0:87ab172a74b4 341 if (!isUp && !isDown) goto end;
maxint 0:87ab172a74b4 342
maxint 0:87ab172a74b4 343 if (isUp && this->lastUp) goto end;
maxint 0:87ab172a74b4 344 if (isDown && this->lastDown) goto end;
maxint 0:87ab172a74b4 345
maxint 0:87ab172a74b4 346 if (isUp)
maxint 0:87ab172a74b4 347 {
maxint 3:ca8b21da67dc 348 if(this->nGameTickDelay<1000) this->nGameTickDelay=(float)this->nGameTickDelay*1.20;
maxint 3:ca8b21da67dc 349 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 350 }
maxint 0:87ab172a74b4 351 else if (isDown)
maxint 0:87ab172a74b4 352 {
maxint 3:ca8b21da67dc 353 if(this->nGameTickDelay>5) this->nGameTickDelay=(float)this->nGameTickDelay/1.20;
maxint 3:ca8b21da67dc 354 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 355 }
maxint 0:87ab172a74b4 356
maxint 0:87ab172a74b4 357 end:
maxint 0:87ab172a74b4 358 this->lastUp = isUp;
maxint 0:87ab172a74b4 359 this->lastDown = isDown;
maxint 0:87ab172a74b4 360 }
maxint 0:87ab172a74b4 361 }
maxint 0:87ab172a74b4 362
maxint 1:c1ee4c699517 363 void Game::drawString(const char* str, int y)
maxint 1:c1ee4c699517 364 {
maxint 1:c1ee4c699517 365 uint8_t width;
maxint 1:c1ee4c699517 366 uint8_t height;
maxint 1:c1ee4c699517 367
maxint 1:c1ee4c699517 368 this->disp.measureString(font_oem, str, width, height);
maxint 1:c1ee4c699517 369 this->disp.drawString(font_oem, WIDTH / 2 - width / 2, y, str);
maxint 1:c1ee4c699517 370
maxint 0:87ab172a74b4 371 }
maxint 0:87ab172a74b4 372
maxint 6:e2eead4e53fb 373 void Game::showSplashScreen()
maxint 6:e2eead4e53fb 374 {
maxint 0:87ab172a74b4 375 this->drawString(Game::SPLASH_1, HEIGHT / 2 - CHAR_HEIGHT / 2);
maxint 0:87ab172a74b4 376 this->drawString(Game::SPLASH_2, HEIGHT / 2 + CHAR_HEIGHT / 2);
maxint 5:67e75a4f0b52 377 this->drawString(Game::SPLASH_3, HEIGHT / 2 + CHAR_HEIGHT / 2 + 2*CHAR_HEIGHT);
maxint 6:e2eead4e53fb 378
maxint 0:87ab172a74b4 379 while (this->circle.read())
maxint 0:87ab172a74b4 380 {
maxint 7:6e7b789f4060 381 //checkTilt();
maxint 7:6e7b789f4060 382 //printf(00, 120, "tilt: %.2f, %.2f ", vGravity.x, vGravity.y);
maxint 0:87ab172a74b4 383
maxint 0:87ab172a74b4 384 wait_ms(1);
maxint 0:87ab172a74b4 385 }
maxint 3:ca8b21da67dc 386 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 387
maxint 2:d4de5a5866fe 388 //this->disp.clearScreen();
maxint 2:d4de5a5866fe 389 this->initialize(); // start a new game
maxint 0:87ab172a74b4 390 }
maxint 0:87ab172a74b4 391
maxint 6:e2eead4e53fb 392 void Game::checkBallCollision()
maxint 2:d4de5a5866fe 393 {
maxint 3:ca8b21da67dc 394 Rectangle rTop=Rectangle(0, -10, WIDTH, this->nTopWall); // Rectangle(0, 0, WIDTH, 1); // top wall
maxint 2:d4de5a5866fe 395 Rectangle rBottom=Rectangle(0, HEIGHT, WIDTH, HEIGHT+10); // Rectangle(0, HEIGHT, WIDTH, HEIGHT); // bottom gap
maxint 2:d4de5a5866fe 396 Rectangle rLeft=Rectangle(-10, 0, 0, HEIGHT); // Rectangle(0, 0, 0, HEIGHT); // left wall
maxint 2:d4de5a5866fe 397 Rectangle rRight=Rectangle(WIDTH, 0, WIDTH+10, HEIGHT); // Rectangle(WIDTH, 0, WIDTH, HEIGHT); // right wall
maxint 2:d4de5a5866fe 398
maxint 6:e2eead4e53fb 399 if(ball.collides(rTop) && ball.vSpeed.isUp()) // top wall
maxint 6:e2eead4e53fb 400 {
maxint 6:e2eead4e53fb 401 ball.vSpeed.y=0;
maxint 6:e2eead4e53fb 402 //this->snd.beepShort();
maxint 6:e2eead4e53fb 403 }
maxint 6:e2eead4e53fb 404 if(ball.collides(rRight) && ball.vSpeed.isRight()) // right wall
maxint 6:e2eead4e53fb 405 {
maxint 6:e2eead4e53fb 406 ball.vSpeed.x=0;
maxint 6:e2eead4e53fb 407 //this->snd.beepShort();
maxint 6:e2eead4e53fb 408 }
maxint 6:e2eead4e53fb 409 if(ball.collides(rLeft) && ball.vSpeed.isLeft()) // left wall
maxint 6:e2eead4e53fb 410 {
maxint 6:e2eead4e53fb 411 ball.vSpeed.x=0;
maxint 6:e2eead4e53fb 412 //this->snd.beepShort();
maxint 6:e2eead4e53fb 413 }
maxint 6:e2eead4e53fb 414 if(ball.collides(rBottom) && ball.vSpeed.isDown()) // bottom wall
maxint 6:e2eead4e53fb 415 {
maxint 6:e2eead4e53fb 416 ball.vSpeed.y=0;
maxint 6:e2eead4e53fb 417 //this->snd.beepShort();
maxint 6:e2eead4e53fb 418 }
maxint 6:e2eead4e53fb 419
maxint 7:6e7b789f4060 420 for(int i=0; i<NUM_WALLS; i++) // test maze walls
maxint 6:e2eead4e53fb 421 {
maxint 6:e2eead4e53fb 422 if(aWalls[i].fActive)
maxint 2:d4de5a5866fe 423 {
maxint 6:e2eead4e53fb 424 Rectangle rWall=aWalls[i].getRect();
maxint 6:e2eead4e53fb 425 if(ball.collides(rWall))
maxint 2:d4de5a5866fe 426 {
maxint 7:6e7b789f4060 427 //printf(30, 0, "b: %.2f", ball.vSpeed.getSize());
maxint 6:e2eead4e53fb 428 if(rWall.isHorizontal())
maxint 7:6e7b789f4060 429 {
maxint 7:6e7b789f4060 430 if(fabs(ball.vSpeed.y)>0.8)
maxint 7:6e7b789f4060 431 snd.play("T240 L128 O4 A");
maxint 7:6e7b789f4060 432 ball.Bounce(Vector(1,-0.1));
maxint 7:6e7b789f4060 433 }
maxint 6:e2eead4e53fb 434 else
maxint 7:6e7b789f4060 435 {
maxint 7:6e7b789f4060 436 if(fabs(ball.vSpeed.x)>0.8)
maxint 7:6e7b789f4060 437 snd.play("T240 L128 O4 A");
maxint 7:6e7b789f4060 438 ball.Bounce(Vector(-0.1,1));
maxint 7:6e7b789f4060 439 }
maxint 6:e2eead4e53fb 440 //ball.vSpeed.multiply(Vector(0,0));
maxint 6:e2eead4e53fb 441 aWalls[i].draw();
maxint 3:ca8b21da67dc 442 }
maxint 6:e2eead4e53fb 443 //printf(0, 100, "W: %d,%d - %d,%d", rWall.getX1(), rWall.getY1(), rWall.getX2(), rWall.getY2());
maxint 2:d4de5a5866fe 444 }
maxint 0:87ab172a74b4 445 }
maxint 7:6e7b789f4060 446
maxint 7:6e7b789f4060 447 for(int i=0; i<NUM_HOLES; i++) // test holes
maxint 7:6e7b789f4060 448 {
maxint 7:6e7b789f4060 449 if(aHoles[i].fActive)
maxint 7:6e7b789f4060 450 {
maxint 7:6e7b789f4060 451 Circle cHole=aHoles[i].getCirc();
maxint 7:6e7b789f4060 452 if(ball.collides(cHole))
maxint 7:6e7b789f4060 453 {
maxint 7:6e7b789f4060 454 //snd.play("T240 L128 O5 C");
maxint 7:6e7b789f4060 455 if(aHoles[i].hasGoneIn(ball.getBoundingCircle()))
maxint 7:6e7b789f4060 456 {
maxint 7:6e7b789f4060 457 //snd.play("T240 L128 O5 C");
maxint 7:6e7b789f4060 458 if(i==0)
maxint 7:6e7b789f4060 459 { // TODO: for now first hole is target hole
maxint 7:6e7b789f4060 460 this->nScore++;
maxint 7:6e7b789f4060 461 this->snd.play("T240 L16 O5 CDEFG");
maxint 7:6e7b789f4060 462 }
maxint 7:6e7b789f4060 463 else
maxint 7:6e7b789f4060 464 {
maxint 7:6e7b789f4060 465 this->nBalls--;
maxint 7:6e7b789f4060 466 this->snd.beepLow();
maxint 7:6e7b789f4060 467 }
maxint 7:6e7b789f4060 468 ball.fActive=false;
maxint 7:6e7b789f4060 469 this->newBall(); // start a new ball
maxint 7:6e7b789f4060 470
maxint 7:6e7b789f4060 471 }
maxint 7:6e7b789f4060 472 }
maxint 7:6e7b789f4060 473 }
maxint 7:6e7b789f4060 474 }
maxint 6:e2eead4e53fb 475
maxint 6:e2eead4e53fb 476
maxint 2:d4de5a5866fe 477 }
maxint 2:d4de5a5866fe 478
maxint 0:87ab172a74b4 479
maxint 1:c1ee4c699517 480 void Game::printf(int x, int y, const char *szFormat, ...)
maxint 0:87ab172a74b4 481 {
maxint 0:87ab172a74b4 482 char szBuffer[256];
maxint 0:87ab172a74b4 483 va_list args;
maxint 0:87ab172a74b4 484
maxint 0:87ab172a74b4 485 va_start(args, szFormat);
maxint 0:87ab172a74b4 486 vsprintf(szBuffer, szFormat, args);
maxint 0:87ab172a74b4 487 va_end(args);
maxint 1:c1ee4c699517 488 this->disp.drawString(font_oem, x, y, szBuffer);
maxint 0:87ab172a74b4 489 }
maxint 7:6e7b789f4060 490
maxint 7:6e7b789f4060 491 void Game::checkNumBalls()
maxint 7:6e7b789f4060 492 {
maxint 7:6e7b789f4060 493 if (this->nBalls == 0)
maxint 7:6e7b789f4060 494 { // game over
maxint 7:6e7b789f4060 495 char buf[256];
maxint 7:6e7b789f4060 496 this->disp.clearScreen();
maxint 7:6e7b789f4060 497
maxint 7:6e7b789f4060 498 this->drawString(Game::LOSE_1, HEIGHT / 2 - CHAR_HEIGHT);
maxint 7:6e7b789f4060 499 this->drawString(Game::LOSE_2, HEIGHT / 2);
maxint 7:6e7b789f4060 500 sprintf(buf,"Your score: %d ", this->nScore);
maxint 7:6e7b789f4060 501 this->drawString(buf, HEIGHT / 2 + CHAR_HEIGHT / 2 + CHAR_HEIGHT );
maxint 7:6e7b789f4060 502
maxint 7:6e7b789f4060 503 this->snd.play("T120 O3 L4 R4 F C F2 C");
maxint 7:6e7b789f4060 504 while (this->circle.read())
maxint 7:6e7b789f4060 505 wait_ms(1);
maxint 7:6e7b789f4060 506 wait_ms(250); // el-cheapo deboounce
maxint 7:6e7b789f4060 507 this->initialize();
maxint 7:6e7b789f4060 508 }
maxint 7:6e7b789f4060 509 else
maxint 7:6e7b789f4060 510 {
maxint 7:6e7b789f4060 511 printf(0, 0, "Balls: %d ", this->nBalls);
maxint 7:6e7b789f4060 512 printf(100, 0, "Score: %d ", this->nScore);
maxint 7:6e7b789f4060 513 }
maxint 7:6e7b789f4060 514 }