Alexandra Posta / Mbed OS ELEC2645_Race_Collision

Dependencies:   ELEC2645_JoystickLCD_LPC1768_2021

Files at this revision

API Documentation at this revision

Comitter:
alex_20
Date:
Thu May 06 12:04:45 2021 +0000
Parent:
8:1fc5e14b0db6
Commit message:
Race Collision for ELEC2645

Changed in this revision

lib/Ball.cpp Show annotated file Show diff for this revision Revisions of this file
lib/Ball.h Show annotated file Show diff for this revision Revisions of this file
lib/Car.cpp Show annotated file Show diff for this revision Revisions of this file
lib/Car.h Show annotated file Show diff for this revision Revisions of this file
lib/GameEngine.cpp Show annotated file Show diff for this revision Revisions of this file
lib/GameEngine.h Show annotated file Show diff for this revision Revisions of this file
lib/Road.cpp Show annotated file Show diff for this revision Revisions of this file
lib/Road.h Show annotated file Show diff for this revision Revisions of this file
lib/ShiftReg.cpp Show annotated file Show diff for this revision Revisions of this file
lib/ShiftReg.h Show annotated file Show diff for this revision Revisions of this file
lib/Utils.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/lib/Ball.cpp	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Ball.cpp	Thu May 06 12:04:45 2021 +0000
@@ -3,16 +3,15 @@
 // constructure
 Ball::Ball() {}
 
