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 10:23:48 2015 +0000
Revision:
9:7bd5def2115d
Parent:
8:b119501f4ef0
Child:
10:1d75861242f7
added cheat buttons to show higher levels

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 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 9:7bd5def2115d 416 snd.playTune();
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 9:7bd5def2115d 425 snd.playTune();
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 9:7bd5def2115d 537 // TODO: workaround for stuck-in-wall bug
maxint 9:7bd5def2115d 538 if(ball.collides(rWall))
maxint 9:7bd5def2115d 539 {
maxint 9:7bd5def2115d 540 snd.beepLow();
maxint 9:7bd5def2115d 541 ball.fActive=false;
maxint 9:7bd5def2115d 542 initLevel();
maxint 9:7bd5def2115d 543 wait_ms(500);
maxint 9:7bd5def2115d 544 newBall(); // start a new ball
maxint 9:7bd5def2115d 545 }
maxint 9:7bd5def2115d 546
maxint 9:7bd5def2115d 547
maxint 9:7bd5def2115d 548
maxint 9:7bd5def2115d 549
maxint 6:e2eead4e53fb 550 aWalls[i].draw();
maxint 3:ca8b21da67dc 551 }
maxint 6:e2eead4e53fb 552 //printf(0, 100, "W: %d,%d - %d,%d", rWall.getX1(), rWall.getY1(), rWall.getX2(), rWall.getY2());
maxint 2:d4de5a5866fe 553 }
maxint 0:87ab172a74b4 554 }
maxint 7:6e7b789f4060 555
maxint 9:7bd5def2115d 556 for(int i=0; i<NUM_HOLES; i++) // check holes
maxint 7:6e7b789f4060 557 {
maxint 7:6e7b789f4060 558 if(aHoles[i].fActive)
maxint 7:6e7b789f4060 559 {
maxint 7:6e7b789f4060 560 Circle cHole=aHoles[i].getCirc();
maxint 7:6e7b789f4060 561 if(ball.collides(cHole))
maxint 7:6e7b789f4060 562 {
maxint 7:6e7b789f4060 563 //snd.play("T240 L128 O5 C");
maxint 7:6e7b789f4060 564 if(aHoles[i].hasGoneIn(ball.getBoundingCircle()))
maxint 7:6e7b789f4060 565 {
maxint 7:6e7b789f4060 566 //snd.play("T240 L128 O5 C");
maxint 8:b119501f4ef0 567 ball.fActive=false;
maxint 7:6e7b789f4060 568 if(i==0)
maxint 7:6e7b789f4060 569 { // TODO: for now first hole is target hole
maxint 8:b119501f4ef0 570 nScore++;
maxint 8:b119501f4ef0 571 snd.play("T240 L16 O5 CDEFG");
maxint 7:6e7b789f4060 572 }
maxint 7:6e7b789f4060 573 else
maxint 7:6e7b789f4060 574 {
maxint 8:b119501f4ef0 575 nBalls--;
maxint 8:b119501f4ef0 576 snd.beepLow();
maxint 7:6e7b789f4060 577 }
maxint 8:b119501f4ef0 578
maxint 8:b119501f4ef0 579 initLevel();
maxint 9:7bd5def2115d 580 wait_ms(500);
maxint 8:b119501f4ef0 581
maxint 8:b119501f4ef0 582 newBall(); // start a new ball
maxint 7:6e7b789f4060 583
maxint 7:6e7b789f4060 584 }
maxint 7:6e7b789f4060 585 }
maxint 7:6e7b789f4060 586 }
maxint 7:6e7b789f4060 587 }
maxint 6:e2eead4e53fb 588
maxint 6:e2eead4e53fb 589
maxint 2:d4de5a5866fe 590 }
maxint 2:d4de5a5866fe 591
maxint 0:87ab172a74b4 592
maxint 1:c1ee4c699517 593 void Game::printf(int x, int y, const char *szFormat, ...)
maxint 0:87ab172a74b4 594 {
maxint 0:87ab172a74b4 595 char szBuffer[256];
maxint 0:87ab172a74b4 596 va_list args;
maxint 0:87ab172a74b4 597
maxint 0:87ab172a74b4 598 va_start(args, szFormat);
maxint 0:87ab172a74b4 599 vsprintf(szBuffer, szFormat, args);
maxint 0:87ab172a74b4 600 va_end(args);
maxint 1:c1ee4c699517 601 this->disp.drawString(font_oem, x, y, szBuffer);
maxint 0:87ab172a74b4 602 }
maxint 7:6e7b789f4060 603
maxint 7:6e7b789f4060 604 void Game::checkNumBalls()
maxint 7:6e7b789f4060 605 {
maxint 7:6e7b789f4060 606 if (this->nBalls == 0)
maxint 7:6e7b789f4060 607 { // game over
maxint 7:6e7b789f4060 608 char buf[256];
maxint 7:6e7b789f4060 609 this->disp.clearScreen();
maxint 7:6e7b789f4060 610
maxint 7:6e7b789f4060 611 this->drawString(Game::LOSE_1, HEIGHT / 2 - CHAR_HEIGHT);
maxint 7:6e7b789f4060 612 this->drawString(Game::LOSE_2, HEIGHT / 2);
maxint 7:6e7b789f4060 613 sprintf(buf,"Your score: %d ", this->nScore);
maxint 7:6e7b789f4060 614 this->drawString(buf, HEIGHT / 2 + CHAR_HEIGHT / 2 + CHAR_HEIGHT );
maxint 7:6e7b789f4060 615
maxint 7:6e7b789f4060 616 this->snd.play("T120 O3 L4 R4 F C F2 C");
maxint 7:6e7b789f4060 617 while (this->circle.read())
maxint 7:6e7b789f4060 618 wait_ms(1);
maxint 7:6e7b789f4060 619 wait_ms(250); // el-cheapo deboounce
maxint 7:6e7b789f4060 620 this->initialize();
maxint 7:6e7b789f4060 621 }
maxint 7:6e7b789f4060 622 else
maxint 7:6e7b789f4060 623 {
maxint 7:6e7b789f4060 624 printf(0, 0, "Balls: %d ", this->nBalls);
maxint 7:6e7b789f4060 625 printf(100, 0, "Score: %d ", this->nScore);
maxint 7:6e7b789f4060 626 }
maxint 7:6e7b789f4060 627 }