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 19:41:00 2015 +0000
Revision:
8:b119501f4ef0
Parent:
7:6e7b789f4060
Child:
9:7bd5def2115d
multiple 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 6:e2eead4e53fb 368 // vGravity=vGravity.getNormalized();
maxint 6:e2eead4e53fb 369
maxint 0:87ab172a74b4 370 //printDouble((double)this->tWait.read_ms()-nStart, 10, 10);
maxint 0:87ab172a74b4 371 /*
maxint 0:87ab172a74b4 372 printDouble(x, 0, 0);
maxint 0:87ab172a74b4 373 char buf[256];
maxint 0:87ab172a74b4 374 sprintf(buf,"tilt:%0.1f", x);
maxint 0:87ab172a74b4 375 this->drawString(buf, DisplayN18::HEIGHT / 2 - DisplayN18::CHAR_HEIGHT / 2 + 4*DisplayN18::CHAR_HEIGHT );
maxint 0:87ab172a74b4 376 */
maxint 0:87ab172a74b4 377
maxint 6:e2eead4e53fb 378 //return(Vector(0,0));
maxint 0:87ab172a74b4 379 }
maxint 0:87ab172a74b4 380
maxint 0:87ab172a74b4 381 void Game::checkButtons()
maxint 0:87ab172a74b4 382 {
maxint 3:ca8b21da67dc 383 if(!this->square.read()) // note: button.read() is false (LOW/0) when pressed
maxint 0:87ab172a74b4 384 {
maxint 3:ca8b21da67dc 385 wait_ms(250); // el-cheapo deboounce
maxint 0:87ab172a74b4 386 this->mode = !this->mode;
maxint 0:87ab172a74b4 387
maxint 0:87ab172a74b4 388 //this->disp.clear();
maxint 0:87ab172a74b4 389 this->disp.clearScreen();
maxint 0:87ab172a74b4 390
maxint 0:87ab172a74b4 391 if (!this->mode)
maxint 0:87ab172a74b4 392 {
maxint 1:c1ee4c699517 393 this->accel.resetGraph();
maxint 0:87ab172a74b4 394 }
maxint 0:87ab172a74b4 395
maxint 0:87ab172a74b4 396 this->led1.write(this->mode);
maxint 0:87ab172a74b4 397 this->led2.write(!this->mode);
maxint 0:87ab172a74b4 398 }
maxint 3:ca8b21da67dc 399 else if(!this->circle.read() && this->mode) // note: button.read() is false (LOW/0) when pressed
maxint 3:ca8b21da67dc 400 {
maxint 3:ca8b21da67dc 401 bool fMute=this->snd.getMute();
maxint 3:ca8b21da67dc 402 fMute=!fMute;
maxint 3:ca8b21da67dc 403 this->snd.setMute(fMute);
maxint 3:ca8b21da67dc 404 this->led2.write(fMute);
maxint 3:ca8b21da67dc 405 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 406 }
maxint 0:87ab172a74b4 407 else
maxint 0:87ab172a74b4 408 {
maxint 0:87ab172a74b4 409 bool isUp = !this->up.read();
maxint 0:87ab172a74b4 410 bool isDown = !this->down.read();
maxint 0:87ab172a74b4 411
maxint 0:87ab172a74b4 412 if (isUp && isDown) goto end;
maxint 0:87ab172a74b4 413 if (!isUp && !isDown) goto end;
maxint 0:87ab172a74b4 414
maxint 0:87ab172a74b4 415 if (isUp && this->lastUp) goto end;
maxint 0:87ab172a74b4 416 if (isDown && this->lastDown) goto end;
maxint 0:87ab172a74b4 417
maxint 0:87ab172a74b4 418 if (isUp)
maxint 0:87ab172a74b4 419 {
maxint 3:ca8b21da67dc 420 if(this->nGameTickDelay<1000) this->nGameTickDelay=(float)this->nGameTickDelay*1.20;
maxint 3:ca8b21da67dc 421 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 422 }
maxint 0:87ab172a74b4 423 else if (isDown)
maxint 0:87ab172a74b4 424 {
maxint 3:ca8b21da67dc 425 if(this->nGameTickDelay>5) this->nGameTickDelay=(float)this->nGameTickDelay/1.20;
maxint 3:ca8b21da67dc 426 this->printf(100, 0, "Speed: %d ", this->nGameTickDelay);
maxint 0:87ab172a74b4 427 }
maxint 0:87ab172a74b4 428
maxint 0:87ab172a74b4 429 end:
maxint 0:87ab172a74b4 430 this->lastUp = isUp;
maxint 0:87ab172a74b4 431 this->lastDown = isDown;
maxint 0:87ab172a74b4 432 }
maxint 0:87ab172a74b4 433 }
maxint 0:87ab172a74b4 434
maxint 1:c1ee4c699517 435 void Game::drawString(const char* str, int y)
maxint 1:c1ee4c699517 436 {
maxint 1:c1ee4c699517 437 uint8_t width;
maxint 1:c1ee4c699517 438 uint8_t height;
maxint 1:c1ee4c699517 439
maxint 1:c1ee4c699517 440 this->disp.measureString(font_oem, str, width, height);
maxint 1:c1ee4c699517 441 this->disp.drawString(font_oem, WIDTH / 2 - width / 2, y, str);
maxint 1:c1ee4c699517 442
maxint 0:87ab172a74b4 443 }
maxint 0:87ab172a74b4 444
maxint 6:e2eead4e53fb 445 void Game::showSplashScreen()
maxint 6:e2eead4e53fb 446 {
maxint 0:87ab172a74b4 447 this->drawString(Game::SPLASH_1, HEIGHT / 2 - CHAR_HEIGHT / 2);
maxint 0:87ab172a74b4 448 this->drawString(Game::SPLASH_2, HEIGHT / 2 + CHAR_HEIGHT / 2);
maxint 5:67e75a4f0b52 449 this->drawString(Game::SPLASH_3, HEIGHT / 2 + CHAR_HEIGHT / 2 + 2*CHAR_HEIGHT);
maxint 6:e2eead4e53fb 450
maxint 0:87ab172a74b4 451 while (this->circle.read())
maxint 0:87ab172a74b4 452 {
maxint 7:6e7b789f4060 453 //checkTilt();
maxint 7:6e7b789f4060 454 //printf(00, 120, "tilt: %.2f, %.2f ", vGravity.x, vGravity.y);
maxint 0:87ab172a74b4 455
maxint 0:87ab172a74b4 456 wait_ms(1);
maxint 0:87ab172a74b4 457 }
maxint 3:ca8b21da67dc 458 wait_ms(250); // el-cheapo deboounce
maxint 3:ca8b21da67dc 459
maxint 2:d4de5a5866fe 460 //this->disp.clearScreen();
maxint 2:d4de5a5866fe 461 this->initialize(); // start a new game
maxint 0:87ab172a74b4 462 }
maxint 0:87ab172a74b4 463
maxint 6:e2eead4e53fb 464 void Game::checkBallCollision()
maxint 2:d4de5a5866fe 465 {
maxint 3:ca8b21da67dc 466 Rectangle rTop=Rectangle(0, -10, WIDTH, this->nTopWall); // Rectangle(0, 0, WIDTH, 1); // top wall
maxint 2:d4de5a5866fe 467 Rectangle rBottom=Rectangle(0, HEIGHT, WIDTH, HEIGHT+10); // Rectangle(0, HEIGHT, WIDTH, HEIGHT); // bottom gap
maxint 2:d4de5a5866fe 468 Rectangle rLeft=Rectangle(-10, 0, 0, HEIGHT); // Rectangle(0, 0, 0, HEIGHT); // left wall
maxint 2:d4de5a5866fe 469 Rectangle rRight=Rectangle(WIDTH, 0, WIDTH+10, HEIGHT); // Rectangle(WIDTH, 0, WIDTH, HEIGHT); // right wall
maxint 2:d4de5a5866fe 470
maxint 6:e2eead4e53fb 471 if(ball.collides(rTop) && ball.vSpeed.isUp()) // top wall
maxint 6:e2eead4e53fb 472 {
maxint 6:e2eead4e53fb 473 ball.vSpeed.y=0;
maxint 6:e2eead4e53fb 474 //this->snd.beepShort();
maxint 6:e2eead4e53fb 475 }
maxint 6:e2eead4e53fb 476 if(ball.collides(rRight) && ball.vSpeed.isRight()) // right wall
maxint 6:e2eead4e53fb 477 {
maxint 6:e2eead4e53fb 478 ball.vSpeed.x=0;
maxint 6:e2eead4e53fb 479 //this->snd.beepShort();
maxint 6:e2eead4e53fb 480 }
maxint 6:e2eead4e53fb 481 if(ball.collides(rLeft) && ball.vSpeed.isLeft()) // left wall
maxint 6:e2eead4e53fb 482 {
maxint 6:e2eead4e53fb 483 ball.vSpeed.x=0;
maxint 6:e2eead4e53fb 484 //this->snd.beepShort();
maxint 6:e2eead4e53fb 485 }
maxint 6:e2eead4e53fb 486 if(ball.collides(rBottom) && ball.vSpeed.isDown()) // bottom wall
maxint 6:e2eead4e53fb 487 {
maxint 6:e2eead4e53fb 488 ball.vSpeed.y=0;
maxint 6:e2eead4e53fb 489 //this->snd.beepShort();
maxint 6:e2eead4e53fb 490 }
maxint 6:e2eead4e53fb 491
maxint 7:6e7b789f4060 492 for(int i=0; i<NUM_WALLS; i++) // test maze walls
maxint 6:e2eead4e53fb 493 {
maxint 6:e2eead4e53fb 494 if(aWalls[i].fActive)
maxint 2:d4de5a5866fe 495 {
maxint 6:e2eead4e53fb 496 Rectangle rWall=aWalls[i].getRect();
maxint 6:e2eead4e53fb 497 if(ball.collides(rWall))
maxint 2:d4de5a5866fe 498 {
maxint 7:6e7b789f4060 499 //printf(30, 0, "b: %.2f", ball.vSpeed.getSize());
maxint 6:e2eead4e53fb 500 if(rWall.isHorizontal())
maxint 7:6e7b789f4060 501 {
maxint 7:6e7b789f4060 502 if(fabs(ball.vSpeed.y)>0.8)
maxint 7:6e7b789f4060 503 snd.play("T240 L128 O4 A");
maxint 7:6e7b789f4060 504 ball.Bounce(Vector(1,-0.1));
maxint 7:6e7b789f4060 505 }
maxint 6:e2eead4e53fb 506 else
maxint 7:6e7b789f4060 507 {
maxint 7:6e7b789f4060 508 if(fabs(ball.vSpeed.x)>0.8)
maxint 7:6e7b789f4060 509 snd.play("T240 L128 O4 A");
maxint 7:6e7b789f4060 510 ball.Bounce(Vector(-0.1,1));
maxint 7:6e7b789f4060 511 }
maxint 6:e2eead4e53fb 512 //ball.vSpeed.multiply(Vector(0,0));
maxint 6:e2eead4e53fb 513 aWalls[i].draw();
maxint 3:ca8b21da67dc 514 }
maxint 6:e2eead4e53fb 515 //printf(0, 100, "W: %d,%d - %d,%d", rWall.getX1(), rWall.getY1(), rWall.getX2(), rWall.getY2());
maxint 2:d4de5a5866fe 516 }
maxint 0:87ab172a74b4 517 }
maxint 7:6e7b789f4060 518
maxint 7:6e7b789f4060 519 for(int i=0; i<NUM_HOLES; i++) // test holes
maxint 7:6e7b789f4060 520 {
maxint 7:6e7b789f4060 521 if(aHoles[i].fActive)
maxint 7:6e7b789f4060 522 {
maxint 7:6e7b789f4060 523 Circle cHole=aHoles[i].getCirc();
maxint 7:6e7b789f4060 524 if(ball.collides(cHole))
maxint 7:6e7b789f4060 525 {
maxint 7:6e7b789f4060 526 //snd.play("T240 L128 O5 C");
maxint 7:6e7b789f4060 527 if(aHoles[i].hasGoneIn(ball.getBoundingCircle()))
maxint 7:6e7b789f4060 528 {
maxint 7:6e7b789f4060 529 //snd.play("T240 L128 O5 C");
maxint 8:b119501f4ef0 530 ball.fActive=false;
maxint 7:6e7b789f4060 531 if(i==0)
maxint 7:6e7b789f4060 532 { // TODO: for now first hole is target hole
maxint 8:b119501f4ef0 533 nScore++;
maxint 8:b119501f4ef0 534 snd.play("T240 L16 O5 CDEFG");
maxint 7:6e7b789f4060 535 }
maxint 7:6e7b789f4060 536 else
maxint 7:6e7b789f4060 537 {
maxint 8:b119501f4ef0 538 nBalls--;
maxint 8:b119501f4ef0 539 snd.beepLow();
maxint 7:6e7b789f4060 540 }
maxint 8:b119501f4ef0 541
maxint 8:b119501f4ef0 542 initLevel();
maxint 8:b119501f4ef0 543
maxint 8:b119501f4ef0 544 newBall(); // start a new ball
maxint 7:6e7b789f4060 545
maxint 7:6e7b789f4060 546 }
maxint 7:6e7b789f4060 547 }
maxint 7:6e7b789f4060 548 }
maxint 7:6e7b789f4060 549 }
maxint 6:e2eead4e53fb 550
maxint 6:e2eead4e53fb 551
maxint 2:d4de5a5866fe 552 }
maxint 2:d4de5a5866fe 553
maxint 0:87ab172a74b4 554
maxint 1:c1ee4c699517 555 void Game::printf(int x, int y, const char *szFormat, ...)
maxint 0:87ab172a74b4 556 {
maxint 0:87ab172a74b4 557 char szBuffer[256];
maxint 0:87ab172a74b4 558 va_list args;
maxint 0:87ab172a74b4 559
maxint 0:87ab172a74b4 560 va_start(args, szFormat);
maxint 0:87ab172a74b4 561 vsprintf(szBuffer, szFormat, args);
maxint 0:87ab172a74b4 562 va_end(args);
maxint 1:c1ee4c699517 563 this->disp.drawString(font_oem, x, y, szBuffer);
maxint 0:87ab172a74b4 564 }
maxint 7:6e7b789f4060 565
maxint 7:6e7b789f4060 566 void Game::checkNumBalls()
maxint 7:6e7b789f4060 567 {
maxint 7:6e7b789f4060 568 if (this->nBalls == 0)
maxint 7:6e7b789f4060 569 { // game over
maxint 7:6e7b789f4060 570 char buf[256];
maxint 7:6e7b789f4060 571 this->disp.clearScreen();
maxint 7:6e7b789f4060 572
maxint 7:6e7b789f4060 573 this->drawString(Game::LOSE_1, HEIGHT / 2 - CHAR_HEIGHT);
maxint 7:6e7b789f4060 574 this->drawString(Game::LOSE_2, HEIGHT / 2);
maxint 7:6e7b789f4060 575 sprintf(buf,"Your score: %d ", this->nScore);
maxint 7:6e7b789f4060 576 this->drawString(buf, HEIGHT / 2 + CHAR_HEIGHT / 2 + CHAR_HEIGHT );
maxint 7:6e7b789f4060 577
maxint 7:6e7b789f4060 578 this->snd.play("T120 O3 L4 R4 F C F2 C");
maxint 7:6e7b789f4060 579 while (this->circle.read())
maxint 7:6e7b789f4060 580 wait_ms(1);
maxint 7:6e7b789f4060 581 wait_ms(250); // el-cheapo deboounce
maxint 7:6e7b789f4060 582 this->initialize();
maxint 7:6e7b789f4060 583 }
maxint 7:6e7b789f4060 584 else
maxint 7:6e7b789f4060 585 {
maxint 7:6e7b789f4060 586 printf(0, 0, "Balls: %d ", this->nBalls);
maxint 7:6e7b789f4060 587 printf(100, 0, "Score: %d ", this->nScore);
maxint 7:6e7b789f4060 588 }
maxint 7:6e7b789f4060 589 }