-void Ball::init() {    
-    //initialize parameters
-    //say that trajectory is 0
+void Ball::init(int radius) {    
+    if (radius > 4 | radius < 0){
+        radius = 4;
+    } 
 }
 
-//std::vector<Vector2Df> Ball::get_path() {
-//    path points = utils.getCurve;
-//    return path_points; 
-//    }
-
-void Ball::draw(N5110 &lcd, std::vector<Vector2Df> path_points, int radius, float iterator) { 
-    lcd.drawCircle(static_cast<int>(path_points[iterator].x), static_cast<int>(path_points[iterator].y), radius, FILL_TRANSPARENT);
+void Ball::draw(N5110 &lcd, std::vector<Vector2Df> path_points, int radius, int iterator) { 
+    
+    if(iterator > 0) {
+        lcd.drawCircle(static_cast<int>(path_points[iterator].x), static_cast<int>(path_points[iterator].y), radius, FILL_TRANSPARENT);
+    }
 }
\ No newline at end of file
--- a/lib/Ball.h	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Ball.h	Thu May 06 12:04:45 2021 +0000
@@ -12,9 +12,9 @@
 public:
 
     Ball();
-    void init();
+    void init(int radius);
 //  std::vector<Vector2Df> get_path;
-    void draw(N5110 &lcd, std::vector<Vector2Df> path_points, int radius, float iterator);
+    void draw(N5110 &lcd, std::vector<Vector2Df> path_points, int radius, int iterator);
 
 };
 #endif 
--- a/lib/Car.cpp	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Car.cpp	Thu May 06 12:04:45 2021 +0000
@@ -3,10 +3,14 @@
 // constructure
 Car::Car() {}
 
-void Car::init() {    
-    //initialize parameters
-    int direction = STRAIGHT;
+void Car::init(int direction, int magnitude, int start_pos) {    
+    // initialize parameters
+    // direction = STRAIGHT;
+    // magnitude = 0; 
+    // start_pos = 38
     _direction = direction;
+    _magnitude = magnitude;
+    _start_pos = start_pos;
 }
 
 
@@ -21,29 +25,27 @@
     else {
         _direction = STRAIGHT;
     } 
-     
     return _direction;
 }
 
     
 int Car::get_magnitude(float coord_x) {
-    int magnitude;
     
     if(coord_x > -0.2 && coord_x < 0.2) {
-        magnitude = 0;
+        _magnitude = 0;
     } 
-    else if(coord_x > 0.8 && coord_x < -0.8) {
-        magnitude = 2;
+    else if(coord_x > 0.8 || coord_x < -0.8) {
+        _magnitude = 2;
     }    
     else {
-        magnitude = 1;
+        _magnitude = 1;
     } 
-    return magnitude;
+    return _magnitude;
 }
 
 
-void Car::draw(N5110 &lcd, float start_pos, float start_angle) { 
-    int x = static_cast<int>(start_pos);
+void Car::draw(N5110 &lcd, int start_pos, float start_angle) { 
+    int x = start_pos;
     int y = static_cast<int>(start_angle);
     
     const int rear_face[12][10] = {
@@ -132,13 +134,13 @@
             lcd.drawSprite(x + y - 2,36,6,4,(int *)wheel);      // wheel 3
             lcd.drawSprite(x - 2,40,6,4,(int *)wheel);          // wheel 1 
             
-            lcd.drawLine(x,42,x + y,38,0,1);                    // line to connect corner 3
-            lcd.drawLine(x + 9,42,x + y + 9,38,0,1);            // line to connect corner 4
+            lcd.drawLine(x,42,x + y,38,0,1);                    // line to connect corner left bottom
+            lcd.drawLine(x + 9,42,x + y + 9,38,0,1);            // line to connect corner right bottom
             
             lcd.drawSprite(x + y + 8,36,6,4,(int *)wheel);      // wheel 4
             
-            lcd.drawLine(x,32,x + y,26,0,1);                    // line to connect corner 1
-            lcd.drawLine(x + 9,32,x + y + 9,26,0,1);            // line to connect corner 2
+            lcd.drawLine(x,32,x + y,26,0,1);                    // line to connect corner left up
+            lcd.drawLine(x + 9,32,x + y + 9,26,0,1);            // line to connect corner right up
             
             lcd.drawSprite(x,32,12,10,(int *)rear_face);
             lcd.drawSprite(x + 8,40,6,4,(int *)wheel);          // wheel 2
@@ -147,19 +149,19 @@
             
         case LEFT:
             lcd.drawSprite(x - y - 2,26,10,10,(int *)window);
-            //lcd.drawSprite(x - y,26,12,10,(int *)front_face);
             lcd.drawLine(x - y,26,x - y + 9,26,0,1);            // front face  
             lcd.drawLine(x - y,26,x - y,36,0,1);                // front face 
             
             lcd.drawSprite(x - y + 8,36,6,4,(int *)wheel);      // wheel 4
             lcd.drawSprite(x + 8,40,6,4,(int *)wheel);          // wheel 2
             
-            lcd.drawLine(x + 9,42,x - y + 9,38,0,1);            // line to connect corner 4
+            lcd.drawLine(x + 9,42,x - y + 9,38,0,1);            // line to connect corner right bottom
+            lcd.drawLine(x,42,x - y,38,0,1);                    // line to connect corner left bottom
             
             lcd.drawSprite(x - 2 - y,36,6,4,(int *)wheel);      // wheel 3
             
-            lcd.drawLine(x,32,x - y,26,0,1);                    // line to connect corner 1
-            lcd.drawLine(x + 9,32,x - y + 9,26,0,1);            // line to connect corner 2
+            lcd.drawLine(x,32,x - y,26,0,1);                    // line to connect corner right up
+            lcd.drawLine(x + 9,32,x - y + 9,26,0,1);            // line to connect corner left up
             
             lcd.drawSprite(x,32,12,10,(int *)rear_face);
             lcd.drawSprite(x - 2,40,6,4,(int *)wheel);          // wheel 1
--- a/lib/Car.h	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Car.h	Thu May 06 12:04:45 2021 +0000
@@ -17,13 +17,15 @@
 public:
 
     Car();
-    void init();
+    void init(int direction, int magnitude, int start_pos);
     int get_direction(float coord_x);
     int get_magnitude(float coord_x);
-    void draw(N5110 &lcd, float start_pos, float start_angle);
+    void draw(N5110 &lcd, int start_pos, float start_angle);
     
 private:
 
     int _direction;
+    int _magnitude;
+    int _start_pos;
 };
 #endif 
\ No newline at end of file
--- a/lib/GameEngine.cpp	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/GameEngine.cpp	Thu May 06 12:04:45 2021 +0000
@@ -1,89 +1,131 @@
-#include "PongEngine.h"
-
-PongEngine::PongEngine(){ _lives = 4; }    
+#include "GameEngine.h"
 
-void PongEngine::init(int paddle_position, int paddle_height, int paddle_width, int ball_size, int speed){
-    //printf("Pong Engine: Init\n");
-    _ball.init(ball_size,speed);
-    _paddle.init(paddle_position, paddle_height, paddle_width);
-}
+// constructure
+GameEngine::GameEngine() {}    
 
-int PongEngine::update(UserInput input) {   
-    //printf("Pong Engine: Update\n");
-    check_goal();  // checking for a goal is a priority 
-    _ball.update();
-    _paddle.update(input);
-    // important to update paddles and ball before checking collisions so can
-    // correct for it before updating the display
-    check_wall_collision();
-    check_paddle_collision();
+void GameEngine::init(int road_direction, 
+                      int road_inclination, 
+                      int radius, 
+                      std::vector<Vector2Df> ball_path,
+                      int car_direction, 
+                      int car_magnitude, 
+                      int car_start_pos, 
+                      float road_offset, 
+                      float car_turn, 
+                      float ball_it)
+{    
+    _road_direction = road_direction;
+    _road_inclination = road_inclination;
+    _radius = radius; 
+    _ball_path = ball_path;
+    _car_direction = car_direction;
+    _car_magnitude = car_magnitude;
+    _car_start_pos = car_start_pos;
+    _road_offset = road_offset; 
+    _car_turn = car_turn;
+    _ball_it = ball_it;
     
-    return _lives;
-}
-
-void PongEngine::draw(N5110 &lcd) {
-    _road.draw(lcd);
+    // initialize all the parameters from the game  
+    _ball.init(_radius);
+    _road.init(_road_direction, _road_inclination);
+    _car.init(_car_direction, _car_magnitude, _car_start_pos);
 }
 
-void PongEngine::check_wall_collision() {
-    //printf("Pong Engine: Check Wall Collision\n");
-    // read current ball attributes
-    Position2D ball_pos = _ball.get_pos();
-    Position2D ball_velocity = _ball.get_velocity();
-    int size = _ball.get_size();
+
+void GameEngine::update(float car_coord) {  
 
-    // 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;  // flip velocity
-    } else if (ball_pos.y + size >= (HEIGHT-1) ) {
-        // hit bottom
-        ball_pos.y = (HEIGHT-1) - size;  // stops ball going off screen
-        ball_velocity.y = -ball_velocity.y;    // flip velcoity 
-    } else if (ball_pos.x + size >= (WIDTH-1) ) {
-        // hit right wall
-        ball_pos.x = (WIDTH-1) - size;  // stops ball going off screen
-        ball_velocity.x = -ball_velocity.x;    // flip velcoity 
+    // Get the user input to know where to draw the car
+    _car_direction = _car.get_direction(car_coord); 
+    _car_magnitude = _car.get_magnitude(car_coord); 
+    
+    if(_car_direction == 0) {       // STRAIGHT
+        _car_turn = 0;
+    }  
+    if(_car_direction == 2) {       // LEFT
+        if(_car_magnitude == 1) {
+            _car_turn = 4.0;
+        }
+        if(_car_magnitude == 2) {   
+            _car_turn = 6.0;
+        }
+        _car_start_pos -=  0.2 * _car_magnitude; 
+    }          
+    if(_car_direction ==  1) {      // RIGHT
+        if(_car_magnitude == 1) {
+            _car_turn = 4.0;
+        }
+        if(_car_magnitude == 2) {
+            _car_turn = 6.0;
+        }
+        _car_start_pos += 0.2 * _car_magnitude;
+    }
+    
+    // Define boundaries for car movement
+    if(_car_start_pos < 22.0) {
+        _car_start_pos = 22.0;
+    }   
+    if(_car_start_pos > 55.0) {
+        _car_start_pos = 55.0;
     } 
 
-    // update ball parameters
-    _ball.set_velocity(ball_velocity);
-    _ball.set_pos(ball_pos);
+    // Make sure that middle line on road is moving continuously 
+   _road_offset += 0.01;
+   
+   
+    if(_ball_it < _ball_path.size()){
+        _ball_it += 0.3;
+        // Get the ball generation function 
+        _iterator = static_cast<int>(_ball_path.size() - _ball_it); 
+    }
+    else {
+        _iterator = 0;
+    }
 }
 
-void PongEngine::check_paddle_collision() {
-    //printf("Pong Engine: Check Paddle Collision\n");
-    // read current ball and paddle attributes
-    Position2D ball_pos = _ball.get_pos();
-    Position2D ball_velocity = _ball.get_velocity();
-    Position2D paddle_pos = _paddle.get_pos();  // paddle
+void GameEngine::reset_ball() {
+    _ball_it = 0;    
+}
+
 
-    // see if ball has hit the paddle by checking for overlaps
-    if (
-        (ball_pos.y >= paddle_pos.y) && //top
-        (ball_pos.y <= paddle_pos.y + _paddle.get_height() ) && //bottom
-        (ball_pos.x >= paddle_pos.x) && //left
-        (ball_pos.x <= paddle_pos.x + _paddle.get_width() )  //right
-    ) {
-        // if it has, fix position and reflect x velocity
-        ball_pos.x = paddle_pos.x + _paddle.get_width();
-        ball_velocity.x = -ball_velocity.x;
+void GameEngine::draw(N5110 &lcd, Utils &utils) {
+    _road.draw(lcd, utils, _road_direction, _road_offset);
+    _ball.draw(lcd, _ball_path, _radius, _iterator);
+    _car.draw(lcd, _car_start_pos, _car_turn);
+}
+
+
+int GameEngine::check_collision() {
+    if (static_cast<int>(_ball_path[_iterator].y) > 38
+        && static_cast<int>(_ball_path[_iterator].y) < 46
+        && static_cast<int>(_ball_path[_iterator].x) <= _car_start_pos + 12
+        && static_cast<int>(_ball_path[_iterator].x) >= _car_start_pos - 2)
+    {
+        return 1;   
     }
 
-    // write new attributes
-    _ball.set_velocity(ball_velocity);
-    _ball.set_pos(ball_pos);
+    
+    else {
+        return 0;   
+    }
+} 
+   
+    
+void GameEngine::generate_road(float tilt) {  
+
+    if (_road_direction < tilt - 0.05) {
+        _road_direction += 0.05;
+    }
+        
+    else if (_road_direction > tilt + 0.05) {
+        _road_direction -= 0.05;
+    }    
+    
+    else {
+        _road_direction = tilt;
+    }
 }
 
-void PongEngine::check_goal() {
-    //printf("Pong Engine: Check Goal\n");
-    Position2D ball_pos = _ball.get_pos();
-    int size = _ball.get_size();
-    int speed = abs(_ball.get_velocity().x);  // speed is magnitude of velocity
-    // check if ball position has gone off the left
-    if (ball_pos.x + size < 0) {
-        // reset the ball
-        _ball.init(size,speed);
-        _lives--;  // lose a life
-    }   
+void GameEngine::generate_ball(int start){
+    std::vector<Vector2Df> ball_path = _utils.getCurve(42 + start,48,42 + 5 * _road_direction + start, 30 - abs(_road_direction),42 + start,12);
+    _ball_path = ball_path;
 }
\ No newline at end of file
--- a/lib/GameEngine.h	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/GameEngine.h	Thu May 06 12:04:45 2021 +0000
@@ -7,21 +7,64 @@
 #include "Utils.h"
 #include "Road.h"
 #include "Car.h"
-#include "Vector.h"
+#include "Vector.h"    
 
-class GameEngine {
-    public:
-        GameEngine();  // pass in the lcd object from the main file
-        void init(int paddle_position,int paddle_height,int paddle_width,int ball_size,int speed);
-        int update(UserInput input);
-        void sign(N5110 &lcd, Road &road);
-        void draw(N5110 &lcd);
-    private:
-        void check_collision();
-        void generate_ball();
-        void generate_road();
-        Ball _ball;
-        Road _road;
+class GameEngine 
+{
+public:
+    
+    GameEngine();     
+        
+    /** Initialize game
+    *   @param  road_direction     - set up the road as STRAIGHT (0)
+    *   @param  road_inclination   - set up the inclination of the road as 0
+    *   @param  radius             - set the ball radius as 4
+    *   @param  ball_path          - initial the ball start position
+    *   @param  car_direction      - set up the car view as STRAIGHT (0)
+    *   @param  car_magnitude      - set up the car tilt as 0
+    *   @param  car_start_pos      - set up the car position as 38 (right in the centre)
+    *   @param  road_offset        - should increase continuously 
+    *   @param  car_turn           - the angle at which the car turns
+    *   @param  ball_it            - the iterator that draws the ball
+    **/
+    void init(int road_direction, 
+              int road_inclination, 
+              int radius, 
+              std::vector<Vector2Df> ball_path,
+              int car_direction, 
+              int car_magnitude, 
+              int car_start_pos, 
+              float road_offset, 
+              float car_turn, 
+              float ball_it);
+                  
+    int check_collision();   
+    void update(float car_coord);
+    void sign(N5110 &lcd, Road &road);
+    void reset_ball();
+    void draw(N5110 &lcd, Utils &utils);
+    void generate_road(float tilt);  
+    void generate_ball(int start);  
+    
+    
+private:
+
+    Ball _ball;
+    Road _road;
+    Car _car;
+    Utils _utils;
+    
+    float _road_offset;                     // Road
+    float _road_direction;                  // Road, i
+    int _road_inclination;                  // Road
+    float _ball_it;                         // Ball, it
+    int _radius;                            // Ball
+    std::vector<Vector2Df> _ball_path;      // Ball
+    int _iterator;                        // Ball
+    int _car_direction;                     // Car
+    int _car_magnitude;                     // Car
+    float _car_start_pos;                   // Car
+    float _car_turn;                        // Car, y
+    
 };
-
 #endif
\ No newline at end of file
--- a/lib/Road.cpp	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Road.cpp	Thu May 06 12:04:45 2021 +0000
@@ -3,24 +3,23 @@
 // constructure
 Road::Road() {}
 
-void Road::init() {    
+void Road::init(float direction, float inclination) {    
     //initialize parameters
-    int direction = 0;
-    int inclination = 0;
-    
     _direction = direction;
     _inclination = inclination;
 }
 
-void Road::set_inclination(int inclination) {
+void Road::set_inclination(float inclination) {
     _inclination = inclination; 
     }
 
 void Road::draw(N5110 &lcd, Utils &utils, float direction, float offset) { 
+    // direction is i in the main code
+    // use "+= or -= speed" to get the direction of the road
     lcd.drawLine (0,12,84,12,0,1);
-    std::vector<Vector2Df> curve_points_1 = utils.getCurve(12,48,20 + 5 * direction, 30 - abs(direction),28,12);
-    std::vector<Vector2Df> curve_points_2 = utils.getCurve(72,48,64 + 5 * direction, 30 - abs(direction),56,12);
-    std::vector<Vector2Df> curve_points_3 = utils.getCurve(42,48,42 + 5 * direction, 30 - abs(direction),42,12);
+    std::vector<Vector2Df> curve_points_1 = utils.getCurve(12,48,20 + 5 * direction, 30 - abs(direction),28,12);    // LEFT
+    std::vector<Vector2Df> curve_points_2 = utils.getCurve(72,48,64 + 5 * direction, 30 - abs(direction),56,12);    // RIGHT
+    std::vector<Vector2Df> curve_points_3 = utils.getCurve(42,48,42 + 5 * direction, 30 - abs(direction),42,12);    // MIDDLE
         
     lcd.drawCurve(curve_points_1, 0, 1, TYPE_SOLID);
     lcd.drawCurve(curve_points_2, 0, 1, TYPE_SOLID);
--- a/lib/Road.h	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Road.h	Thu May 06 12:04:45 2021 +0000
@@ -13,15 +13,15 @@
 public:
 
     Road();
-    void init();
-    void set_inclination(int inclination);
+    void init(float direction, float inclination);
+    void set_inclination(float inclination);
     void draw(N5110 &lcd, Utils &utils, float direction, float offset);
     void draw_warn(N5110 &lcd, int warn_position);
 
 private:
 
-    int _inclination;
-    int _direction;
+    float _inclination;
+    float _direction;
 
 };
 #endif 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ShiftReg.cpp	Thu May 06 12:04:45 2021 +0000
@@ -0,0 +1,26 @@
+#include "ShiftReg.h"
+
+ShiftReg::ShiftReg()
+{
+    clkout = new DigitalOut(p7);
+    dataout = new DigitalOut(p5);
+    latchout = new DigitalOut(p30);
+}
+
+ShiftReg::~ShiftReg()
+{
+    delete clkout;
+    delete dataout;
+    delete latchout;
+}
+
+void ShiftReg::write(int data)
+{
+    *latchout = 0;
+    for (int i = 7; i >=  0; i--) {
+        *clkout = 0;
+        *dataout = (data & (1 << i)) != 0;
+        *clkout = 1;
+    }
+    *latchout = 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ShiftReg.h	Thu May 06 12:04:45 2021 +0000
@@ -0,0 +1,23 @@
+#ifndef SHIFTREG_H
+#define SHIFTREG_H
+
+#include <mbed.h>
+
+/** A simple serial driver for a shift register that uses only three digital out pins.
+* Based on a fork of Ollie8/ShiftOut
+*/
+class ShiftReg {
+
+    public :
+    
+        ShiftReg();    
+        ~ShiftReg();
+        void write(int data);
+         
+    private :
+        DigitalOut *clkout;
+        DigitalOut *dataout;
+        DigitalOut *latchout;
+};
+
+#endif
\ No newline at end of file
--- a/lib/Utils.cpp	Sat Apr 24 21:31:19 2021 +0000
+++ b/lib/Utils.cpp	Thu May 06 12:04:45 2021 +0000
@@ -25,7 +25,7 @@
 {  
     // vertor that will store all points 
     std::vector<Vector2Df> curve_points;
-    for(float i = 0 ; i <= 1 ; i += 0.2)
+    for(float i = 0 ; i <= 1 ; i += 0.05)
     {
         float xa, ya, xb, yb; 
         xa = curveEquation(x0 , x1 , i);
--- a/main.cpp	Sat Apr 24 21:31:19 2021 +0000
+++ b/main.cpp	Thu May 06 12:04:45 2021 +0000
@@ -4,6 +4,7 @@
  */
 
 #include "mbed.h"
+#include "ShiftReg.h" 
 #include "Joystick.h"
 #include "N5110.h"
 #include "Road.h"
@@ -11,13 +12,20 @@
 #include "Utils.h"
 #include "Vector.h"
 #include "Ball.h"
+#include "Vector.h"
+#include "GameEngine.h"
+#include <stdlib.h>     
+#include <time.h>       
 
 // objects
 // BusOut leds(LED4,LED3,LED2,LED1);
 
 N5110 lcd(p14,p8,p9,p10,p11,p13,p21); 
-DigitalIn button_A(p29);
+InterruptIn button_A(p29);
+DigitalIn button_B(p28);
 DigitalIn button_C(p27);
+DigitalIn button_D(p26);
+ShiftReg seven_seg;
 
 //                 y   x  
 Joystick joystick(p20,p19);
@@ -30,6 +38,13 @@
 Utils utils;
 Car car;
 Ball ball;
+GameEngine game;
+Ticker ticker;
+
+// flag - must be volatile as changes within ISR
+// g_ prefix makes it easier to distinguish it as global
+volatile int g_timer_flag = 0;
+volatile int g_buttonA_flag = 0;
 
 #define speed 0.01
 #define road_speed 0.016
@@ -37,93 +52,158 @@
 
 // functions
 void init_buttons();
+void init();
+void render();
+void menu();
+void instructions();
+void pause();
+void game_over();
+void draw_arrow(int x, int y);
+void timer_isr();
+void buttonA_isr();
+void display_lives(int lives);
 
 int main()
 {
-    // initialisation
-    lcd.init();
-    road.init();
-    car.init();
-    joystick.init();
-    lcd.setContrast(0.5);
-   
-    float i = 0;
-    float offset = 0;
-    float start_pos = 38.0;
-    float y = 0.0;
-    float it = 0.0;
-    float perspective = 0.0;
+    button_A.rise(&buttonA_isr);
+    init_buttons();
+    int state = 0;  // set inital state
+    init();
+    // welcome();
+    int up_down = 17;
+    float number_1 = 0;
+    float number_2 = 0;
+    int lives = 4;
+    int old_collision = 0;
+    display_lives(0);
+    
+    // set-up the ticker so that the ISR it is called every 5 seconds
+    ticker.attach(&timer_isr,5);
     
     while(1) {
         lcd.clear();
-        road.draw(lcd, utils, i, offset);
-        
-        if (button_A.read() == 1) {
+        Vector2D coord = joystick.get_mapped_coord(); 
+        switch(state) {
             
-            road.draw_warn(lcd, 1);  
-            i += speed;  
-        }
-        
-        if (button_C.read() == 1) {
-            road.draw_warn(lcd, 2);
-            i -= speed;   
-        }
-        offset += road_speed;
-        
-        Vector2D coord = joystick.get_mapped_coord();
-        int direction = car.get_direction(coord.x);
-        int magnitude = car.get_magnitude(coord.x);
-        
-        if(direction == STRAIGHT) {
-            y = 0;
+            case 0: // Main Menu
+            {
+                menu();
+                lives = 4;
+                display_lives(0);
+                if(coord.y >= 0.5) {
+                    up_down = 17;
+                }
+                
+                if(coord.y <= -0.5) {
+                    up_down = 25;
+                }
+                
+                draw_arrow(2,up_down);
+                
+                if(g_buttonA_flag) {
+                    if(up_down == 17){
+                        state = 1;
+                        g_buttonA_flag = 0;
+                    }
+                    if(up_down == 25) {
+                        state = 2;
+                        g_buttonA_flag = 0;
+                    }
+                }  
+                break;
             }
-        
-        if(direction == LEFT) {
-            if(magnitude == 1) {
-                y = 4.0;
-                }
-            if(magnitude == 2) {
-                y = 4.0;
+            
+            
+            case 1: // Actual Game
+            {
+                game.update(coord.x);
+                
+                // check if flag is set i.e. interrupt has occured
+                if (g_timer_flag) {
+                    g_timer_flag = 0;  // if it has, clear the flag
+                    
+                    // generate random road or ball
+                    // initialize random seed: 
+                    srand (time(NULL));
+                    
+                    number_1 = (rand() % 20 + 1) - 10;
+                    number_2 = (static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/10.0))) - 5.0;
+                    game.reset_ball();
                 }
-            start_pos -= car_speed;
-        } 
-              
-        if(direction ==  RIGHT) {
-            if(magnitude == 1) {
-                y = 4.0;
+                
+                game.generate_ball(number_1);
+                game.generate_road(number_2);
+         
+                // put the MCU to sleep until an interrupt wakes it up
+                sleep();
+                render();
+                display_lives(lives);
+                
+                int collision = game.check_collision();
+                if(collision == 1 && old_collision == 0) {
+                    lives--;
+                    if (lives == 0) {
+                        state = 4;
+                    }
+                }
+                
+                old_collision = collision;
+                
+                if(g_buttonA_flag) {
+                    state = 3;
+                    g_buttonA_flag = 0;   
+                }
+                break;
+            }
+            
+           
+            case 2:  // Instructions 
+            {
+                instructions();
+                if(g_buttonA_flag) {
+                    state = 0;
+                    g_buttonA_flag = 0;
                 }
-            if(magnitude == 2) {
-                y = 8.0;
+                break;   
+            }
+                 
+                
+            case 3: // Pause Menu
+            {
+                pause();
+                if(coord.y >= 0.5) {
+                    up_down = 17;    
                 }
-            start_pos += car_speed;
-        }
-        
-        // define boundaries for car movement
-         if(start_pos < 20.0) {
-            start_pos = 20.0;
+                if(coord.y <= -0.5) {
+                    up_down = 25;
+                    }    
+                
+                draw_arrow(2,up_down);
+                if(g_buttonA_flag) {
+                    if(up_down == 17){
+                        state = 1;
+                        g_buttonA_flag = 0;
+                    }
+                    if(up_down == 25) {
+                        state = 0;
+                        g_buttonA_flag = 0;
+                    } 
+                }
+                break;
+            }
+            
+            case 4: // Game over
+            {
+                game_over();
+                if(g_buttonA_flag) {
+                    state = 0;
+                    g_buttonA_flag = 0;
+                }
+                break;  
+            } 
         }
-        
-        if(start_pos > 55.0) {
-            start_pos = 55.0;
-        }
-        
-        car.draw(lcd,start_pos,y);
-     
-        std::vector<Vector2Df> path_points = utils.getCurve(12,60,25,30,28,12);
-        float iterator = path_points.size() - it;
-        
-        // take the current coordinates and draw circle on the line
-        ball.draw(lcd, path_points, 4, iterator);
-        it += 0.03;
-        perspective += road_speed;  
-              
-        printf("%f\n", it);
-        
-        if (it > 10) {
-            it = 0;
-        }
-        
-        lcd.refresh(); 
+    sleep();
+    lcd.refresh();
     }
 }
 
@@ -132,5 +212,101 @@
     // PCB has external pull-down resistors so turn the internal ones off
     // (default for DigitalIn)
     button_A.mode(PullNone);
+    button_B.mode(PullNone);
     button_C.mode(PullNone);
+    button_D.mode(PullNone);
+}
+
+
+void init() {
+    seven_seg.write(0x00); 
+    lcd.init();
+    joystick.init();
+    lcd.setContrast(0.55);
+    
+    std::vector<Vector2Df> curve_point;
+    Vector2Df point = {-20.0,-50.0};
+    curve_point.push_back(point);
+    
+    game.init(0.0,          // road direction
+              0.0,          // road inclination
+              4,            // ball radius
+              curve_point,  // points from ball path
+              0,            // car direction
+              0,            // car magnitude 
+              38.0,         // car start position
+              0.0,          // offset
+              0.0,          // car_turn
+              0.0);         // ball_it
+}
+
+void menu() { 
+    lcd.printString("MAIN MENU",15,0);
+    lcd.printString("Start Game",10,2);
+    lcd.printString("Instructions",10,3); 
+    lcd.printString("Press A",20,5); 
+}
+
+void instructions() {  
+    lcd.printString("INSTRUCTIONS",6,0);
+    lcd.printString("Use joystick",6,1);
+    lcd.printString("to move",21,2);
+    lcd.printString("Press A to",13,4);
+    lcd.printString("pause or exit",4,5);
+    display_lives(0);
+}
+
+void pause() { 
+    lcd.printString("PAUSE",27,0);
+    lcd.printString("Back to game",10,2);
+    lcd.printString("Back to menu",10,3); 
+}
+
+void game_over() {
+    lcd.printString("GAME OVER",16,1); 
+    lcd.printString("Don't collide!",1,2); 
+    lcd.printString("Press A",20,5); 
+}
+
+void render() { 
+    game.draw(lcd, utils);
+}
+
+void draw_arrow(int x, int y) {
+    const int arrow[5][7] = {
+        { 0, 0, 0, 0, 1, 0, 0 },
+        { 1, 1, 1, 1, 1, 1, 0 },
+        { 1, 1, 1, 1, 1, 1, 1 },
+        { 1, 1, 1, 1, 1, 1, 0 },
+        { 0, 0, 0, 0, 1, 0, 0 },
+    };  
+    lcd.drawSprite(x,y,5,7,(int *)arrow);
+}
+
+// time-triggered interrupt
+void timer_isr() {
+    g_timer_flag = 1;   // set flag in ISR
+}
+
+// Button A event-triggered interrupt
+void buttonA_isr() {
+    g_buttonA_flag = 1;   // set flag in ISR     
+}
+
+void display_lives(int lives) {
+    if (lives == 4) {
+        lcd.printString("Lives: 4",0,0);
+        seven_seg.write(0x66);
+    } else if (lives == 3) {
+        lcd.printString("Lives: 3",0,0);
+        seven_seg.write(0x4F);
+    } else if (lives == 2) {
+        lcd.printString("Lives: 2",0,0);
+        seven_seg.write(0x5B);
+    } else if (lives == 1) {
+        lcd.printString("Lives: 1",0,0);
+        seven_seg.write(0x06);
+    } else {
+        seven_seg.write(0x3F);
+    }
 }
\ No newline at end of file