
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, committed 2015-05-08
- Comitter:
- wray2303
- Date:
- Fri May 08 09:24:50 2015 +0000
- Child:
- 1:71da2fca5e97
- Commit message:
- pre-update
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebounceIn.lib Fri May 08 09:24:50 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/DebounceIn/#31ae5cfb44a4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/N5110.lib Fri May 08 09:24:50 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/eencae/code/N5110/#7aaa6802ce64
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PowerControl.lib Fri May 08 09:24:50 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/JST2011/code/PowerControl/#d0fa2aeb02a4
--- /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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.h Fri May 08 09:24:50 2015 +0000 @@ -0,0 +1,344 @@ +/** +@file main.h +@brief Header file containing functions prototypes, defines and global variables. +@author Louis Wray +@date 14th April 2015 +*/ + +#ifndef MAIN_H +#define MAIN_H +#include "mbed.h" +#include "N5110.h" +#include "PowerControl/PowerControl.h" +#include "PowerControl/EthernetPowerControl.h" +#include "DebounceIn.h" +#define DIRECTION_TOLERANCE 0.05 + +/** +@namespace button +@brief represents button input pin from joystick +*/ +DebounceIn button(p17); + +/** +@namespace buzzer +@brief represents buzzer output pin from pwm +*/ +PwmOut PWM1(p25); + +/** +@namespace xPot +@brief analog input from potentiometer reading x position +*/ +AnalogIn xPot(p15); + +/** +@namespace yPot +@brief analog input from potentiometer reading y position +*/ +AnalogIn yPot(p16); + +/** +@namespace randomPin +@brief analog input to seed random function +*/ +AnalogIn randomPin(p19); + +/** +@namespace serial +@brief serial connection established +*/ +Serial serial(USBTX,USBRX); + +/** +@namespace myled +@brief GPIO for on board mbed LED1 +*/ +DigitalOut myled(LED1); + +/** +@namespace lcd +@brief creates object for display. +@brief shows pins used and there configuration +*/ +N5110 lcd(p7,p8,p9,p10,p11,p13,p26); // pin settings + +/** +@namespace buttonS +@brief creates interrupt in for shooting function. +*/ +DebounceIn buttonS(p22); // create interrupt button shoot + +/** +@namespace buttonP +@brief creates interrupt in for other functions. +*/ +DebounceIn buttonP(p23); // create interrupt button + +/** +@brief class created for user component ship. +*code will access the components of this ship class to control user component on the screen +*/ +class Ship +{ +public: + int xs; /**< ships integer x coordinate */ + int ys; /**< ships integer y coordinate */ + + /** + *set the values for the ship, used for drawing and moving etc + */ + void SetValues(int,int); + + /** + *function to draw ships shape + @param xs - ships integer x coordinate + @param ys - ships integer y coordinate + */ + void shape() { + lcd.drawLine(xs,ys,xs-5,ys+6,1); + lcd.drawLine(xs,ys,xs+5,ys+6,1); + lcd.drawLine(xs-5,ys+6,xs+5,ys+6,1); + lcd.setPixel(xs-3,ys+7); + lcd.setPixel(xs+3,ys+7); + // lcd.refresh(); + } + + /** + *function for moving the ship to the left + */ + void ShipLeft() { + xs = xs-1; + clearShapeL(); + shape(); + } + + /** + *function for moving the ship to the right + */ + void ShipRight() { + xs = xs+1; + clearShapeR(); + shape(); + } + + /** + *function for clearing the previous shape when moved to the left + */ + void clearShapeL() { + lcd.drawLine(xs+1,ys,xs-4,ys+6,0); + lcd.drawLine(xs+1,ys,xs+6,ys+6,0); + lcd.drawLine(xs-4,ys+6,xs+6,ys+6,0); + lcd.clearPixel(xs-2,ys+7); + lcd.clearPixel(xs+4,ys+7); + } + + /** + *function for clearing the previous shape when moved to the right + */ + void clearShapeR() { + lcd.drawLine(xs-1,ys,xs-6,ys+6,0); + lcd.drawLine(xs-1,ys,xs+4,ys+6,0); + lcd.drawLine(xs-6,ys+6,xs+4,ys+6,0); + lcd.clearPixel(xs-4,ys+7); + lcd.clearPixel(xs+2,ys+7); + } +} ship; + +/** function which sets the ships xs and ys coordinates, used in the main program as an initialisation +@param X - integer value to set xs +@param Y - integer value to set ys +*/ +void Ship::SetValues(int X,int Y) +{ + xs = X; + ys = Y; +} + +/** +@brief class created for bullet fired. +*code will access the components of this Bullet class to control the bullet +*/ +class Bullet +{ +public: + int x; /**< bullets integer x coordinate */ + int y; /**< bullets integer y coordinate */ + + /** + *set the values for the bullet, used when first fired for other commands to work off + */ + void SetValues(int,int); + + /** + *function to draw bullets shape + @param x - bullets integer x coordinate + @param y - bullets integer y coordinate + */ + void createBullet() { + lcd.setPixel(x,y); + lcd.setPixel(x+1,y); + lcd.setPixel(x-1,y); + lcd.setPixel(x,y-1); + lcd.refresh(); + } + + /** + *function to erase previous bullets when moving forward + *always followed by create bullet so no need for lcd refresh when drawing + */ + void erasePrevBullet() { + lcd.clearPixel(x,y+1); + lcd.clearPixel(x+1,y+1); + lcd.clearPixel(x-1,y+1); + } + + /** + *bool function, which determines whether the bullet has collided with any enemies returns true or false + */ + bool collision() { + if(lcd.getPixel(x+1,y-1)||lcd.getPixel(x-1,y-1)||lcd.getPixel(x,y-2)) { + clearBullet(); + return true; + } else {return false;} + } + /** + *bool function, which determines whether the bullet has reached the edge of the screen returns true or false + */ + bool offScreen() { + if(y<4) { + clearBullet(); + return true; + } else { + return false; + } + } + /** + *function to clear bullets current position + */ + void clearBullet() { + lcd.clearPixel(x,y); + lcd.clearPixel(x+1,y); + lcd.clearPixel(x-1,y); + lcd.clearPixel(x,y-1); + lcd.refresh(); + } +} bullet; + +/** function which sets the bullets x and y coordinates, used in the shooting program to initialise where the bullet was fired +@param Xb - integer value to set x +@param Yb - integer value to set y +*/ +void Bullet::SetValues(int Xb,int Yb) +{ + x = Xb; + y = Yb; +} + +/** +@brief class created for Asteroids. +*code will access the components of this Asteroid class to control the Asteroid +*/ +class Asteroid +{ +public: + int xa; /**< asteroids integer x coordinate */ + int ya; /**< asteroids integer y coordinate */ + int nscore; /**< an integer value score that increments every time the player has destroyed an asteroid */ + + /** + *set the x value for the asteroid, used at intervals called by a ticker + */ + void SetAsteroidValue(int,int); + + /** + *function to draw and asteroid according to given coordinates + */ + void createAsteroid() { + lcd.drawCircle(xa,ya,3,0,1); + lcd.refresh(); + } + + /** + *function to clear previous asteroid when moving forward(forward being from the aseroids point of view, looking at + *the screen would be downwards) + */ + void erasePrevAsteroid() { + lcd.drawCircle(xa,ya-1,3,0,0); + lcd.refresh(); + } + + /** + *function to eliminate asteroid, this will be called when a bullet has made a collision with the asteroid + */ + void destroyAsteroid() { + lcd.drawCircle(xa,ya,3,0,0); + nscore = nscore+1; + bullet.clearBullet(); + lcd.refresh(); + } + + /** + *boolean function which returns true or false, determining whether the asteroid has reached the bottom of the screen or not + */ + bool armageddon() { + if(ya+4 == 47) { + return true; + } else { + return false; + } + } +} asteroid; + +/** function which sets the asteroids x position (y posisition is set to top of the screen) +@param XA - integer value to set xa +@param YA - integer value to set ya +*/ +void Asteroid::SetAsteroidValue(int XA, int YA) +{ + xa = XA; + ya = YA; +} + +/** +*function prototype to caibrate the joystick and centre values +*/ +void calibrateJoystick(); + +/** +*function which when called upon will update the joystick position +*/ +void updateJoystick(); + +/** +*function which shows initial display and sleeps(low power sleep) untill interrupt made and game started +*/ +void startUpDisplay(); + +/** +*function for gameplay +*/ +void Game(); + +/** +*function which reads the position of the bullet on screen and reprints according to position also checking +*whether it has made contact with enemies or the end of the screen +*/ +void ReadBullet(); + +/** +*function which reads the position and state of the asteroid and refeshes accordingly +*/ +void ReadAsteroid(); + +/** +*function which shows end display with score, and sleeps(low power sleep) untill interrupt made and game re-started +*/ +void EndDisplay(); + +/** +*function which shows Pause Display and will restart when shoot button pressed , sleep() mode untill then +*/ +void PauseDisplay(); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri May 08 09:24:50 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/487b796308b0 \ No newline at end of file