A project that creates falling asteroids at random positions along the top of the screen for a space ship at the bottom to shoot, using a Nokia N5110 LCD, joystick and pushbuttons

Dependencies:   DebounceIn N5110 PowerControl mbed

Revision:
0:6eba0e66ce01
Child:
2:8d28a2f491eb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri May 08 09:24:50 2015 +0000
@@ -0,0 +1,373 @@
+/**
+@file main.cpp
+
+@brief Program implementation
+
+@author Louis Wray
+
+@date 14th April 2015
+*/
+
+#include "main.h"
+
+/// timer to regularly read the joystick
+Ticker pollJoystick;
+/// timer to regularly call the read bullet function
+Ticker readShoot;
+/// timer to regularly call new asteroids
+Ticker readTheAsteroid;
+/// timeout to create the asteroids
+Timer shootSoundtimer;
+
+/**
+create enumerated type (0,1,2,3 etc. for direction)
+*/
+enum DirectionName {
+    UP,
+    DOWN,
+    LEFT,
+    RIGHT,
+    CENTRE,
+    UNKNOWN
+};
+
+/**
+struct for Joystick
+*/
+typedef struct JoyStick Joystick;
+struct JoyStick {
+    float x;    /// current x value
+    float x0;   /// 'centred' x value
+    float y;    /// current y value
+    float y0;   /// 'centred' y value
+    int button; /// button state (assume pull-down used, so 1 = pressed, 0 = unpressed)
+    DirectionName direction;  /// current direction
+};
+/// create struct variable
+Joystick joystick;
+
+int printFlag =0; /**< flag for calling joystick value printing */
+int state = 0; /**< integer value for what state the game is in.
+for use of the switch statement */
+int GenAsteroidFlag = 0; /// asteroid generation flag
+int AsteroidCreatedFlag = 0; /// flag to note asteroid is created
+int BulletExistsFlag = 0; /// flag to note bullet has been fired and is on screen
+int PauseNumber = 0;
+
+int main()
+{
+    asteroid.nscore = 0;
+    srand(15000*randomPin); /// seeding random function
+    calibrateJoystick();  /// set's centred values of joystick
+    pollJoystick.attach(&updateJoystick,1/45.0);  /// read joystick 45 times per second
+    ship.SetValues(42,39); /// initialise ships starting x,y coordinates
+
+    PHY_PowerDown(); /// power down ethernet connection
+
+    while(1) {
+
+        switch(state) { /// switch statement this enables the game to switch between states giving a start state
+                /// a game play state and subsequently a game over state giving choice to start again.
+
+            case 0:
+                startUpDisplay(); /// call start up display function
+                state=1;
+                break;
+
+            case 1:
+                Game(); /// game play
+                break;
+
+            case 2:
+                lcd.clear();
+                PauseDisplay();
+                break;
+
+            case 3:
+                EndDisplay(); /// end of game display
+                break;
+        }
+
+        Sleep(); /// sleep function when nothings happening mbed can sleep and save power consumption
+    }
+}
+
+void startUpDisplay()
+{
+    lcd.init(); /// initialise the display
+    lcd.clear();
+    lcd.printString("Space-Teroid",6,1); /// opening message
+    lcd.printString("Press S5 to",12,3);
+    lcd.printString("Play",30,4);
+    lcd.drawLine(0,0,0,47,1); /// draw outline
+    lcd.drawLine(83,0,83,47,1);
+    lcd.drawLine(0,0,83,0,1);
+    lcd.drawLine(0,47,83,47,1);
+    lcd.refresh(); /// refesh LCD to create this display
+
+    while(!buttonP) { /// while the pause flag or pause button has not been set or used , the mbed will sleep saving power and allowing
+        /// the user to start when they are ready
+        sleep();
+    }
+    GenAsteroidFlag = 1;
+    lcd.clear(); /// when flag has been set while loop has been broken and start up display will be escaped
+    ship.shape(); /// the ships shape is drawn and  and the game can begin
+}
+
+void Game()
+{
+    lcd.drawLine(0,0,0,47,1); /// draw outline repeatedly when asteroid is falling
+    lcd.drawLine(83,0,83,47,1);
+    lcd.drawLine(0,0,83,0,1);
+    lcd.drawLine(0,47,83,47,1);
+    
+    if (printFlag) {  /// if print flag set, clear flag and use joysticks horizontal position
+        printFlag = 0;
+
+        if (joystick.direction == LEFT && ship.xs>=7) { /// 7 represents the left most boundary
+            ship.ShipLeft(); /// if joystick moves left, call ship moving left function
+        }
+        if (joystick.direction == RIGHT && ship.xs<=76) { /// 76 represents the right most boundary
+            ship.ShipRight(); /// if joystick moves right, call the ship moving right function
+        } else {} /// else do nothing
+    }
+
+    if(button) {
+        AsteroidCreatedFlag = 0;
+        GenAsteroidFlag = 0;
+        asteroid.destroyAsteroid();
+        readTheAsteroid.detach();
+        PWM1 = 0;
+        state = 2;
+
+    } else {}
+
+
+    if(BulletExistsFlag==0) { /// check if there is already a bullet on the screen, a rule of the game one bullet at a time!
+        if(buttonS) { /// if shoot button is pressed
+
+            shootSoundtimer.start(); /// start timer for shooting sound
+            PWM1.period(2e-3); /// set the period of the PWM
+            PWM1 = 0.5; /// set the duty cycle
+            BulletExistsFlag=1; /// bullet exists flag set
+            bullet.SetValues(ship.xs,ship.ys-1); /// set the bullets values according to where the ship is
+
+            bullet.collision(); /// chec for bullet collision
+            if(bullet.collision()==true) {
+                readShoot.detach();
+                bullet.clearBullet();
+                BulletExistsFlag=0;
+
+                /** if bullet colision happens during sound being made then
+                buzzer doesnt stop, thisis because of the interrupt the button makes
+                here we reset the buzzer manually */
+                shootSoundtimer.stop(); /// stop the timer
+                shootSoundtimer.reset(); /// reset the timer
+                PWM1 = 0.0; /// turn of the PWM
+            }
+
+            else if(bullet.collision()==false) { /// if bullet co-ordinates are not off the screen
+                bullet.createBullet(); /// create the bullet
+                readShoot.attach(&ReadBullet,0.05); /// set ticker to read the position of the bullet
+            } else {}
+
+            if(AsteroidCreatedFlag==1) { /// check if an asteroid has been created
+                readTheAsteroid.attach(&ReadAsteroid,0.05); /// set ticker for asteroid movement
+            } else {}
+        } else {}
+    }
+
+    if(GenAsteroidFlag == 1) { /// check if an asteroid is to be generated
+        int A = rand() % 75 + 6; /// returns random value between 6 and 7
+        asteroid.SetAsteroidValue(A,0); /// set asteroid position according to randomly generated value
+        asteroid.createAsteroid(); /// create asteroid
+        AsteroidCreatedFlag = 1; /// set flag to state an asteroid has been created and is on screen
+        GenAsteroidFlag=0; /// reset Generate asteroid flag so no more asteroid are created
+        if(AsteroidCreatedFlag==1) { /// if asteroid has been created
+            readTheAsteroid.attach(&ReadAsteroid,0.05); /// set ticker to read and move asteroid
+        } else {}
+
+    } else {}
+
+}
+
+void ReadAsteroid()
+{
+
+    bullet.collision(); /// check if the bullet has made a collision this must mean an asteroid has been shot
+    if(bullet.collision()==false) { /// if no collision and the asteroid y position is less than the end of the screen move the asteroid
+        asteroid.ya=asteroid.ya+1; /// move asteroids y position down the screen
+        asteroid.erasePrevAsteroid(); /// erase the previous asteroid
+        asteroid.createAsteroid(); /// create the asteroid in its new position
+    } else {}
+
+    ////////// using a double check seems to make the game run smoother //////////////
+    bullet.collision(); /// check if the bullet has made a collision this must mean an asteroid has been shot
+    if(bullet.collision()==true) { /// if a collision is made
+        BulletExistsFlag=0; /// reset the bullet exists flag
+        readShoot.detach();
+        readTheAsteroid.detach(); /// detach the read asteroid function from the ticker
+        bullet.clearBullet(); /// clear the bullet from the screen
+        AsteroidCreatedFlag=0; /// reset Asteroid created Flag to state there is no longer an asteroid on screen
+        GenAsteroidFlag=1; /// set the Generate asteroid flag
+        asteroid.destroyAsteroid(); /// destroy on screen asteroid
+    } else {}
+
+    asteroid.armageddon(); /// check if asteroid has reached the bottom of the screen
+    if(asteroid.armageddon() == true) { /// if asteroid has it the bottom of the screen ... RUN!!!
+        /// armageddon takes place and the game is over
+        bullet.clearBullet(); /// clear the existing bullet
+        readTheAsteroid.detach(); /// detach the read asteroid function
+        asteroid.destroyAsteroid(); /// destroy asteroid in place
+        asteroid.nscore=asteroid.nscore-1; /// minus one point for the asteroid that was detroyed in losing
+        state=3; /// go to state 3 (end screen)
+    } else {}
+
+    lcd.drawLine(0,0,83,0,1);
+    
+}
+
+void ReadBullet()
+{
+    if(shootSoundtimer.read() > 0.1) { /// check when the sound timer reaches 0.1 sec
+        shootSoundtimer.stop(); /// stop the timer
+        shootSoundtimer.reset(); /// reset the timer
+        PWM1 = 0.0; /// turn of the PWM
+    } else {}
+
+    if(button) {
+        AsteroidCreatedFlag = 0;
+        GenAsteroidFlag = 0;
+        asteroid.destroyAsteroid();
+        readTheAsteroid.detach();
+        PWM1 = 0;
+        state = 2;
+
+    } else {}
+    bullet.collision(); /// check if the bullet has collided with anything
+    bullet.offScreen(); /// check if the bullet is off screen
+    if (bullet.collision() == true||bullet.offScreen()==true) { /// if a collision is made or the bullet goes off the screen
+        BulletExistsFlag=0;
+        bullet.clearBullet(); /// clear the bullet
+        readShoot.detach(); /// detach the ticker
+
+        /** if bullet colision happens during sound being made then
+        buzzer doesnt stop, thisis because of the interrupt the button makes
+        here we reset the buzzer manually*/
+        shootSoundtimer.stop(); /// stop the timer
+        shootSoundtimer.reset(); /// reset the timer
+        PWM1 = 0.0; /// turn of the PWM
+    } else {}
+
+    bullet.y=bullet.y-1; /// move the bullet up i.e. move its y coordinate
+    bullet.createBullet(); /// draw new bullet
+    bullet.erasePrevBullet(); /// erase previous position
+
+////////// double check this seems to help rid some bugs ////////////
+
+    bullet.offScreen(); /// check if the bullet is off screen
+    bullet.collision(); /// check if the bullet has collided with anything
+    if (bullet.collision() == true||bullet.offScreen()==true) { /// if a collision is made or the bullet goes off the screen
+        BulletExistsFlag=0;
+        bullet.clearBullet(); /// clear the bullet
+        readShoot.detach(); /// detach the ticker
+    } else {}
+
+
+    if (printFlag) {  /// here we are checking the position of the joystick, so the user can move while the bullet is shooting else where
+        printFlag = 0;
+        if (joystick.direction == LEFT && ship.xs>=7) {
+            ship.ShipLeft();
+        }
+        if (joystick.direction == RIGHT && ship.xs<=76) {
+            ship.ShipRight();
+        } else {}
+    }
+}
+
+void EndDisplay()
+{
+    lcd.clear(); /// clear entire display to make way for end screen
+    asteroid.nscore = asteroid.nscore-PauseNumber; /// takes points off for the asteroid destroyed when pausing game and destroy asteroid command sent
+    char buffer[14]; /// set buffer to 14, screen 84 pixels long , 6 pixel per char , 84/6 = 14
+    int score = sprintf(buffer,"Score: %d",asteroid.nscore); /// print formatted data to buffer
+    if (score <= 14) { /// if string will fit on display
+        lcd.printString(buffer,10,5);   /// display on screen
+    }
+
+
+
+    lcd.printString("Game Over !",12,1); /// closing message
+    lcd.printString("Press S4 to",11,2);
+    lcd.printString("Play again",12,3);
+    lcd.drawLine(0,0,0,47,1); /// draw outline
+    lcd.drawLine(83,0,83,47,1);
+    lcd.drawLine(0,0,83,0,1);
+    lcd.drawLine(0,47,83,47,1);
+    lcd.refresh(); /// refesh LCD to create this display
+
+    while(!buttonS) { /// while button b has not been pressed sleep (save power)
+        Sleep();
+    }
+    /// when button s pressed
+    state = 0; /// set the state to 0 (intital game display
+    asteroid.nscore=0; /// reset the score
+}
+
+void PauseDisplay()
+{
+    lcd.printString("PAUSE",28,1); /// print pause display message
+    lcd.printString("press S5 to",11,3);
+    lcd.printString("resume",24,4);
+    lcd.drawLine(0,0,0,47,1); /// draw outline
+    lcd.drawLine(83,0,83,47,1);
+    lcd.drawLine(0,0,83,0,1);
+    lcd.drawLine(0,47,83,47,1);
+    lcd.refresh();
+    while(!buttonP) { /// while button P is not pressed Sleep() to save power
+        Sleep();
+        if(buttonP) { /// if button P is pressed
+            lcd.clear(); /// clear LCD
+            ship.shape(); /// draw the ship back on in position it was left
+            GenAsteroidFlag = 1; /// reset the Generate asteroid flag
+            PauseNumber = PauseNumber+1; /// increment pause amount counter
+            state=1; /// state = 1 means back to the game in the switch statement
+        }
+    }
+}
+
+void calibrateJoystick()
+{
+    button.mode(PullDown);
+    /// must not move during calibration
+    joystick.x0 = xPot;  /// initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
+    joystick.y0 = yPot;
+}
+
+void updateJoystick()
+{
+    /// reading the joystick position 0.0 is centered returns a value in the range -0.5 and 0.5
+    joystick.x = xPot - joystick.x0;
+    joystick.y = yPot - joystick.y0;
+    /// read button state
+    joystick.button = button;
+
+    /// calculate direction depending on x,y values
+    /// tolerance allows a little lee-way in case joystick not exactly in the stated direction
+    if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
+        joystick.direction = CENTRE;
+    } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
+        joystick.direction = UP;
+    } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
+        joystick.direction = DOWN;
+    } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
+        joystick.direction = RIGHT;
+    } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
+        joystick.direction = LEFT;
+    } else {
+        joystick.direction = UNKNOWN;
+    }
+
+    /// set flag for use of the joystick position
+    printFlag = 1;
+}
\ No newline at end of file