
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
Diff: main.cpp
- 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