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:
Sun Mar 01 13:16:19 2015 +0000
Revision:
10:1d75861242f7
Parent:
9:7bd5def2115d
Child:
11:ef3cbc443f27
ready for submisison?

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 10:1d75861242f7 7 const char* Game::SPLASH_3 = "Tilt console to steer ball.";
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 8:b119501f4ef0 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.005, -0.005), 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 8:b119501f4ef0 58 // disp.clearScreen();
maxint 8:b119501f4ef0 59 // snd.reset();
maxint 8:b119501f4ef0 60 nBalls = 4;
maxint 8:b119501f4ef0 61 nScore = 0;
maxint 0:87ab172a74b4 62
maxint 8:b119501f4ef0 63 tWait.start(); // start the timer
maxint 5:67e75a4f0b52 64
maxint 6:e2eead4e53fb 65 //char sWalls[]="W010010A0";
maxint 6:e2eead4e53fb 66 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 67 {
maxint 8:b119501f4ef0 68 aWalls[i]=Wall(&(disp));
maxint 8:b119501f4ef0 69 }
maxint 8:b119501f4ef0 70
maxint 8:b119501f4ef0 71 initLevel();
maxint 8:b119501f4ef0 72
maxint 8:b119501f4ef0 73 // setNoBall(); // reset all balls
maxint 8:b119501f4ef0 74 newBall(); // start first ball
maxint 8:b119501f4ef0 75 snd.play("T240 L16 O5 D E F");
maxint 8:b119501f4ef0 76 }
maxint 8:b119501f4ef0 77
maxint 8:b119501f4ef0 78 void Game::initLevel()
maxint 8:b119501f4ef0 79 {
maxint 8:b119501f4ef0 80 char szLevel0[]="01:1 0262 2787-2227 8187 ";
maxint 8:b119501f4ef0 81 char szLevel1[]="01:1 0292 0343 63:3 2484 0545 65:5 1797-5257 1617 2526 3637 7677 8586 9697 ";
maxint 8:b119501f4ef0 82 char szLevel2[]="01:1 0232 82:2 1343 6393 0484 1696-4143 6163 5355 9396 3435 7475 1617 4547 5758 6567 ";
maxint 8:b119501f4ef0 83 char szLevel3[]="01:1 0232 82:2 3444 1545 6696-4147 6166 2223 8284 1315 5358 9397 ";
maxint 8:b119501f4ef0 84
maxint 8:b119501f4ef0 85 disp.clearScreen();
maxint 8:b119501f4ef0 86 snd.reset();
maxint 8:b119501f4ef0 87
maxint 8:b119501f4ef0 88 // reset current walls and holes
maxint 8:b119501f4ef0 89 for(int i=0; i<NUM_WALLS; i++)
maxint 8:b119501f4ef0 90 aWalls[i].fActive=false;
maxint 8:b119501f4ef0 91 for(int i=0; i<NUM_HOLES; i++)
maxint 8:b119501f4ef0 92 aHoles[i].fActive=false;
maxint 8:b119501f4ef0 93
maxint 8:b119501f4ef0 94 // add walls/holes depending on level
maxint 8:b119501f4ef0 95 switch(nScore)
maxint 8:b119501f4ef0 96 {
maxint 8:b119501f4ef0 97 case 0:
maxint 8:b119501f4ef0 98 addWalls(szLevel0);
maxint 8:b119501f4ef0 99 addHoles("4411 6412 ");
maxint 8:b119501f4ef0 100 break;
maxint 8:b119501f4ef0 101 case 1:
maxint 8:b119501f4ef0 102 addWalls(szLevel1);
maxint 8:b119501f4ef0 103 addHoles("9111 0312 9412 4612 5612 ");
maxint 8:b119501f4ef0 104 break;
maxint 8:b119501f4ef0 105 case 2:
maxint 8:b119501f4ef0 106 addWalls(szLevel1);
maxint 8:b119501f4ef0 107 addHoles("5711 0312 9412 4612 5612 ");
maxint 8:b119501f4ef0 108 break;
maxint 8:b119501f4ef0 109 case 3:
maxint 8:b119501f4ef0 110 addWalls(szLevel1);
maxint 8:b119501f4ef0 111 addHoles("0211 0312 9412 4612 5612 ");
maxint 8:b119501f4ef0 112 break;
maxint 8:b119501f4ef0 113
maxint 8:b119501f4ef0 114 case 4:
maxint 8:b119501f4ef0 115 addWalls(szLevel2);
maxint 8:b119501f4ef0 116 addHoles("4411 6112 5112 1512 8512 2712 7712 8612 ");
maxint 8:b119501f4ef0 117 break;
maxint 8:b119501f4ef0 118 case 5:
maxint 8:b119501f4ef0 119 addWalls(szLevel2);
maxint 8:b119501f4ef0 120 addHoles("5611 6112 5112 1512 8512 2712 7712 8612 ");
maxint 8:b119501f4ef0 121 break;
maxint 8:b119501f4ef0 122 case 6:
maxint 8:b119501f4ef0 123 addWalls(szLevel2);
maxint 8:b119501f4ef0 124 addHoles("9111 6112 5112 1512 8512 2712 7712 8612 ");
maxint 8:b119501f4ef0 125 break;
maxint 8:b119501f4ef0 126
maxint 8:b119501f4ef0 127 case 7:
maxint 8:b119501f4ef0 128 addWalls(szLevel3);
maxint 8:b119501f4ef0 129 addHoles("3411 4112 5112 6112 2212 3312 6312 1412 7412 8512 0612 2612 6612 8612 5712 7712 ");
maxint 8:b119501f4ef0 130 break;
maxint 8:b119501f4ef0 131 case 8:
maxint 8:b119501f4ef0 132 addWalls(szLevel3);
maxint 8:b119501f4ef0 133 addHoles("5211 4112 5112 6112 2212 3312 6312 1412 7412 8512 0612 2612 6612 8612 5712 7712 ");
maxint 8:b119501f4ef0 134 break;
maxint 8:b119501f4ef0 135 case 9:
maxint 8:b119501f4ef0 136 addWalls(szLevel3);
maxint 8:b119501f4ef0 137 addHoles("9711 4112 5112 6112 2212 3312 6312 1412 7412 8512 0612 2612 6612 8612 5712 7712 ");
maxint 8:b119501f4ef0 138 break;
maxint 8:b119501f4ef0 139 case 10:
maxint 8:b119501f4ef0 140 addWalls(szLevel3);
maxint 8:b119501f4ef0 141 addHoles("9111 4112 5112 6112 2212 3312 6312 1412 7412 8512 0612 2612 6612 8612 5712 7712 ");
maxint 8:b119501f4ef0 142 break;
maxint 8:b119501f4ef0 143 case 11:
maxint 8:b119501f4ef0 144 default:
maxint 8:b119501f4ef0 145 addWalls(szLevel3);
maxint 8:b119501f4ef0 146 addHoles("9111 4112 5112 6112 2212 3312 6312 1412 7452 8512 0612 2652 6612 8612 5712 7712 ");
maxint 8:b119501f4ef0 147 break;
maxint 6:e2eead4e53fb 148 }
maxint 6:e2eead4e53fb 149
maxint 6:e2eead4e53fb 150
maxint 8:b119501f4ef0 151 drawWalls();
maxint 8:b119501f4ef0 152 drawHoles();
maxint 8:b119501f4ef0 153 checkNumBalls();
maxint 8:b119501f4ef0 154 }
maxint 7:6e7b789f4060 155
maxint 7:6e7b789f4060 156
maxint 2:d4de5a5866fe 157
maxint 6:e2eead4e53fb 158 Point Game::getGridPos(char *sPos)
maxint 6:e2eead4e53fb 159 { // get item pos based on a grid definition of 16x16 pixel squares, layed out in a 10x8 grid
maxint 6:e2eead4e53fb 160 // sPos is a 2 character string containing the coordinates in decimal notation: xy
maxint 6:e2eead4e53fb 161 int x=(sPos[0]-'0')*16+8;
maxint 6:e2eead4e53fb 162 int y=(sPos[1]-'0')*16+8;
maxint 6:e2eead4e53fb 163 return(Point(x,y));
maxint 2:d4de5a5866fe 164 }
maxint 2:d4de5a5866fe 165
maxint 6:e2eead4e53fb 166 void Game::addWall(char *sWall)
maxint 6:e2eead4e53fb 167 { // add a wall based on a grid definition of 16x16 pixel squares, layed out in a 10x8 grid
maxint 6:e2eead4e53fb 168 // sWall is a 4 character string containing the edge coordinates in decimal notation: xyXY
maxint 6:e2eead4e53fb 169 // grid axis range from x: '0'-'9', ':'=10 - y: '0'-'8'
maxint 6:e2eead4e53fb 170 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 171 {
maxint 6:e2eead4e53fb 172 if(!aWalls[i].fActive)
maxint 6:e2eead4e53fb 173 {
maxint 6:e2eead4e53fb 174 int x1=sWall[0]-'0';
maxint 6:e2eead4e53fb 175 int y1=sWall[1]-'0';
maxint 6:e2eead4e53fb 176 int x2=sWall[2]-'0';
maxint 6:e2eead4e53fb 177 int y2=sWall[3]-'0';
maxint 7:6e7b789f4060 178 aWalls[i].setRect(Rectangle(x1*16,y1*16,x2*16+1,y2*16+1));
maxint 6:e2eead4e53fb 179 aWalls[i].fActive=true;
maxint 7:6e7b789f4060 180 //printf(0, 0, "W: %d,%d - %d,%d", x1, y1, x2, y2);
maxint 6:e2eead4e53fb 181 break;
maxint 2:d4de5a5866fe 182
maxint 6:e2eead4e53fb 183 //aWalls[i].draw();
maxint 6:e2eead4e53fb 184 //snd.beepShort();
maxint 2:d4de5a5866fe 185 }
maxint 2:d4de5a5866fe 186 }
maxint 0:87ab172a74b4 187 }
maxint 0:87ab172a74b4 188
maxint 8:b119501f4ef0 189 void Game::addWalls(char *sWalls)
maxint 8:b119501f4ef0 190 {
maxint 8:b119501f4ef0 191 char sWall[]="0000";
maxint 8:b119501f4ef0 192 for(int i=0; i<strlen(sWalls); i+=5)
maxint 8:b119501f4ef0 193 {
maxint 8:b119501f4ef0 194 strncpy(sWall, sWalls+i, 4);
maxint 8:b119501f4ef0 195 addWall(sWall);
maxint 8:b119501f4ef0 196 }
maxint 8:b119501f4ef0 197 }
maxint 8:b119501f4ef0 198
maxint 7:6e7b789f4060 199
maxint 6:e2eead4e53fb 200 void Game::drawWalls()
maxint 2:d4de5a5866fe 201 {
maxint 6:e2eead4e53fb 202 for(int i=0; i<NUM_WALLS; i++)
maxint 6:e2eead4e53fb 203 if(aWalls[i].fActive)
maxint 6:e2eead4e53fb 204 {
maxint 6:e2eead4e53fb 205 aWalls[i].draw();
maxint 6:e2eead4e53fb 206 //snd.beepShort();
maxint 6:e2eead4e53fb 207 }
maxint 6:e2eead4e53fb 208 }
maxint 2:d4de5a5866fe 209
maxint 7:6e7b789f4060 210 void Game::addHole(char *sHole)
maxint 7:6e7b789f4060 211 { // add a wall based on a grid definition of 16x16 pixel squares, layed out in a 10x8 grid
maxint 7:6e7b789f4060 212 // sWall is a 4 character string containing the edge coordinates in decimal notation: xyXY
maxint 7:6e7b789f4060 213 // grid axis range from x: '0'-'9', ':'=10 - y: '0'-'8'
maxint 7:6e7b789f4060 214 for(int i=0; i<NUM_WALLS; i++)
maxint 7:6e7b789f4060 215 {
maxint 7:6e7b789f4060 216 if(!aHoles[i].fActive)
maxint 7:6e7b789f4060 217 {
maxint 8:b119501f4ef0 218 int x=(sHole[0]-'0')*16+8;
maxint 8:b119501f4ef0 219 int y=(sHole[1]-'0')*16+8;
maxint 7:6e7b789f4060 220 int r=sHole[2]-'0';
maxint 7:6e7b789f4060 221 int c=sHole[3]-'0';
maxint 8:b119501f4ef0 222 int rnd1=0, rnd2=0;
maxint 8:b119501f4ef0 223 if(r==2) rnd1=rand() % r - r/2;
maxint 8:b119501f4ef0 224 if(r==2) rnd2=rand() % r - r/2;
maxint 8:b119501f4ef0 225 aHoles[i].setCirc(Circle(x+rnd1,y+rnd2, Game::HOLE_RADIUS));
maxint 7:6e7b789f4060 226 if(c==1) aHoles[i].setColor(Color565::Green);
maxint 7:6e7b789f4060 227 if(c==2) aHoles[i].setColor(Color565::Gray);
maxint 7:6e7b789f4060 228 if(c==3) aHoles[i].setColor(Color565::Red);
maxint 7:6e7b789f4060 229 aHoles[i].fActive=true;
maxint 7:6e7b789f4060 230 //printf(0, 0, "H: %d,%d - %d,%d", x1, y1, r, c);
maxint 7:6e7b789f4060 231 break;
maxint 7:6e7b789f4060 232
maxint 7:6e7b789f4060 233 //aWalls[i].draw();
maxint 7:6e7b789f4060 234 //snd.beepShort();
maxint 7:6e7b789f4060 235 }
maxint 7:6e7b789f4060 236 }
maxint 7:6e7b789f4060 237 }
maxint 7:6e7b789f4060 238
maxint 8:b119501f4ef0 239 void Game::addHoles(char *sHoles)
maxint 8:b119501f4ef0 240 {
maxint 8:b119501f4ef0 241 char sHole[]="0000";
maxint 8:b119501f4ef0 242 for(int i=0; i<strlen(sHoles); i+=5)
maxint 8:b119501f4ef0 243 {
maxint 8:b119501f4ef0 244 strncpy(sHole, sHoles+i, 4);
maxint 8:b119501f4ef0 245 addHole(sHole);
maxint 8:b119501f4ef0 246 }
maxint 8:b119501f4ef0 247 }
maxint 8:b119501f4ef0 248
maxint 8:b119501f4ef0 249
maxint 7:6e7b789f4060 250 void Game::drawHoles()
maxint 7:6e7b789f4060 251 {
maxint 7:6e7b789f4060 252 for(int i=0; i<NUM_HOLES; i++)
maxint 7:6e7b789f4060 253 if(aHoles[i].fActive)
maxint 7:6e7b789f4060 254 {
maxint 7:6e7b789f4060 255 aHoles[i].draw();
maxint 7:6e7b789f4060 256 //snd.beepShort();
maxint 7:6e7b789f4060 257 }
maxint 7:6e7b789f4060 258 }
maxint 7:6e7b789f4060 259
maxint 7:6e7b789f4060 260
maxint 2:d4de5a5866fe 261
maxint 6:e2eead4e53fb 262 void Game::setNoBall()
maxint 6:e2eead4e53fb 263 { // make sure no balls are active
maxint 6:e2eead4e53fb 264 /* for(int i=0; i<NUM_BALLS; i++)
maxint 6:e2eead4e53fb 265 this->aBalls[i].fActive=false;
maxint 6:e2eead4e53fb 266 */
maxint 2:d4de5a5866fe 267 }
maxint 2:d4de5a5866fe 268
maxint 6:e2eead4e53fb 269 void Game::newBall()
maxint 6:e2eead4e53fb 270 { // add a ball to the game
maxint 6:e2eead4e53fb 271 Point ptBall=getGridPos("01");
maxint 6:e2eead4e53fb 272 ball.initialize(ptBall.getX(), ptBall.getY(), Game::BALL_RADIUS, Color565::White);
maxint 6:e2eead4e53fb 273 //float ftRandX=rand() % 2 ? 1 : -1;
maxint 6:e2eead4e53fb 274 //float ftRandY=rand() % 2 ? 1 : -1;
maxint 6:e2eead4e53fb 275 //this->aBalls[i].setSpeed(ftRandX, ftRandY);
maxint 6:e2eead4e53fb 276 // float ftRandX=((rand() % 20) - 10)/5.0; // left/right at random speed
maxint 6:e2eead4e53fb 277 // float ftRandY=((rand() % 10) - 10)/5.0; // up at random speed
maxint 6:e2eead4e53fb 278 // ball.vSpeed.set(ftRandX, ftRandY);
maxint 6:e2eead4e53fb 279 //this->aBalls[i].fActive=true;
maxint 2:d4de5a5866fe 280 }
maxint 2:d4de5a5866fe 281
maxint 6:e2eead4e53fb 282 void Game::updateBall()
maxint 6:e2eead4e53fb 283 {
maxint 6:e2eead4e53fb 284 ball.update(); // update the ball position
maxint 6:e2eead4e53fb 285
maxint 6:e2eead4e53fb 286 // increase speed based on gravity
maxint 6:e2eead4e53fb 287 checkTilt();
maxint 8:b119501f4ef0 288 if(ball.vSpeed.getSize()<2.0)
maxint 6:e2eead4e53fb 289 ball.vSpeed.add(this->vGravity); // add some gravity
maxint 6:e2eead4e53fb 290
maxint 6:e2eead4e53fb 291 // decrease speed based on friction
maxint 6:e2eead4e53fb 292 Vector vDecel=ball.vSpeed.getNormalized();
maxint 6:e2eead4e53fb 293 vDecel.multiply(vFriction);
maxint 6:e2eead4e53fb 294 ball.vSpeed.add(vDecel);
maxint 6:e2eead4e53fb 295 }
maxint 6:e2eead4e53fb 296
maxint 6:e2eead4e53fb 297 void Game::redrawBall()
maxint 6:e2eead4e53fb 298 {
maxint 6:e2eead4e53fb 299 ball.redraw(); // update the ball position
maxint 6:e2eead4e53fb 300 }
maxint 6:e2eead4e53fb 301
maxint 6:e2eead4e53fb 302 int Game::countBall()
maxint 2:d4de5a5866fe 303 {
maxint 2:d4de5a5866fe 304 int nResult=0;
maxint 6:e2eead4e53fb 305 /*
maxint 2:d4de5a5866fe 306 for(int i=0; i<NUM_BALLS; i++)
maxint 2:d4de5a5866fe 307 {
maxint 2:d4de5a5866fe 308 if(this->aBalls[i].fActive)
maxint 2:d4de5a5866fe 309 nResult++;
maxint 2:d4de5a5866fe 310 }
maxint 6:e2eead4e53fb 311 */
maxint 2:d4de5a5866fe 312 return(nResult);
maxint 2:d4de5a5866fe 313 }
maxint 2:d4de5a5866fe 314
maxint 2:d4de5a5866fe 315
maxint 2:d4de5a5866fe 316
maxint 2:d4de5a5866fe 317
maxint 2:d4de5a5866fe 318
maxint 2:d4de5a5866fe 319 void Game::tick()
maxint 2:d4de5a5866fe 320 {
maxint 6:e2eead4e53fb 321 checkButtons();
maxint 0:87ab172a74b4 322
maxint 6:e2eead4e53fb 323 if(mode)
maxint 6:e2eead4e53fb 324 {
maxint 0:87ab172a74b4 325 /*
maxint 0:87ab172a74b4 326 if(this->tWait.read_ms()>100)
maxint 0:87ab172a74b4 327 {
maxint 0:87ab172a74b4 328 this->tWait.reset();
maxint 0:87ab172a74b4 329 }
maxint 0:87ab172a74b4 330 */
maxint 2:d4de5a5866fe 331
maxint 6:e2eead4e53fb 332 updateBall(); // update the ball positions
maxint 0:87ab172a74b4 333
maxint 6:e2eead4e53fb 334 checkBallCollision();
maxint 5:67e75a4f0b52 335
maxint 6:e2eead4e53fb 336 redrawBall();
maxint 6:e2eead4e53fb 337
maxint 7:6e7b789f4060 338 if(this->tWait.read_ms()>100)
maxint 7:6e7b789f4060 339 { // redraw walls and holes every tenth second
maxint 7:6e7b789f4060 340 drawWalls();
maxint 7:6e7b789f4060 341 drawHoles();
maxint 7:6e7b789f4060 342
maxint 7:6e7b789f4060 343 checkNumBalls();
maxint 7:6e7b789f4060 344
maxint 7:6e7b789f4060 345 this->tWait.reset();
maxint 7:6e7b789f4060 346 }
maxint 0:87ab172a74b4 347
maxint 5:67e75a4f0b52 348 // this->snd.checkPwm();
maxint 1:c1ee4c699517 349 //this->checkScore();
maxint 6:e2eead4e53fb 350 //this->checkBall();
maxint 0:87ab172a74b4 351
maxint 6:e2eead4e53fb 352 wait_ms(nGameTickDelay); // can be adjusted using up/down
maxint 0:87ab172a74b4 353 }
maxint 6:e2eead4e53fb 354 else
maxint 6:e2eead4e53fb 355 {
maxint 6:e2eead4e53fb 356 accel.updateGraph();
maxint 0:87ab172a74b4 357 wait_ms(100);
maxint 0:87ab172a74b4 358 }
maxint 0:87ab172a74b4 359 }
maxint 0:87ab172a74b4 360
maxint 6:e2eead4e53fb 361 void Game::checkTilt()
maxint 6:e2eead4e53fb 362 { // move the gravity direction and weight by tilting the board
maxint 0:87ab172a74b4 363 double x, y, z;
maxint 0:87ab172a74b4 364 //int nStart=this->tWait.read_ms();
maxint 0:87ab172a74b4 365 this->accel.getXYZ(x, y, z);
maxint 0:87ab172a74b4 366
maxint 6:e2eead4e53fb 367 vGravity=Vector(x,y);
maxint 9:7bd5def2115d 368 while(vGravity.getSize()>0.5)
maxint 9:7bd5def2115d 369 vGravity.multiply(Vector(0.9, 0.9));
maxint 6:e2eead4e53fb 370 // vGravity=vGravity.getNormalized();
maxint 6:e2eead4e53fb 371
maxint 0:87ab172a74b4 372 //printDouble((double)this->tWait.read_ms()-nStart, 10, 10);
maxint 0:87ab172a74b4 373 /*
maxint 0:87ab172a74b4 374 printDouble(x, 0, 0);
maxint 0:87ab172a74b4 375 char buf[256];
maxint 0:87ab172a74b4 376 sprintf(buf,"tilt:%0.1f", x);
maxint 0:87ab172a74b4 377 this->drawString(buf, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2 + 4*DisplayN18::CHAR_HEIGHT );
maxint 0:87ab172a74b4 378 */
maxint 0:87ab172a74b4 379
maxint 6:e2eead4e53fb 380 //return(Vector(0,0));
maxint 0:87ab172a74b4 381 }
maxint 0:87ab172a74b4 382
maxint 0:87ab172a74b4 383 void Game::checkButtons()
maxint 0:87ab172a74b4 384 {
maxint 3:ca8b21da67dc 385 if(!this->square.read()) // note: button.read() is false (LOW/0) when pressed
maxint 0:87ab172a74b4 386 {
maxint 3:ca8b21da67dc 387 wait_ms(250); // el-cheapo deboounce
maxint 0:87ab172a74b4 388 this->mode = !this->mode;
maxint 0:87ab172a74b4 389
maxint 0:87ab172a74b4 390 //this->disp.clear();
maxint 0:87ab172a74b4 391 this->disp.clearScreen();
maxint 0:87ab172a74b4 392
maxint 0:87ab172a74b4 393 if (!this->mode)
maxint 0:87ab172a74b4 394 {
maxint 1:c1ee4c699517 395 this->accel.resetGraph();
maxint 0:87ab172a74b4 396 }
maxint 0:87ab172a74b4 397
maxint 0:87ab172a74b4 398 this->led1.write(this->mode);
maxint 0:87ab172a74b4 399 this->led2.write(!this->mode);
maxint 0:87ab172a74b4 400 }
maxint 3:ca8b21da67dc 401 else if(!this->circle.read() && this->mode) // note: button.read() is false (LOW/0) when pressed
maxint 3:ca8b21da67dc 402 {
maxint 3:ca8b21da67dc 403 bool fMute=this->snd.getMute();
maxint 3:ca8b21da67dc 404 fMute=!fMute;
maxint 3:ca8b21da67dc 405 this->snd.setMute(fMute);
maxint 3:ca8b21da67dc 406 this->led2.write(fMute);
maxint 3:ca8b21da67dc 407 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 408 }
maxint 0:87ab172a74b4 409 else
maxint 0:87ab172a74b4 410 {
maxint 0:87ab172a74b4 411 bool isUp = !this->up.read();
maxint 0:87ab172a74b4 412 bool isDown = !this->down.read();
maxint 9:7bd5def2115d 413
maxint 9:7bd5def2115d 414 if(!this->left.read())
maxint 9:7bd5def2115d 415 { // cheat: restart level
maxint 10:1d75861242f7 416 snd.play("T240 L128 O6 CEF");
maxint 9:7bd5def2115d 417 ball.fActive=false;
maxint 9:7bd5def2115d 418 initLevel();
maxint 9:7bd5def2115d 419 wait_ms(500);
maxint 9:7bd5def2115d 420 newBall(); // start a new ball
maxint 9:7bd5def2115d 421 return;
maxint 9:7bd5def2115d 422 }
maxint 9:7bd5def2115d 423 else if(!this->right.read())
maxint 9:7bd5def2115d 424 { // cheat: next level
maxint 10:1d75861242f7 425 snd.play("T240 L128 O5 FEC");
maxint 9:7bd5def2115d 426 nScore++;
maxint 9:7bd5def2115d 427 ball.fActive=false;
maxint 9:7bd5def2115d 428 initLevel();
maxint 9:7bd5def2115d 429 wait_ms(500);
maxint 9:7bd5def2115d 430 newBall(); // start a new ball
maxint 9:7bd5def2115d 431 return;
maxint 9:7bd5def2115d 432 }
maxint 9:7bd5def2115d 433
maxint 0:87ab172a74b4 434
maxint 0:87ab172a74b4 435 if (isUp && isDown) goto end;
maxint 0:87ab172a74b4 436 if (!isUp && !isDown) goto end;
maxint 0:87ab172a74b4 437
maxint 0:87ab172a74b4 438 if (isUp && this->lastUp) goto end;
maxint 0:87ab172a74b4 439 if (isDown && this->lastDown) goto end;
maxint 0:87ab172a74b4 440
maxint 0:87ab172a74b4 441 if (isUp)
maxint 0:87ab172a74b4 442 {
maxint 3:ca8b21da67dc 443 if(this->nGameTickDelay<1000) this->nGameTickDelay=(float)this->nGameTickDelay*1.20;
maxint 3:ca8b21da67dc 444 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 445 }
maxint 0:87ab172a74b4 446 else if (isDown)
maxint 0:87ab172a74b4 447 {
maxint 3:ca8b21da67dc 448 if(this->nGameTickDelay>5) this->nGameTickDelay=(float)this->nGameTickDelay/1.20;
maxint 3:ca8b21da67dc 449 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 450 }
maxint 0:87ab172a74b4 451
maxint 0:87ab172a74b4 452 end:
maxint 0:87ab172a74b4 453 this->lastUp = isUp;
maxint 0:87ab172a74b4 454 this->lastDown = isDown;
maxint 0:87ab172a74b4 455 }
maxint 0:87ab172a74b4 456 }
maxint 0:87ab172a74b4 457
maxint 1:c1ee4c699517 458 void Game::drawString(const char* str, int y)
maxint 1:c1ee4c699517 459 {
maxint 1:c1ee4c699517 460 uint8_t width;
maxint 1:c1ee4c699517 461 uint8_t height;
maxint 1:c1ee4c699517 462
maxint 1:c1ee4c699517 463 this->disp.measureString(font_oem, str, width, height);
maxint 1:c1ee4c699517 464 this->disp.drawString(font_oem, WIDTH / 2 - width / 2, y, str);
maxint 1:c1ee4c699517 465
maxint 0:87ab172a74b4 466 }
maxint 0:87ab172a74b4 467
maxint 6:e2eead4e53fb 468 void Game::showSplashScreen()
maxint 6:e2eead4e53fb 469 {
maxint 0:87ab172a74b4 470 this->drawString(Game::SPLASH_1, HEIGHT / 2 - CHAR_HEIGHT / 2);
maxint 0:87ab172a74b4 471 this->drawString(Game::SPLASH_2, HEIGHT / 2 + CHAR_HEIGHT / 2);
maxint 5:67e75a4f0b52 472 this->drawString(Game::SPLASH_3, HEIGHT / 2 + CHAR_HEIGHT / 2 + 2*CHAR_HEIGHT);
maxint 6:e2eead4e53fb 473
maxint 0:87ab172a74b4 474 while (this->circle.read())
maxint 0:87ab172a74b4 475 {
maxint 7:6e7b789f4060 476 //checkTilt();
maxint 7:6e7b789f4060 477 //printf(00, 120, "tilt: %.2f, %.2f ", vGravity.x, vGravity.y);
maxint 0:87ab172a74b4 478
maxint 0:87ab172a74b4 479 wait_ms(1);
maxint 0:87ab172a74b4 480 }
maxint 3:ca8b21da67dc 481 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 482
maxint 2:d4de5a5866fe 483 //this->disp.clearScreen();
maxint 2:d4de5a5866fe 484 this->initialize(); // start a new game
maxint 0:87ab172a74b4 485 }
maxint 0:87ab172a74b4 486
maxint 6:e2eead4e53fb 487 void Game::checkBallCollision()
maxint 2:d4de5a5866fe 488 {
maxint 3:ca8b21da67dc 489 Rectangle rTop=Rectangle(0, -10, WIDTH, this->nTopWall); // Rectangle(0, 0, WIDTH, 1); // top wall
maxint 2:d4de5a5866fe 490 Rectangle rBottom=Rectangle(0, HEIGHT, WIDTH, HEIGHT+10); // Rectangle(0, HEIGHT, WIDTH, HEIGHT); // bottom gap
maxint 2:d4de5a5866fe 491 Rectangle rLeft=Rectangle(-10, 0, 0, HEIGHT); // Rectangle(0, 0, 0, HEIGHT); // left wall
maxint 2:d4de5a5866fe 492 Rectangle rRight=Rectangle(WIDTH, 0, WIDTH+10, HEIGHT); // Rectangle(WIDTH, 0, WIDTH, HEIGHT); // right wall
maxint 2:d4de5a5866fe 493
maxint 6:e2eead4e53fb 494 if(ball.collides(rTop) && ball.vSpeed.isUp()) // top wall
maxint 6:e2eead4e53fb 495 {
maxint 6:e2eead4e53fb 496 ball.vSpeed.y=0;
maxint 6:e2eead4e53fb 497 //this->snd.beepShort();
maxint 6:e2eead4e53fb 498 }
maxint 6:e2eead4e53fb 499 if(ball.collides(rRight) && ball.vSpeed.isRight()) // right wall
maxint 6:e2eead4e53fb 500 {
maxint 6:e2eead4e53fb 501 ball.vSpeed.x=0;
maxint 6:e2eead4e53fb 502 //this->snd.beepShort();
maxint 6:e2eead4e53fb 503 }
maxint 6:e2eead4e53fb 504 if(ball.collides(rLeft) && ball.vSpeed.isLeft()) // left wall
maxint 6:e2eead4e53fb 505 {
maxint 6:e2eead4e53fb 506 ball.vSpeed.x=0;
maxint 6:e2eead4e53fb 507 //this->snd.beepShort();
maxint 6:e2eead4e53fb 508 }
maxint 6:e2eead4e53fb 509 if(ball.collides(rBottom) && ball.vSpeed.isDown()) // bottom wall
maxint 6:e2eead4e53fb 510 {
maxint 6:e2eead4e53fb 511 ball.vSpeed.y=0;
maxint 6:e2eead4e53fb 512 //this->snd.beepShort();
maxint 6:e2eead4e53fb 513 }
maxint 6:e2eead4e53fb 514
maxint 9:7bd5def2115d 515 for(int i=0; i<NUM_WALLS; i++) // check maze walls
maxint 6:e2eead4e53fb 516 {
maxint 6:e2eead4e53fb 517 if(aWalls[i].fActive)
maxint 2:d4de5a5866fe 518 {
maxint 6:e2eead4e53fb 519 Rectangle rWall=aWalls[i].getRect();
maxint 6:e2eead4e53fb 520 if(ball.collides(rWall))
maxint 2:d4de5a5866fe 521 {
maxint 7:6e7b789f4060 522 //printf(30, 0, "b: %.2f", ball.vSpeed.getSize());
maxint 6:e2eead4e53fb 523 if(rWall.isHorizontal())
maxint 7:6e7b789f4060 524 {
maxint 7:6e7b789f4060 525 if(fabs(ball.vSpeed.y)>0.8)
maxint 7:6e7b789f4060 526 snd.play("T240 L128 O4 A");
maxint 7:6e7b789f4060 527 ball.Bounce(Vector(1,-0.1));
maxint 7:6e7b789f4060 528 }
maxint 6:e2eead4e53fb 529 else
maxint 7:6e7b789f4060 530 {
maxint 7:6e7b789f4060 531 if(fabs(ball.vSpeed.x)>0.8)
maxint 7:6e7b789f4060 532 snd.play("T240 L128 O4 A");
maxint 7:6e7b789f4060 533 ball.Bounce(Vector(-0.1,1));
maxint 7:6e7b789f4060 534 }
maxint 6:e2eead4e53fb 535 //ball.vSpeed.multiply(Vector(0,0));
maxint 9:7bd5def2115d 536
maxint 6:e2eead4e53fb 537 aWalls[i].draw();
maxint 3:ca8b21da67dc 538 }
maxint 6:e2eead4e53fb 539 //printf(0, 100, "W: %d,%d - %d,%d", rWall.getX1(), rWall.getY1(), rWall.getX2(), rWall.getY2());
maxint 2:d4de5a5866fe 540 }
maxint 0:87ab172a74b4 541 }
maxint 7:6e7b789f4060 542
maxint 9:7bd5def2115d 543 for(int i=0; i<NUM_HOLES; i++) // check holes
maxint 7:6e7b789f4060 544 {
maxint 7:6e7b789f4060 545 if(aHoles[i].fActive)
maxint 7:6e7b789f4060 546 {
maxint 7:6e7b789f4060 547 Circle cHole=aHoles[i].getCirc();
maxint 7:6e7b789f4060 548 if(ball.collides(cHole))
maxint 7:6e7b789f4060 549 {
maxint 7:6e7b789f4060 550 //snd.play("T240 L128 O5 C");
maxint 7:6e7b789f4060 551 if(aHoles[i].hasGoneIn(ball.getBoundingCircle()))
maxint 7:6e7b789f4060 552 {
maxint 7:6e7b789f4060 553 //snd.play("T240 L128 O5 C");
maxint 8:b119501f4ef0 554 ball.fActive=false;
maxint 7:6e7b789f4060 555 if(i==0)
maxint 7:6e7b789f4060 556 { // TODO: for now first hole is target hole
maxint 8:b119501f4ef0 557 nScore++;
maxint 8:b119501f4ef0 558 snd.play("T240 L16 O5 CDEFG");
maxint 7:6e7b789f4060 559 }
maxint 7:6e7b789f4060 560 else
maxint 7:6e7b789f4060 561 {
maxint 8:b119501f4ef0 562 nBalls--;
maxint 8:b119501f4ef0 563 snd.beepLow();
maxint 7:6e7b789f4060 564 }
maxint 8:b119501f4ef0 565
maxint 8:b119501f4ef0 566 initLevel();
maxint 9:7bd5def2115d 567 wait_ms(500);
maxint 8:b119501f4ef0 568
maxint 8:b119501f4ef0 569 newBall(); // start a new ball
maxint 7:6e7b789f4060 570
maxint 7:6e7b789f4060 571 }
maxint 7:6e7b789f4060 572 }
maxint 7:6e7b789f4060 573 }
maxint 7:6e7b789f4060 574 }
maxint 6:e2eead4e53fb 575
maxint 6:e2eead4e53fb 576
maxint 2:d4de5a5866fe 577 }
maxint 2:d4de5a5866fe 578
maxint 0:87ab172a74b4 579
maxint 1:c1ee4c699517 580 void Game::printf(int x, int y, const char *szFormat, ...)
maxint 0:87ab172a74b4 581 {
maxint 0:87ab172a74b4 582 char szBuffer[256];
maxint 0:87ab172a74b4 583 va_list args;
maxint 0:87ab172a74b4 584
maxint 0:87ab172a74b4 585 va_start(args, szFormat);
maxint 0:87ab172a74b4 586 vsprintf(szBuffer, szFormat, args);
maxint 0:87ab172a74b4 587 va_end(args);
maxint 1:c1ee4c699517 588 this->disp.drawString(font_oem, x, y, szBuffer);
maxint 0:87ab172a74b4 589 }
maxint 7:6e7b789f4060 590
maxint 7:6e7b789f4060 591 void Game::checkNumBalls()
maxint 7:6e7b789f4060 592 {
maxint 7:6e7b789f4060 593 if (this->nBalls == 0)
maxint 7:6e7b789f4060 594 { // game over
maxint 7:6e7b789f4060 595 char buf[256];
maxint 7:6e7b789f4060 596 this->disp.clearScreen();
maxint 7:6e7b789f4060 597
maxint 7:6e7b789f4060 598 this->drawString(Game::LOSE_1, HEIGHT / 2 - CHAR_HEIGHT);
maxint 7:6e7b789f4060 599 this->drawString(Game::LOSE_2, HEIGHT / 2);
maxint 7:6e7b789f4060 600 sprintf(buf,"Your score: %d ", this->nScore);
maxint 7:6e7b789f4060 601 this->drawString(buf, HEIGHT / 2 + CHAR_HEIGHT / 2 + CHAR_HEIGHT );
maxint 7:6e7b789f4060 602
maxint 7:6e7b789f4060 603 this->snd.play("T120 O3 L4 R4 F C F2 C");
maxint 7:6e7b789f4060 604 while (this->circle.read())
maxint 7:6e7b789f4060 605 wait_ms(1);
maxint 7:6e7b789f4060 606 wait_ms(250); // el-cheapo deboounce
maxint 7:6e7b789f4060 607 this->initialize();
maxint 7:6e7b789f4060 608 }
maxint 7:6e7b789f4060 609 else
maxint 7:6e7b789f4060 610 {
maxint 7:6e7b789f4060 611 printf(0, 0, "Balls: %d ", this->nBalls);
maxint 7:6e7b789f4060 612 printf(100, 0, "Score: %d ", this->nScore);
maxint 7:6e7b789f4060 613 }
maxint 7:6e7b789f4060 614 }