James Heavey
/
EL17JH
FINAL VERSION
BreakoutEngine/BreakoutEngine.cpp
- Committer:
- jamesheavey
- Date:
- 2019-05-09
- Revision:
- 140:d8634e76ecce
- Parent:
- 136:04a2724f90cf
File content as of revision 140:d8634e76ecce:
#include "BreakoutEngine.h" BreakoutEngine::BreakoutEngine() { } BreakoutEngine::~BreakoutEngine() { } void BreakoutEngine::init(int paddle_width,int paddle_height,int ball_size,int speed) { // initialise the game parameters _paddle_width = paddle_width; _paddle_height = paddle_height; _ball_size = ball_size; // size of the ball _speed = speed; // speed of the ball _number_left = 18; // number of bricks that remain on screen _index = 0; // index of which laser to move on screen at any time, starts at 0 _cool_time = 0.0f; // time remaining before laser can be fired again, starts at 0 _score = 0; // initialised as 0 _prev_score = 0; // initialised as 0 for the first round _multiplier = 0; // initialised as 1 for the first round // y position of the paddle on screen - HEIGHT is defined in N5110.h _paddley = HEIGHT - GAP - 1; // initialises paddles and ball in middle _paddle.init(_paddley,_paddle_height,_paddle_width); _ball.init(_ball_size,_speed,_paddle.get_pos().x + (PADDLE_WIDTH/2)); // initialises all the bricks in their set x/y positions _brick11.init(3,GAP_TOP+1,3); _brick12.init(16,GAP_TOP+1,3); _brick13.init(29,GAP_TOP+1,3); _brick14.init(42,GAP_TOP+1,3); _brick15.init(55,GAP_TOP+1,3); _brick16.init(68,GAP_TOP+1,3); _brick21.init(3,GAP_TOP+BRICK_HEIGHT+2,2); _brick22.init(16,GAP_TOP+BRICK_HEIGHT+2,2); _brick23.init(29,GAP_TOP+BRICK_HEIGHT+2,2); _brick24.init(42,GAP_TOP+BRICK_HEIGHT+2,2); _brick25.init(55,GAP_TOP+BRICK_HEIGHT+2,2); _brick26.init(68,GAP_TOP+BRICK_HEIGHT+2,2); _brick31.init(3,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1); _brick32.init(16,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1); _brick33.init(29,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1); _brick34.init(42,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1); _brick35.init(55,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1); _brick36.init(68,GAP_TOP+1+((BRICK_HEIGHT+1)*2),1); // appends all bricks to a list so that they are easier to check for collisions listofBricks.push_back(_brick11); listofBricks.push_back(_brick12); listofBricks.push_back(_brick13); listofBricks.push_back(_brick14); listofBricks.push_back(_brick15); listofBricks.push_back(_brick16); listofBricks.push_back(_brick21); listofBricks.push_back(_brick22); listofBricks.push_back(_brick23); listofBricks.push_back(_brick24); listofBricks.push_back(_brick25); listofBricks.push_back(_brick26); listofBricks.push_back(_brick31); listofBricks.push_back(_brick32); listofBricks.push_back(_brick33); listofBricks.push_back(_brick34); listofBricks.push_back(_brick35); listofBricks.push_back(_brick36); // initialises lasers off screen _laser1.init(); _laser2.init(); _laser3.init(); // appends lasers to a list so that they are easier to check for collisions listofLasers.push_back(_laser1); listofLasers.push_back(_laser2); listofLasers.push_back(_laser3); _powerup.init(); } void BreakoutEngine::reset_game() // resets the game after victory screen { reset_num_left(); // resets _number_left to 18 _paddle.recentre(); // recentres the paddle on screen //printf("Paddle lives = %d", _paddle.get_lives()); _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 _powerup.set_posx(-50); int pointer = 0; // tracks the rows, if 6 bricks are placed, it moves to the next row for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) { if (pointer <= 5) { // 6 bricks in the first row it_R -> set_posx((pointer * 13) + 3); } else if (pointer <= 11) { it_R -> set_posx(((pointer-6) * 13) + 3); // pointer - 6 to offset it back to the first column of bricks } else if (pointer <= 17) { it_R -> set_posx(((pointer-12) * 13) + 3); // pointer - 12 to offset it back to the first column of bricks } it_R -> reset_lives(_multiplier); // increases the bricks number of lives by the multiplier + their _base_lives pointer ++; // increment the pointer //printf("pointer = %d",pointer); } for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { it_L -> set_posx(-10); // moves all the lasers off screen } } void BreakoutEngine::read_input(Gamepad &pad) { _d = pad.get_direction(); _mag = pad.get_mag(); if (pad.check_event(Gamepad::B_PRESSED) && _cool_time <= 0) { // if B is pressed and it is not cooling down then fire a laser Vector2D p_pos = _paddle.get_pos(); it_L = listofLasers.begin(); switch(_index) { // switch between the lasers each time the button is pressed so that it doesnt just re position the same laser each time case 0: advance(it_L, 0); it_L -> set_posx(p_pos.x+7); // move laser 1 to middle of paddle it_L -> set_posy(p_pos.y); inc_index(); //printf("index = %d",_index); break; case 1: advance(it_L, 1); it_L -> set_posx(p_pos.x+7); // move laser 2 to middle of paddle it_L -> set_posy(p_pos.y); inc_index(); //printf("index = %d",_index); break; case 2: advance(it_L, 2); it_L -> set_posx(p_pos.x+7); // move laser 3 to middle of paddle it_L -> set_posy(p_pos.y); //printf("index = %d",_index); reset_index(); //printf("index = %d",_index); break; } it_L = listofLasers.end(); _cool_time = 0.75f; // reset cool time to 0.75 seconds } else { _cool_time -= 0.125; // reduce cool down time by 1/8 of a second as fps is 8 } } void BreakoutEngine::draw(N5110 &lcd) { lcd.drawRect(0,GAP_TOP - 2,WIDTH,HEIGHT - GAP_TOP + 2,FILL_TRANSPARENT); // draw the game screen dimensions print_scores(lcd); // print the score above the screen _paddle.draw(lcd); // draw the paddle _ball.draw(lcd); // draw the ball for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) { // draw all teh bricks it_R->draw(lcd); } for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { // draw all the lasers it_L->draw(lcd); } check_life_powerup(); // check if power up can be drawn, if so move on screen when random condition is met _powerup.draw(lcd); // draw the powerup } void BreakoutEngine::update(Gamepad &pad) { check_loss(pad); // check if the ball has gone above max y _paddle.update(_d,_mag); // update paddle position _ball.update(); // update ball position _powerup.update(); // update powerup position for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { // update all the lasers' positions it_L->update(); } lives_leds(pad); // update the LEDs with the remaining lives check_wall_collisions(pad); // check ball and laser collisions with walls and ceiling check_paddle_collisions(pad); // check ball collision with paddle check_brick_collisions(pad); // check ball collision with bricks check_laser_collisions(pad); // check all laser collisions with all bricks check_powerup_collisions(pad); // check powerup collision with paddle } void BreakoutEngine::lives_leds(Gamepad &pad) // converst the number of lives left into LEDs { if (_paddle.get_lives() == 0) { pad.leds_off(); // all LEDs off } else if (_paddle.get_lives() == 1) { pad.leds_off(); pad.led(1,1); // 1 LED on } else if (_paddle.get_lives() == 2) { pad.leds_off(); pad.led(1,1); pad.led(2,1); // 2 LEDs on } else if (_paddle.get_lives() == 3) { pad.leds_off(); pad.led(1,1); pad.led(2,1); pad.led(3,1); // 3 LEDs on } else if (_paddle.get_lives() == 4) { pad.leds_on(); pad.led(5,0); pad.led(6,0); // 4 LEDs on } else if (_paddle.get_lives() == 5) { pad.leds_on(); pad.led(6,0); // 5 LEDs on } else if (_paddle.get_lives() == 6) { pad.leds_on(); // all LEDs on //printf("all LEDs on \n"); } } void BreakoutEngine::check_wall_collisions(Gamepad &pad) // checks ball and laser collisions with the walls and ceiling { // read current ball attributes Vector2D ball_pos = _ball.get_pos(); Vector2D ball_velocity = _ball.get_velocity(); // bounce off the ceiling if (ball_pos.y <= GAP_TOP - 1) { // 1 due to 1 pixel boundary ball_pos.y = GAP_TOP - 1; ball_velocity.y = -ball_velocity.y; pad.tone(750.0,0.1); } // bounce off the left else if (ball_pos.x <= 1) { // 1 due to 1 pixel boundary ball_pos.x = 1; // bounce off walls ball_velocity.x = -ball_velocity.x; pad.tone(750.0,0.1); } // bounce off the right else if (ball_pos.x + _ball_size >= (WIDTH-1) ) { // bottom pixel is 47 // hit bottom ball_pos.x = (WIDTH-1) - _ball_size; // stops ball going off screen ball_velocity.x = -ball_velocity.x; // audio feedback pad.tone(750.0,0.1); } // update ball parameters _ball.set_velocity(ball_velocity); _ball.set_pos(ball_pos); for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { // checks every laser if ( (it_L -> get_y() <= GAP_TOP - 2) // if it hits the ceiling ) { it_L -> set_posx(-10); // set its x coordinate off screen } } } void BreakoutEngine::check_paddle_collisions(Gamepad &pad) { // read current ball attributes Vector2D ball_pos = _ball.get_pos(); Vector2D ball_velocity = _ball.get_velocity(); // read the paddle position Vector2D paddle_pos = _paddle.get_pos(); // check if ball overlaps with the paddle if ( (ball_pos.x >= paddle_pos.x) && //left (ball_pos.x <= paddle_pos.x + _paddle_width) && //right (ball_pos.y >= _paddley) && //bottom (ball_pos.y <= _paddley + _paddle_height) //top ) { pad.tone(1000.0,0.1); ball_pos.y = _paddley + _paddle_height - 1; ball_velocity.y = -ball_velocity.y; // below is a method to control the ball reflect angle based on where it hits the paddle // however cannot be used as it does not work with collisions due to varying angles and speeds // would work with greater pixel density in the screen // 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 // ball_pos.y = _paddley + _paddle_height - 1; // ball_velocity.y = -ball_velocity.y; // } // else if (ball_pos.x <= paddle_pos.x + PADDLE_WIDTH/2) { // 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 // if (ball_velocity.x > 0) { // ball_velocity.x = -ball_velocity.x; // } // ball_pos.y = _paddley + _paddle_heigh - 1; // ball_velocity.y = -tan(ang); // } // else if (ball_pos.x >= paddle_pos.x + PADDLE_WIDTH/2) { // 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 // if (ball_velocity.x < 0) { // ball_velocity.x = -ball_velocity.x; // } // ball_pos.y = _paddley + _paddle_height - 1; // ball_velocity.y = -tan(ang); // } } // write new attributes _ball.set_velocity(ball_velocity); _ball.set_pos(ball_pos); } void BreakoutEngine::check_brick_collisions(Gamepad &pad) { // read current ball attributes Vector2D ball_pos = _ball.get_pos(); Vector2D ball_velocity = _ball.get_velocity(); for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) { if ( (ball_pos.x >= it_R -> get_x()) && //left (ball_pos.x <= it_R -> get_x() + BRICK_WIDTH) && //right (ball_pos.y >= it_R -> get_y()) && //bottom (ball_pos.y <= it_R -> get_y() + BRICK_HEIGHT) //top ) { if (ball_velocity.y < 0) { // if velocity is negative, it has hit the bottom, therefore correct its pos to the bottom face ball_pos.y = it_R -> get_y() + BRICK_HEIGHT; } else { // else it has hit the top, correct its position to the top face ball_pos.y = it_R -> get_y(); } ball_velocity.y = -ball_velocity.y; // invert the balls y velocity // audio feedback pad.tone(1000.0,0.1); it_R -> hit(); if(it_R-> hit() == true) { // hit the brick, remove 2 lives from it and check if destroyed it_R -> set_posx(-100); // if destroyed, move off screen dec_num_left(); // decrement the number of bricks left on screen } } } // write new attributes _ball.set_velocity(ball_velocity); _ball.set_pos(ball_pos); } void BreakoutEngine::check_laser_collisions(Gamepad &pad) { for (it_L = listofLasers.begin(); it_L != listofLasers.end(); ++it_L) { for (it_R = listofBricks.begin(); it_R != listofBricks.end(); ++it_R) { // check every laser against every brick if ( (it_L -> get_x() >= it_R -> get_x()) && //left (it_L -> get_x() <= it_R -> get_x() + BRICK_WIDTH) && //right (it_L -> get_y() >= it_R -> get_y()) && //bottom (it_L -> get_y() <= it_R -> get_y() + BRICK_HEIGHT) //top ) { it_L -> set_posx(-10); // if they overlap/collide, move the laser off screen // audio feedback pad.tone(1000.0,0.1); if(it_R-> hit() == true) { // remove a life from the brick, if its destroyed, move it off screen it_R -> set_posx(-100); dec_num_left(); // decrement the number of bricks remaining on screen } } } } } void BreakoutEngine::check_powerup_collisions(Gamepad &pad) // checks powerup collisions with the paddle and the bottom of the screen { // read the current position of the paddle Vector2D paddle_pos = _paddle.get_pos(); if ( (_powerup.get_x() >= paddle_pos.x) && //left (_powerup.get_x() + 8 <= paddle_pos.x + _paddle_width) && //right (_powerup.get_y() + 8 >= paddle_pos.y) // top ) { pad.tone(2500.0,0.1); _powerup.set_posx(-50); // if the paddle and power up overlap, move the powerup off screen _paddle.inc_life(); // increment the numebr of lives left on the paddle } else if ( (_powerup.get_y() +9 >= HEIGHT) // bottom of screen ) { _powerup.set_posx(-50); // if the powerup reaches the bottom of the screen, move it off screen } } bool BreakoutEngine::check_loss(Gamepad &pad) // check if the ball has hit the bottom of the screen { // read the current ball position Vector2D ball_pos = _ball.get_pos(); if (ball_pos.y > HEIGHT) { // if it has gone off screen _paddle.lose_life(); // decrement the number of lives left _ball.init(_ball_size,_speed+_multiplier/2,_paddle.get_pos().x + (PADDLE_WIDTH/2)); // re initialise the ball above the paddle pad.tone(1500.0,0.5); return true; // return true, to be used to flash the screen in the main } else { return false; } } void BreakoutEngine::set_paddle_motion(bool tilt, float sens) // sets the motion options for the paddle { if (tilt == true) { _paddle.set_tilt(); // sets tilt } else { _paddle.set_joy(); // sets joystick } _paddle.set_sens(sens); // sets sensitivity } void BreakoutEngine::print_scores(N5110 &lcd) { int score = _prev_score + (18 - get_num_left())*100 * (_multiplier + 1); // current score depends on number left, the multiplier and the previous score _score = score; // set the member variable _score char buffer[14]; sprintf(buffer,"%2d",score); // put score in buffer lcd.printString("SCORE: ",2,0); lcd.printString(buffer,WIDTH/2 -2,0); // print buffer on LCD } void BreakoutEngine::check_life_powerup() { srand(time(0)); // Initialize random number generator. int r1 = (rand() % 25) + 1; int r2 = (rand() % 25) + 1; // 2 random number between 1 and 26 int rx = (rand() % 60) + 11; // generate a random x coordinate for the powerup to be place //printf("r1 = %d",r1); //printf("r2 = %d",r2); //printf("rx = %d",rx); if ((get_paddle_lives() < 6) & (r1 == r2)) { // if lives are not max, and the random condition is met _powerup.set_posx(rx); // set the powerup x _powerup.set_posy(HEIGHT/2); // set the y at the middle of the screen } } int BreakoutEngine::get_prev_score() { return _prev_score; // return the previous score } void BreakoutEngine::set_prev_score(int prev_score) { _prev_score = prev_score; // set the member variable _prev_score } int BreakoutEngine::get_num_left() { return _number_left; // return the number of bricks left on screen } void BreakoutEngine::dec_num_left() { _number_left -= 1; // decrement the member variable _number_left when a brick is destroyed } void BreakoutEngine::reset_num_left() { _number_left = 18; // reset the number left to 18 when the game is reset } int BreakoutEngine::get_score() { return _score; // return the member variable _score } void BreakoutEngine::inc_mult() { _multiplier ++; // increment the _multiplier when continue is selected upon victory } int BreakoutEngine::get_mult() { return _multiplier; // retrieve the multiplier value } void BreakoutEngine::reset_mult() { _multiplier = 0; // reset the multiplier to 0 } void BreakoutEngine::inc_index() { _index ++; // increment the laser index } void BreakoutEngine::reset_index() { _index = 0; // reset the laser index } void BreakoutEngine::reset_paddle_lives() { _paddle.reset_lives(); // resets paddle lives } int BreakoutEngine::get_paddle_lives() { return _paddle.get_lives(); // return the number of lives left }