ELEC2645 (2019/20) / Mbed 2 deprecated ELEC2645_Project_el17c2w

Dependencies:   mbed

Revision:
12:2af7b4868033
Parent:
5:3c9407e2fe55
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Engine/Engine.cpp	Wed May 27 07:00:37 2020 +0000
@@ -0,0 +1,546 @@
+#include "Engine.h"
+
+Engine::Engine()
+{
+}
+
+Engine::~Engine()
+{
+}
+
+void Engine::init(int paddle_width,int paddle_height,int ball_size,int ball2_size,int speed,int thing_size, int repaddle_size)
+{
+    // initialise the game parameters
+    _paddle_width = paddle_width;
+    _paddle_height = paddle_height;
+    _ball_size = ball_size;
+    _ball2_size = ball2_size; // add another ball when score reaches 5
+    _thing_size = thing_size;
+    _repaddle_size = repaddle_size;
+    _speed = speed;
+    
+    // x position on screen - WIDTH is defined in N5110.h
+    _p1y = HEIGHT - GAP;
+    // puts paddles and ball in middle
+    _p1.init(HEIGHT/2,_p1y,_paddle_width);
+    
+    _ball.init(_ball_size,_speed);
+    _ball2.init(_ball2_size,_speed);
+    _thing.init(_thing_size);
+}
+
+void Engine::read_input(Gamepad &pad)
+{
+    _d = pad.get_direction();
+    _mag = pad.get_mag();
+}
+
+///////////////////////  Draw the graph  ///////////////////////////////////////
+
+void Engine::draw(N5110 &lcd)
+{
+    // draw the elements in the LCD buffer
+    // pitch
+    lcd.drawRect(0,0,WIDTH,HEIGHT,FILL_TRANSPARENT);
+    lcd.drawLine(20,30,70,30,FILL_BLACK);    //the first reflection board.
+    lcd.drawLine(25,22,45,22,FILL_BLACK);   // the second reflection board.
+    lcd.drawLine(55,25,75,25,FILL_BLACK);    // the third reflection board.
+    
+    //score
+    print_scores(lcd);
+    //draw paddles
+    _p1.draw(lcd);
+    // draw ball1, thing and repaddle
+    _ball.draw(lcd);
+    _ball2.draw(lcd);
+    _thing.draw(lcd);
+    /// _repaddle.draw(lcd);
+}
+
+//////////////////////////////UPDATE/////////////////////////////////////////////
+void Engine::update(N5110 &lcd,Gamepad &pad)
+{
+    check_goal(pad);
+    check_ball2_goal(pad);
+    
+    // important to update paddles and ball before checking collisions so can
+    // correct for it before updating the display
+    _p1.update(_d,_mag);
+    
+    _ball.update();
+    /////// check  ball///////////////
+    check_wall_collision(pad);
+    check_paddle_collisions(pad);
+    check_thing_collisions(pad);
+    check_reflection(pad);
+    
+    ///////////////Ball2///////////////
+    _ball2.update();
+    // get the scores
+    int p_score = _p1.get_score();
+    Vector2D ball2_pos = _ball2.get_pos();
+    Vector2D ball2_velocity = _ball2.get_velocity();   
+    Vector2D thing_pos = _thing.get_pos();
+    // if the score is bigger than 5, than add another ball
+    if (p_score < 5) {
+        ball2_pos.x = thing_pos.x;
+        ball2_pos.y = thing_pos.y;
+        ball2_velocity.x = 0;
+        ball2_velocity.y = 0;
+        
+        _ball2.set_velocity(ball2_velocity);
+        _ball2.set_pos(ball2_pos); 
+    }
+    // the another ball will begin to move in a random direction
+    else if (p_score == 5) {
+        ball2_velocity.x = _speed * (2*(rand() % 2) - 1);
+        ball2_velocity.y = _speed * (2*(rand() % 2) - 1);
+        _ball2.set_velocity(ball2_velocity);
+        while (_p1.get_score() == 5) {
+            read_input(pad);
+            check_goal(pad);
+            check_ball2_goal(pad);
+            _p1.update(_d,_mag);
+            _ball.update();
+            check_wall_collision(pad);
+            check_paddle_collisions(pad);
+            check_thing_collisions(pad);
+            check_reflection(pad);
+            _ball2.update();
+            check_ball2(pad);  
+            lcd.clear();  
+            draw(lcd);
+            lcd.refresh();
+            wait(1.0f/8);
+        }
+    }
+    check_ball2(pad); // check the states of ball2 for updating
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////CHECK BALL1////////////////////////////////////////
+
+// set the refrection of the board and speed up the ball
+// two ways of refrection: x-direction and y-direction
+void Engine::check_reflection(Gamepad &pad)
+{   
+    Vector2D ball_pos = _ball.get_pos();
+    Vector2D ball_velocity = _ball.get_velocity();
+    if ((ball_pos.x >= 20) && (ball_pos.x <= 70) && (ball_pos.y <= 31) && (ball_pos.y >= 29)) {
+        ball_velocity.x =  ball_velocity.x*2;
+        // audio feedback
+        pad.tone(750.0,0.1);    
+    }
+    else if ((ball_pos.x >=25) && (ball_pos.x <= 45) && (ball_pos.y >= 21) && (ball_pos.y <= 23)){
+        ball_velocity.y =  ball_velocity.y*2;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    else if ((ball_pos.x >=55) && (ball_pos.x <= 75) && (ball_pos.y >= 24) && (ball_pos.y <= 26)){
+        ball_velocity.y =  ball_velocity.y*2;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    _ball.set_velocity(ball_velocity);
+    _ball.set_pos(ball_pos);
+}
+
+void Engine::check_wall_collision(Gamepad &pad)
+{
+    // read current ball attributes
+    Vector2D ball_pos = _ball.get_pos();
+    Vector2D ball_velocity = _ball.get_velocity();
+    
+    //adjust to the original speed
+    if (abs(ball_velocity.x) > _speed) {
+        ball_velocity.x = ball_velocity.x / abs(ball_velocity.x) * 2; 
+    }
+    if (abs(ball_velocity.y) > _speed) {
+        ball_velocity.y = ball_velocity.y / abs(ball_velocity.y) * 2; 
+    }
+
+    // check if hit top wall
+    if (ball_pos.y <= 1) {  //  1 due to 1 pixel boundary
+        ball_pos.y = 1;  // bounce off ceiling without going off screen
+        ball_velocity.y = -ball_velocity.y;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    // check if hit bottom wall
+    else if (ball_pos.x <= 1) {  //  1 due to 1 pixel boundary
+        ball_pos.x = 1;  // bounce off ceiling without going off screen
+        ball_velocity.x = -ball_velocity.x;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    else if (ball_pos.x >= 84) {  //  1 due to 1 pixel boundary
+        ball_pos.x = 84;  // bounce off ceiling without 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);
+}
+
+void Engine::check_paddle_collisions(Gamepad &pad)
+{
+    // read current ball attributes
+    Vector2D ball_pos = _ball.get_pos();
+    Vector2D ball_velocity = _ball.get_velocity();
+    Vector2D p1_pos = _p1.get_pos();
+    
+    //adjust to the original speed
+    if (abs(ball_velocity.x) > _speed) {
+        ball_velocity.x = ball_velocity.x / abs(ball_velocity.x) * 2;
+        }
+    if (abs(ball_velocity.y) > _speed) {
+        ball_velocity.y = ball_velocity.y / abs(ball_velocity.y) * 2; 
+        }
+    
+    // see if ball has hit the paddle by checking for overlaps
+    if (
+        (ball_pos.y >= p1_pos.y) && //top
+        (ball_pos.y <= p1_pos.y + 2) && //bottom
+        (ball_pos.x >= p1_pos.x-4) && //left
+        (ball_pos.x <= p1_pos.x + 10)  //right
+    ) {
+        // if it has, fix position and reflect x velocity
+        ball_pos.x = p1_pos.x ;
+        ball_velocity.y = -ball_velocity.y;
+        // audio feedback
+        pad.tone(1000.0,0.1);
+    }
+    // write new attributes
+    _ball.set_velocity(ball_velocity);
+    _ball.set_pos(ball_pos);
+}
+
+void Engine::check_thing_collisions(Gamepad &pad)
+{
+    // read current ball attributes
+    Vector2D ball_pos = _ball.get_pos();
+    Vector2D ball_velocity = _ball.get_velocity();
+    // read current thing position
+    Vector2D thing_pos = _thing.get_pos();
+    
+    //adjust to the original speed
+    if (abs(ball_velocity.x) > _speed) {
+        ball_velocity.x = ball_velocity.x / abs(ball_velocity.x) * 2; 
+        }
+    if (abs(ball_velocity.y) > _speed) {
+        ball_velocity.y = ball_velocity.y / abs(ball_velocity.y) * 2; 
+        }
+    
+    // see if ball has hit the thing by checking for overlaps
+    if (
+        (ball_pos.y >= thing_pos.y - 1) && //top
+        (ball_pos.y <= thing_pos.y + 1) && //bottom
+        (ball_pos.x >= thing_pos.x - 3) && //left
+        (ball_pos.x <= thing_pos.x + 10)  //right
+    ) {
+        // if it has, fix position and reflect x velocity
+        ball_pos.x = thing_pos.x ;
+        ball_velocity.y = -ball_velocity.y;
+        // audio feedback
+        pad.tone(1000.0,0.1);
+    }
+    // write new attributes
+    _ball.set_velocity(ball_velocity);
+    _ball.set_pos(ball_pos);
+}
+
+void Engine::check_goal(Gamepad &pad)
+{
+    Vector2D ball_pos = _ball.get_pos();
+    Vector2D thing_pos = _thing.get_pos();
+    if (
+        (ball_pos.y >= thing_pos.y - 1) && //top
+        (ball_pos.y <= thing_pos.y + 1) && //bottom
+        (ball_pos.x >= thing_pos.x - 3) && //left
+        (ball_pos.x <= thing_pos.x + 10)  //right
+    ) {
+        _p1.add_score();
+        _thing.init(_thing_size);
+        pad.tone(1500.0,0.5);
+        pad.leds_on();
+        wait(0.5);
+        pad.leds_off();     
+    }
+    if (ball_pos.y >= HEIGHT) {
+        _ball.init(_ball_size,_speed);
+        pad.tone(1500.0,0.5);
+        pad.leds_on();
+        wait(0.5);
+        pad.leds_off();
+    }
+}
+
+void Engine::print_scores(N5110 &lcd)
+{
+    // get scores from paddles
+    int p1_score = _p1.get_score();
+    // print to LCD i
+    char buffer1[14];
+    sprintf(buffer1,"%2d",p1_score);
+    lcd.printString(buffer1,60,1);  // print at top-right corner
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+////////////////////     Check    Ball2      ////////////////////////////////////
+void Engine::check_ball2(Gamepad &pad)
+{
+    check_ball2_wall_collision(pad);
+    check_ball2_paddle_collisions(pad);
+    check_ball2_thing_collisions(pad);
+    check_ball2_reflection(pad);
+}
+
+
+////////////// Check the states of the second ball  /////////////////////////////
+void Engine::check_ball2_reflection(Gamepad &pad)
+{   
+    Vector2D ball2_pos = _ball2.get_pos();
+    Vector2D ball2_velocity = _ball2.get_velocity();
+    if ((ball2_pos.x >= 20) && (ball2_pos.x <= 70) && (ball2_pos.y >= 29)&& (ball2_pos.y <= 31)) {
+        ball2_velocity.x =  ball2_velocity.x*2;
+        // audio feedback
+        pad.tone(750.0,0.1);    
+    }
+    else if ((ball2_pos.x >=25) && (ball2_pos.x <= 45) && (ball2_pos.y >= 21) && (ball2_pos.y <= 23)) {
+        ball2_velocity.y =  ball2_velocity.y*2;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    else if ((ball2_pos.x >=55) && (ball2_pos.x <= 75) && (ball2_pos.y >= 24) && (ball2_pos.y <= 26)) {
+        ball2_velocity.y =  ball2_velocity.y*2;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    _ball2.set_velocity(ball2_velocity);
+    _ball2.set_pos(ball2_pos);
+}
+
+
+void Engine::check_ball2_wall_collision(Gamepad &pad)
+{
+    // read current ball attributes
+    Vector2D ball2_pos = _ball2.get_pos();
+    Vector2D ball2_velocity = _ball2.get_velocity();
+    
+    //adjust to the original speed
+    if (abs(ball2_velocity.x) > _speed) {
+        ball2_velocity.x = ball2_velocity.x / abs(ball2_velocity.x) * 2; 
+        }
+    if (abs(ball2_velocity.y) > _speed) {
+        ball2_velocity.y = ball2_velocity.y / abs(ball2_velocity.y) * 2; 
+        }
+    
+    // check if hit top wall
+    if (ball2_pos.y <= 1) {  //  1 due to 1 pixel boundary
+        ball2_pos.y = 1;  // bounce off ceiling without going off screen
+        ball2_velocity.y = -ball2_velocity.y;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    // check if hit bottom wall
+    else if (ball2_pos.x <= 1) {  //  1 due to 1 pixel boundary
+        ball2_pos.x = 1;  // bounce off ceiling without going off screen
+        ball2_velocity.x = -ball2_velocity.x;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    else if (ball2_pos.x >= 84) {  //  1 due to 1 pixel boundary
+        ball2_pos.x = 84;  // bounce off ceiling without going off screen
+        ball2_velocity.x = -ball2_velocity.x;
+        // audio feedback
+        pad.tone(750.0,0.1);
+    }
+    // update ball parameters
+    _ball2.set_velocity(ball2_velocity);
+    _ball2.set_pos(ball2_pos);
+}
+
+void Engine::check_ball2_paddle_collisions(Gamepad &pad)
+{
+    // read current ball attributes
+    Vector2D ball2_pos = _ball2.get_pos();
+    Vector2D ball2_velocity = _ball2.get_velocity();
+    Vector2D p1_pos = _p1.get_pos();
+    
+    //adjust to the original speed
+    if (abs(ball2_velocity.x) > _speed) {
+        ball2_velocity.x = ball2_velocity.x / abs(ball2_velocity.x) * 2; 
+        }
+    if (abs(ball2_velocity.y) > _speed) {
+        ball2_velocity.y = ball2_velocity.y / abs(ball2_velocity.y) * 2; 
+        }
+    
+    // see if ball has hit the paddle by checking for overlaps
+    if (
+        (ball2_pos.y >= p1_pos.y) && //top
+        (ball2_pos.y <= p1_pos.y + 2) && //bottom
+        (ball2_pos.x >= p1_pos.x-4) && //left
+        (ball2_pos.x <= p1_pos.x + 10)  //right
+    ) {
+        // if it has, fix position and reflect x velocity
+        ball2_pos.x = p1_pos.x ;
+        ball2_velocity.y = -ball2_velocity.y;
+        // audio feedback
+        pad.tone(1000.0,0.1);
+    }
+    // write new attributes
+    _ball2.set_velocity(ball2_velocity);
+    _ball2.set_pos(ball2_pos);
+}
+
+void Engine::check_ball2_thing_collisions(Gamepad &pad)
+{
+    // read current ball attributes
+    Vector2D ball2_pos = _ball2.get_pos();
+    Vector2D ball2_velocity = _ball2.get_velocity();
+    // read current thing position
+    Vector2D thing_pos = _thing.get_pos();
+    
+    //adjust to the original speed
+    if (abs(ball2_velocity.x) > _speed) {
+        ball2_velocity.x = ball2_velocity.x / abs(ball2_velocity.x) * _speed; 
+        }
+    if (abs(ball2_velocity.y) > _speed) {
+        ball2_velocity.y = ball2_velocity.y / abs(ball2_velocity.y) * _speed; 
+        }
+    
+    // see if ball has hit the thing by checking for overlaps
+    if (
+        (ball2_pos.y >= thing_pos.y - 1) && //top
+        (ball2_pos.y <= thing_pos.y + 1) && //bottom
+        (ball2_pos.x >= thing_pos.x - 3) && //left
+        (ball2_pos.x <= thing_pos.x + 10)  //right
+    ) {
+        // if it has, fix position and reflect x velocity
+        ball2_pos.x = thing_pos.x ;
+        ball2_velocity.y = -ball2_velocity.y;
+        // audio feedback
+        pad.tone(1000.0,0.1);
+    }
+    // write new attributes
+    _ball2.set_velocity(ball2_velocity);
+    _ball2.set_pos(ball2_pos);
+}
+
+void Engine::check_ball2_goal(Gamepad &pad)
+{
+    Vector2D ball2_pos = _ball2.get_pos();
+    Vector2D thing_pos = _thing.get_pos();
+    if (
+        (ball2_pos.y >= thing_pos.y - 1) && //top
+        (ball2_pos.y <= thing_pos.y + 1) && //bottom
+        (ball2_pos.x >= thing_pos.x - 3) && //left
+        (ball2_pos.x <= thing_pos.x + 10)  //right
+    ) {
+        _p1.add_score();
+        _thing.init(_thing_size);
+        pad.tone(1500.0,0.5);
+        pad.leds_on();
+        wait(0.5);
+        pad.leds_off();     
+    }
+    if (ball2_pos.y >= HEIGHT) {
+        _ball2.init(_ball2_size,_speed);
+        pad.tone(1500.0,0.5);
+        pad.leds_on();
+        wait(0.5);
+        pad.leds_off();
+    }
+}
+
+
+//////////////////////        The World       //////////////////////////////////
+/* Every time we get 6 socres , the stand power of the world is triggered
+*  The function of the world is used to pause the first ball for a while
+*/
+
+
+void Engine::The_world(N5110 &lcd, Gamepad &pad){
+    
+    Vector2D ball_pos = _ball.get_pos();
+    Vector2D ball_velocity = _ball.get_velocity();
+    // check the score whether reach the goal
+    while ((_p1.get_score() % 6 == 0) && (_p1.get_score() != 0)){
+        //set the sound of the world
+        pad.tone(500.0,0.2);
+        wait(0.2);
+        pad.tone(800.0,0.2);
+        pad.tone(1300.0,0.3);
+        pad.tone(1600.0,0.3);
+        
+        // get the state of ball 1 before begin the world
+        // make the ball 2 keep moving
+        while((_p1.get_score() % 6 == 0) && (_p1.get_score() != 0)){
+            read_input(pad);
+            check_ball2_goal(pad);
+            _p1.update(_d,_mag);
+            _ball2.update();
+            check_ball2(pad);
+            
+            // reflesh the lcd and make pause
+            lcd.clear();  
+            draw(lcd);
+            lcd.refresh();
+            wait(1.0f/8);
+
+            }
+        
+    // restore the state of ball 1 after the world
+    _ball.set_velocity(ball_velocity);
+    }
+}
+
+
+//////////////////////       Bite the Dust    /////////////////////////////////
+/* When the socre we get reaches 8, the stand power of bite the dust is triggered
+*  The function of bite the dust is time backing tracking 
+*/// The second ball will go back to the initial state
+
+void Engine::bite_dust(N5110 &lcd, Gamepad &pad){
+    // check the score whether reach the goal
+    while ((_p1.get_score() % 8 == 0) && (_p1.get_score() != 0)){
+        //set the sound of the world
+        pad.tone(1000.0,0.2);
+        wait(0.1);
+        pad.tone(1000.0,0.2);
+        wait(0.1);
+        pad.tone(600.0,0.3);
+
+        // get the state of ball 2
+        Vector2D ball2_pos = _ball2.get_pos();
+        Vector2D ball2_velocity = _ball2.get_velocity();
+        Vector2D thing_pos = _thing.get_pos();     
+        
+        
+        int distance_x = floor((ball2_pos.x - thing_pos.x)/3.0);
+        int distance_y = floor((ball2_pos.y - thing_pos.y)/3.0);
+        for (int i = 1; i <= 3; i ++){
+            ball2_pos.x = ball2_pos.x - distance_x;
+            ball2_pos.y = ball2_pos.y - distance_y;
+            _ball2.set_pos(ball2_pos);
+
+            // reflesh the lcd and make pause
+            lcd.clear();  
+            draw(lcd);
+            lcd.refresh();
+            wait(0.5);
+        }
+        while((_p1.get_score() % 8 == 0) && (_p1.get_score() != 0)){
+            int p_score_b = _p1.get_score();
+            read_input(pad);
+            update(lcd,pad);
+            lcd.clear();  
+            draw(lcd);
+            lcd.refresh();
+            wait(1.0f/8);
+        }
+    }
+}
\ No newline at end of file