FINAL VERSION

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BreakoutEngine.cpp Source File

BreakoutEngine.cpp

00001 #include "BreakoutEngine.h"
00002 
00003 BreakoutEngine::BreakoutEngine()
00004 {
00005 
00006 }
00007 
00008 BreakoutEngine::~BreakoutEngine()
00009 {
00010 
00011 }
00012 
00013 void BreakoutEngine::init(int paddle_width,int paddle_height,int ball_size,int speed)
00014 {
00015     // initialise the game parameters
00016     _paddle_width = paddle_width;
00017     _paddle_height = paddle_height;
00018     _ball_size = ball_size; // size of the ball
00019     _speed = speed; // speed of the ball
00020     _number_left = 18; // number of bricks that remain on screen
00021     _index = 0;  // index of which laser to move on screen at any time, starts at 0
00022     _cool_time = 0.0f; // time remaining before laser can be fired again, starts at 0
00023     _score = 0; // initialised as 0
00024     _prev_score = 0;  // initialised as 0 for the first round
00025     _multiplier = 0;  // initialised as 1 for the first round
00026 
00027     // y position of the paddle on screen - HEIGHT is defined in N5110.h
00028     _paddley = HEIGHT - GAP - 1;
00029 
00030     // initialises paddles and ball in middle
00031     _paddle.init(_paddley,_paddle_height,_paddle_width);
00032     _ball.init(_ball_size,_speed,_paddle.get_pos().x + (PADDLE_WIDTH/2));
00033 
00034     // initialises all the bricks in their set x/y positions
00035     _brick11.init(3,GAP_TOP+1,3);
00036     _brick12.init(16,GAP_TOP+1,3);
00037     _brick13.init(29,GAP_TOP+1,3);
00038     _brick14.init(42,GAP_TOP+1,3);
00039     _brick15.init(55,GAP_TOP+1,3);
00040     _brick16.init(68,GAP_TOP+1,3);
00041 
00042     _brick21.init(3,GAP_TOP+BRICK_HEIGHT+2,2);
00043     _brick22.init(16,GAP_TOP+BRICK_HEIGHT+2,2);
00044     _brick23.init(29,GAP_TOP+BRICK_HEIGHT+2,2);
00045     _brick24.init(42,GAP_TOP+BRICK_HEIGHT+2,2);
00046     _brick25.init(55,GAP_TOP+BRICK_HEIGHT+2,2);
00047     _brick26.init(68,GAP_TOP+BRICK_HEIGHT+2,2);
00048 
00049     _brick31.init(3,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1);
00050     _brick32.init(16,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1);
00051     _brick33.init(29,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1);
00052     _brick34.init(42,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1);
00053     _brick35.init(55,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1);
00054     _brick36.init(68,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1);
00055 
00056     // appends all bricks to a list so that they are easier to check for collisions
00057     listofBricks.push_back(_brick11);
00058     listofBricks.push_back(_brick12);
00059     listofBricks.push_back(_brick13);
00060     listofBricks.push_back(_brick14);
00061     listofBricks.push_back(_brick15);
00062     listofBricks.push_back(_brick16);
00063     listofBricks.push_back(_brick21);
00064     listofBricks.push_back(_brick22);
00065     listofBricks.push_back(_brick23);
00066     listofBricks.push_back(_brick24);
00067     listofBricks.push_back(_brick25);
00068     listofBricks.push_back(_brick26);
00069     listofBricks.push_back(_brick31);
00070     listofBricks.push_back(_brick32);
00071     listofBricks.push_back(_brick33);
00072     listofBricks.push_back(_brick34);
00073     listofBricks.push_back(_brick35);
00074     listofBricks.push_back(_brick36);
00075 
00076     // initialises lasers off screen
00077     _laser1.init();
00078     _laser2.init();
00079     _laser3.init();
00080 
00081     // appends lasers to a list so that they are easier to check for collisions
00082     listofLasers.push_back(_laser1);
00083     listofLasers.push_back(_laser2);
00084     listofLasers.push_back(_laser3);
00085 
00086     _powerup.init();
00087 }
00088 
00089 
00090 void BreakoutEngine::reset_game()  // resets the game after victory screen
00091 {
00092     reset_num_left();   // resets _number_left to 18
00093     _paddle.recentre();  // recentres the paddle on screen
00094     //printf("Paddle lives = %d", _paddle.get_lives());
00095     _ball.init(_ball_size,_speed + _multiplier/2, _paddle.get_pos().x + (PADDLE_WIDTH/2)); // resets the ball position to above the paddle, and increases its speed depending on the _multiplier
00096     _powerup.set_posx(-50);
00097 
00098     int pointer = 0;  // tracks the rows, if 6 bricks are placed, it moves to the next row
00099     for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) {
00100         if (pointer <= 5) {  // 6 bricks in the first row
00101             it_R -> set_posx((pointer * 13) + 3);
00102         } else if (pointer <= 11) {
00103             it_R -> set_posx(((pointer-6) * 13) + 3);  // pointer - 6 to offset it back to the first column of bricks
00104         } else if (pointer <= 17) {
00105             it_R -> set_posx(((pointer-12) * 13) + 3);  // pointer - 12 to offset it back to the first column of bricks
00106         }
00107 
00108         it_R -> reset_lives(_multiplier);  // increases the bricks number of lives by the multiplier + their _base_lives
00109         pointer ++;  // increment the pointer
00110         //printf("pointer = %d",pointer);
00111     }
00112     for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) {
00113         it_L -> set_posx(-10);  // moves all the lasers off screen
00114     }
00115 }
00116 
00117 
00118 void BreakoutEngine::read_input(Gamepad &pad)
00119 {
00120     _d = pad.get_direction();
00121     _mag = pad.get_mag();
00122 
00123     if (pad.check_event(Gamepad::B_PRESSED) && _cool_time <= 0) {  // if B is pressed and it is not cooling down then fire a laser
00124 
00125         Vector2D p_pos = _paddle.get_pos();
00126         it_L = listofLasers.begin();
00127         switch(_index) {     // switch between the lasers each time the button is pressed so that it doesnt just re position the same laser each time
00128             case 0:
00129                 advance(it_L, 0);
00130                 it_L -> set_posx(p_pos.x+7);  // move laser 1 to middle of paddle
00131                 it_L -> set_posy(p_pos.y);
00132                 inc_index();
00133                 //printf("index = %d",_index);
00134                 break;
00135             case 1:
00136                 advance(it_L, 1);
00137                 it_L -> set_posx(p_pos.x+7);  // move laser 2 to middle of paddle
00138                 it_L -> set_posy(p_pos.y);
00139                 inc_index();
00140                 //printf("index = %d",_index);
00141                 break;
00142             case 2:
00143                 advance(it_L, 2);
00144                 it_L -> set_posx(p_pos.x+7);  // move laser 3 to middle of paddle
00145                 it_L -> set_posy(p_pos.y);
00146                 //printf("index = %d",_index);
00147                 reset_index();
00148                 //printf("index = %d",_index);
00149                 break;
00150         }
00151 
00152         it_L = listofLasers.end();
00153 
00154         _cool_time = 0.75f;  // reset cool time to 0.75 seconds
00155     } else {
00156         _cool_time -= 0.125; // reduce cool down time by 1/8 of a second as fps is 8  
00157     }
00158 
00159 }
00160 
00161 
00162 void BreakoutEngine::draw(N5110 &lcd)
00163 {
00164     lcd.drawRect(0,GAP_TOP - 2,WIDTH,HEIGHT - GAP_TOP + 2,FILL_TRANSPARENT); // draw the game screen dimensions
00165     print_scores(lcd);  // print the score above the screen
00166     _paddle.draw(lcd);  // draw the paddle
00167     _ball.draw(lcd);  // draw the ball
00168 
00169     for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) {  // draw all teh bricks
00170         it_R->draw(lcd);
00171     }
00172     for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) {  // draw all the lasers
00173         it_L->draw(lcd);
00174     }
00175 
00176     check_life_powerup();  // check if power up can be drawn, if so move on screen when random condition is met
00177 
00178     _powerup.draw(lcd);   // draw the powerup
00179 }
00180 
00181 
00182 void BreakoutEngine::update(Gamepad &pad)
00183 {
00184     check_loss(pad);  // check if the ball has gone above max y
00185     
00186     _paddle.update(_d,_mag);  // update paddle position
00187     _ball.update();   // update ball position
00188     _powerup.update();  // update powerup position
00189 
00190     for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { // update all the lasers' positions
00191         it_L->update();
00192     }
00193 
00194     lives_leds(pad);  // update the LEDs with the remaining lives
00195 
00196     check_wall_collisions(pad);  // check ball and laser collisions with walls and ceiling
00197     check_paddle_collisions(pad);  // check ball collision with paddle
00198     check_brick_collisions(pad);  // check ball collision with bricks
00199     check_laser_collisions(pad);  // check all laser collisions with all bricks
00200     check_powerup_collisions(pad);  // check powerup collision with paddle
00201 }
00202 
00203 
00204 void BreakoutEngine::lives_leds(Gamepad &pad)  // converst the number of lives left into LEDs
00205 {
00206     if (_paddle.get_lives() == 0) {  
00207         pad.leds_off();  // all LEDs off
00208     }
00209 
00210     else if (_paddle.get_lives() == 1) {
00211         pad.leds_off();
00212         pad.led(1,1);   // 1 LED on
00213     }
00214 
00215     else if (_paddle.get_lives() == 2) {
00216         pad.leds_off();
00217         pad.led(1,1);
00218         pad.led(2,1); // 2 LEDs on
00219     }
00220 
00221     else if (_paddle.get_lives() == 3) {
00222         pad.leds_off();
00223         pad.led(1,1);
00224         pad.led(2,1);
00225         pad.led(3,1);  // 3 LEDs on
00226     }
00227 
00228     else if (_paddle.get_lives() == 4) {
00229         pad.leds_on();
00230         pad.led(5,0);
00231         pad.led(6,0); // 4 LEDs on
00232     }
00233 
00234     else if (_paddle.get_lives() == 5) {
00235         pad.leds_on();
00236         pad.led(6,0);  // 5 LEDs on
00237     }
00238 
00239     else if (_paddle.get_lives() == 6) {
00240         pad.leds_on();  // all LEDs on
00241         //printf("all LEDs on \n");
00242     }
00243 }
00244 
00245 
00246 void BreakoutEngine::check_wall_collisions(Gamepad &pad)  // checks ball and laser collisions with the walls and ceiling
00247 {
00248     // read current ball attributes
00249     Vector2D ball_pos = _ball.get_pos();
00250     Vector2D ball_velocity = _ball.get_velocity();
00251     
00252     // bounce off the ceiling
00253     if (ball_pos.y <= GAP_TOP - 1) {  //  1 due to 1 pixel boundary
00254         ball_pos.y = GAP_TOP - 1;  
00255         ball_velocity.y = -ball_velocity.y;
00256         pad.tone(750.0,0.1);
00257     }
00258     
00259     // bounce off the left
00260     else if (ball_pos.x <= 1) {  //  1 due to 1 pixel boundary
00261         ball_pos.x = 1;  // bounce off walls 
00262         ball_velocity.x = -ball_velocity.x;
00263         pad.tone(750.0,0.1);
00264     }
00265 
00266     // bounce off the right
00267     else if (ball_pos.x + _ball_size >= (WIDTH-1) ) { // bottom pixel is 47
00268         // hit bottom
00269         ball_pos.x = (WIDTH-1) - _ball_size;  // stops ball going off screen
00270         ball_velocity.x = -ball_velocity.x;
00271         // audio feedback
00272         pad.tone(750.0,0.1);
00273     }
00274 
00275     // update ball parameters
00276     _ball.set_velocity(ball_velocity);
00277     _ball.set_pos(ball_pos);
00278 
00279     for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { // checks every laser
00280         if (
00281             (it_L -> get_y() <= GAP_TOP - 2) // if it hits the ceiling 
00282         ) {    
00283             it_L -> set_posx(-10);  // set its x coordinate off screen
00284         }
00285     }
00286 
00287 }
00288 
00289 
00290 void BreakoutEngine::check_paddle_collisions(Gamepad &pad)
00291 {
00292     // read current ball attributes
00293     Vector2D ball_pos = _ball.get_pos();
00294     Vector2D ball_velocity = _ball.get_velocity();
00295 
00296     // read the paddle position
00297     Vector2D paddle_pos = _paddle.get_pos();
00298 
00299     // check if ball overlaps with the paddle
00300     if (
00301         (ball_pos.x >= paddle_pos.x) && //left
00302         (ball_pos.x <= paddle_pos.x + _paddle_width) && //right
00303         (ball_pos.y >= _paddley) && //bottom
00304         (ball_pos.y <= _paddley + _paddle_height)  //top
00305     ) {    
00306         pad.tone(1000.0,0.1);
00307         ball_pos.y = _paddley + _paddle_height - 1;
00308         ball_velocity.y = -ball_velocity.y;
00309         
00310         // below is a method to control the ball reflect angle based on where it hits the paddle
00311         // however cannot be used as it does not work with collisions due to varying angles and speeds
00312         // would work with greater pixel density in the screen
00313 
00314 //        if (ball_pos.x == paddle_pos.x + PADDLE_WIDTH/2) {     // check ballxpos in relation to paddle xpos. translate the distance from the centre to an angle between 30 and 60 degrees in that direction
00315 //            ball_pos.y = _paddley + _paddle_height - 1;
00316 //            ball_velocity.y = -ball_velocity.y;
00317 //        }
00318 //        else if (ball_pos.x <= paddle_pos.x + PADDLE_WIDTH/2) {
00319 //            float ang = 40*(((paddle_pos.x + PADDLE_WIDTH/2)-ball_pos.x)/(PADDLE_WIDTH/2 - paddle_pos.x)) + 30;  //converts the distance from the centre to an angle between 30 and 60
00320 //            if (ball_velocity.x > 0) {
00321 //                ball_velocity.x = -ball_velocity.x;
00322 //            }
00323 //           ball_pos.y = _paddley + _paddle_heigh - 1;
00324 //           ball_velocity.y = -tan(ang);
00325 //       }
00326 //       else if (ball_pos.x >= paddle_pos.x + PADDLE_WIDTH/2) {
00327 //           float ang = 40*(((paddle_pos.x + PADDLE_WIDTH/2)-ball_pos.x)/(PADDLE_WIDTH/2 - paddle_pos.x)) + 30;  //converts the distance from the centre to an angle between 30 and 60
00328 //           if (ball_velocity.x < 0) {
00329 //               ball_velocity.x = -ball_velocity.x;
00330 //           }
00331 //           ball_pos.y = _paddley + _paddle_height - 1;
00332 //           ball_velocity.y = -tan(ang);
00333 //       }
00334     }
00335 
00336     // write new attributes
00337     _ball.set_velocity(ball_velocity);
00338     _ball.set_pos(ball_pos);
00339 }
00340 
00341 void BreakoutEngine::check_brick_collisions(Gamepad &pad)
00342 {
00343     // read current ball attributes
00344     Vector2D ball_pos = _ball.get_pos();
00345     Vector2D ball_velocity = _ball.get_velocity();
00346 
00347     for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) {
00348         if (
00349             (ball_pos.x >= it_R -> get_x()) && //left
00350             (ball_pos.x <= it_R -> get_x() + BRICK_WIDTH) && //right
00351             (ball_pos.y >= it_R -> get_y()) && //bottom
00352             (ball_pos.y <= it_R -> get_y() + BRICK_HEIGHT)  //top
00353         ) {    
00354             if (ball_velocity.y < 0) {  // if velocity is negative, it has hit the bottom, therefore correct its pos to the bottom face
00355                 ball_pos.y = it_R -> get_y() + BRICK_HEIGHT;
00356             } else {  // else it has hit the top, correct its position to the top face
00357                 ball_pos.y = it_R -> get_y();   
00358             }
00359             ball_velocity.y = -ball_velocity.y;  // invert the balls y velocity
00360             // audio feedback
00361             pad.tone(1000.0,0.1);  
00362             it_R -> hit();  
00363             if(it_R-> hit() == true) {  // hit the brick, remove 2 lives from it and check if destroyed
00364                 it_R -> set_posx(-100);  // if destroyed, move off screen
00365                 dec_num_left();  // decrement the number of bricks left on screen
00366             }
00367         }
00368     }
00369     // write new attributes
00370     _ball.set_velocity(ball_velocity);
00371     _ball.set_pos(ball_pos);
00372 }
00373 
00374 
00375 void BreakoutEngine::check_laser_collisions(Gamepad &pad)
00376 {
00377     for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) {   
00378         for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) {  // check every laser against every brick
00379             if (
00380                 (it_L -> get_x() >= it_R -> get_x()) && //left
00381                 (it_L -> get_x() <= it_R -> get_x() + BRICK_WIDTH) && //right
00382                 (it_L -> get_y() >= it_R -> get_y()) && //bottom
00383                 (it_L -> get_y() <= it_R -> get_y() + BRICK_HEIGHT)  //top
00384             ) {  
00385                 it_L -> set_posx(-10);    // if they overlap/collide, move the laser off screen
00386                 // audio feedback
00387                 pad.tone(1000.0,0.1);  
00388                 if(it_R-> hit() == true) {   // remove a life from the brick, if its destroyed, move it off screen
00389                     it_R -> set_posx(-100);
00390                     dec_num_left();  // decrement the number of bricks remaining on screen
00391                 }
00392             }
00393         }
00394     }
00395 }
00396 
00397 
00398 void BreakoutEngine::check_powerup_collisions(Gamepad &pad)  // checks powerup collisions with the paddle and the bottom of the screen
00399 {
00400     // read the current position of the paddle
00401     Vector2D paddle_pos = _paddle.get_pos();  
00402     
00403     if (
00404         (_powerup.get_x() >= paddle_pos.x) && //left
00405         (_powerup.get_x() + 8 <= paddle_pos.x + _paddle_width) && //right
00406         (_powerup.get_y() + 8 >= paddle_pos.y) // top
00407     ) {   
00408         pad.tone(2500.0,0.1);
00409         _powerup.set_posx(-50);   // if the paddle and power up overlap, move the powerup off screen
00410         _paddle.inc_life();   // increment the numebr of lives left on the paddle
00411     }
00412 
00413     else if (
00414         (_powerup.get_y() +9 >= HEIGHT)  // bottom of screen
00415     ) {    
00416         _powerup.set_posx(-50);   // if the powerup reaches the bottom of the screen, move it off screen
00417     }
00418 }
00419 
00420 
00421 bool BreakoutEngine::check_loss(Gamepad &pad)  // check if the ball has hit the bottom of the screen
00422 {
00423     // read the current ball position
00424     Vector2D ball_pos = _ball.get_pos();
00425     
00426     if (ball_pos.y > HEIGHT) {  // if it has gone off screen
00427         _paddle.lose_life();   // decrement the number of lives left
00428 
00429         _ball.init(_ball_size,_speed+_multiplier/2,_paddle.get_pos().x + (PADDLE_WIDTH/2));  // re initialise the ball above the paddle
00430         pad.tone(1500.0,0.5);
00431         return true;     // return true, to be used to flash the screen in the main
00432     } else {
00433         return false;    
00434     }
00435 }
00436 
00437 
00438 void BreakoutEngine::set_paddle_motion(bool tilt, float sens)  // sets the motion options for the paddle
00439 {
00440     if (tilt == true) {
00441         _paddle.set_tilt();  // sets tilt
00442     } else {
00443         _paddle.set_joy();  // sets joystick
00444     }
00445     _paddle.set_sens(sens);  // sets sensitivity
00446 }
00447 
00448 
00449 void BreakoutEngine::print_scores(N5110 &lcd)
00450 {
00451     int score = _prev_score + (18 - get_num_left())*100 * (_multiplier + 1);  // current score depends on number left, the multiplier and the previous score
00452     _score = score; // set the member variable _score
00453     
00454     char buffer[14];
00455     sprintf(buffer,"%2d",score); // put score in buffer
00456     lcd.printString("SCORE: ",2,0);
00457     lcd.printString(buffer,WIDTH/2 -2,0);  // print buffer on LCD
00458 }
00459 
00460 
00461 void BreakoutEngine::check_life_powerup()
00462 {
00463     srand(time(0));  // Initialize random number generator.
00464     int r1 = (rand() % 25) + 1; 
00465     int r2 = (rand() % 25) + 1;   // 2 random number between 1 and 26
00466     int rx = (rand() % 60) + 11;   // generate a random x coordinate for the powerup to be place
00467     //printf("r1 = %d",r1);
00468     //printf("r2 = %d",r2);
00469     //printf("rx = %d",rx);
00470     if ((get_paddle_lives() < 6) & (r1 == r2)) {   // if lives are not max, and the random condition is met
00471         _powerup.set_posx(rx);   // set the powerup x
00472         _powerup.set_posy(HEIGHT/2);  // set the y at the middle of the screen
00473     }
00474 }
00475 
00476 
00477 int BreakoutEngine::get_prev_score()
00478 {
00479     return _prev_score;  // return the previous score
00480 }
00481 
00482 
00483 void BreakoutEngine::set_prev_score(int prev_score)
00484 {
00485     _prev_score = prev_score;  // set the member variable _prev_score
00486 }
00487 
00488 
00489 int BreakoutEngine::get_num_left()
00490 {
00491     return _number_left;  // return the number of bricks left on screen
00492 }
00493 
00494 
00495 void BreakoutEngine::dec_num_left()
00496 {
00497     _number_left -= 1;  // decrement the member variable _number_left when a brick is destroyed
00498 }
00499 
00500 
00501 void BreakoutEngine::reset_num_left()
00502 {
00503     _number_left = 18;  // reset the number left to 18 when the game is reset
00504 }
00505 
00506 
00507 int BreakoutEngine::get_score()
00508 {
00509     return _score;  // return the member variable _score
00510 }
00511 
00512 
00513 void BreakoutEngine::inc_mult()
00514 {
00515     _multiplier ++;   // increment the _multiplier when continue is selected upon victory
00516 }
00517 
00518 
00519 int BreakoutEngine::get_mult()
00520 {
00521     return _multiplier;   // retrieve the multiplier value
00522 }
00523 
00524 
00525 void BreakoutEngine::reset_mult()
00526 {
00527     _multiplier = 0;    // reset the multiplier to 0
00528 }
00529 
00530 
00531 void BreakoutEngine::inc_index()
00532 {
00533     _index ++;    // increment the laser index
00534 }
00535 
00536 
00537 void BreakoutEngine::reset_index()
00538 {
00539     _index = 0;  // reset the laser index
00540 }
00541 
00542 
00543 void BreakoutEngine::reset_paddle_lives()
00544 {
00545     _paddle.reset_lives();  // resets paddle lives
00546 }
00547 
00548 
00549 int BreakoutEngine::get_paddle_lives()
00550 {
00551     return _paddle.get_lives();    // return the number of lives left
00552 }