Fiifi Mills / Mbed 2 deprecated Snake

Dependencies:   N5110 PinDetect PowerControl mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "N5110.h"
00003 #include "PinDetect.h"
00004 #include "PowerControl/PowerControl.h"
00005 #include "PowerControl/EthernetPowerControl.h"
00006 #include <vector>
00007 #include <stdlib.h>     /* srand, rand */
00008 #include <time.h>
00009 
00010 /* Code for Snake game
00011 
00012 B.F. Mills
00013 
00014 April 12th 2015
00015 
00016 */
00017 
00018 // change this to alter tolerance of joystick direction
00019 #define DIRECTION_TOLERANCE 0.05
00020 
00021 //      vcc, sce, rst, dc, mosi, sck, backlight
00022 N5110 lcd(p7, p8, p9, p10, p11, p13, p26);
00023 
00024 // joystick connections
00025 AnalogIn yPot(p15);
00026 AnalogIn xPot(p16);
00027 DigitalIn button(p17);
00028 
00029 // leds
00030 BusOut myleds(LED1, LED2, LED3, LED4);
00031 
00032 // buttons
00033 PinDetect buttonA(p30);
00034 PinDetect buttonB(p29);
00035 
00036 // timer to regularly read the joystick
00037 Ticker pollJoystick;
00038 // Serial for debug
00039 Serial serial(USBTX,USBRX);
00040 
00041 // create enumerated type (0,1,2,3 etc. for direction)
00042 // could be extended for diagonals etc.
00043 enum DirectionName {
00044     UP,
00045     DOWN,
00046     LEFT,
00047     RIGHT,
00048     CENTRE,
00049     UNKNOWN
00050 };
00051 
00052 DirectionName currentDirection ;  // enum variable for current direction of snake's movement
00053 DirectionName previousDirection ;  // enum variable for previous direction of snake's movement
00054 
00055 // enumerated type for game menu screen
00056 enum GameMenu {
00057     STARTUP,
00058     SELECTSPEED,
00059     GAMEPLAY
00060 };
00061 
00062 GameMenu currentGameMenu ;  // create game menu variable
00063 
00064 // struct for Joystick
00065 typedef struct JoyStick Joystick;
00066 struct JoyStick {
00067     float x;    // current x value
00068     float x0;   // 'centred' x value
00069     float y;    // current y value
00070     float y0;   // 'centred' y value
00071     int button; // button state (assume pull-down used, so 1 = pressed, 0 = unpressed)
00072     DirectionName direction;  // current direction
00073 };
00074 // create struct variable
00075 Joystick joystick;
00076 
00077 // struct for a coordinate
00078 struct coordinate {
00079     int x; // x coordinate
00080     int y; // y coordinate
00081 };
00082 
00083 char buffer [14];  // buffer for printing score to screen
00084 
00085 // flags
00086 int printFlag = 0;
00087 int Aflag  = 0;          // flag for notification of A button interrupt
00088 int Bflag  = 0;           // flag for notification of B button interrupt
00089 int collisionFlag  = 0;      // flag for notification of self snake collision
00090 int borderFlag  = 0;         // flag for hitting border in insane mode
00091 
00092 // global variables
00093 int score = 0;              // score value
00094 bool gameOver ;              // boolean variable for game over
00095 int xCentre  = 4;            // x coordinate for centre of selection circle
00096 int yCentre  = 11;           // y coordinate for centre of selection circle
00097 float speed ;            // wait time for moveSnake function
00098 
00099 void pressedA()
00100 {
00101     Aflag  = 1;  // set flag when A button is pressed
00102 }
00103 
00104 void pressedB()
00105 {
00106     Bflag  = 1;  // set flag when B button is pressed
00107 }
00108 
00109 // function prototypes
00110 void calibrateJoystick();
00111 void updateJoystick();
00112 void moveSnake();
00113 void speedSelect();
00114 
00115 std::vector<coordinate> Snake;  // create a vector that stores coordinate structs
00116 
00117 int main()
00118 {
00119 
00120     calibrateJoystick();  // get centred values of joystick
00121     pollJoystick.attach(&updateJoystick,1.0/20.0);  // read joystick 20 times per second
00122 
00123     lcd.init();  // initialise display
00124     lcd.setBrightness(0.5);  // set brightness of backlight
00125 
00126     PHY_PowerDown();   // power down ethernet
00127 
00128     // set button modes to pull down
00129     buttonA.mode(PullDown);
00130     buttonB.mode(PullDown);
00131 
00132     buttonA.attach_asserted(&pressedA);  // call pressedA function when button is pressed
00133     buttonB.attach_asserted(&pressedB);  // call pressedB function when button is presed
00134 
00135     // set sample frequency for buttons (default = 20ms)
00136     buttonA.setSampleFrequency();
00137     buttonB.setSampleFrequency();
00138 
00139     currentGameMenu  = STARTUP;  // initialise game menu to be splash screen
00140     gameOver  = false; // initialise gameOver as false
00141 
00142 
00143     while (1) {  // infinite loop
00144 
00145         if (currentGameMenu  == STARTUP) { // start up screen
00146 
00147             // splash screen for startup
00148             lcd.printString("SNAKE",28,1);
00149             lcd.printString("PRESS A",21,5);
00150 
00151             // draw snake logo
00152             lcd.drawRect(26,27,5,5,0); // bottom rectangle of snake
00153             lcd.drawRect(26,22,5,5,0);  // the rectangle directly above
00154             lcd.drawRect(31,22,5,5,0);  // the rectangle one to the right
00155             lcd.drawRect(36,22,5,5,0);  // one to the right
00156             lcd.drawRect(41,22,5,5,0);  // one to the right
00157             lcd.drawRect(51,22,5,5,1);  // "food"
00158             lcd.refresh();
00159             
00160             Sleep();  // when flag is not set, go to sleep & wait for interrupt  
00161 
00162             if (Aflag ) { // if currentGameMenu is STARTUP and A is pressed,
00163                 Aflag  = 0;  // reset flag
00164                 lcd.clear();  // clear screen
00165                 currentGameMenu  = SELECTSPEED;  // segue to select speed menu
00166             }
00167             
00168         }
00169 
00170         if (currentGameMenu  == SELECTSPEED) {  // select speed menu
00171 
00172             // print menu options to screen
00173             lcd.printString("SLOW",10,1);
00174             lcd.printString("MEDIUM",10,3);
00175             lcd.printString("FAST",10,5);
00176             lcd.printString("INSANE",46,1);
00177 
00178             lcd.drawCircle(xCentre ,yCentre ,3,1);  // draw selection circle (starting on SLOW)
00179             lcd.refresh();
00180             speedSelect();
00181 
00182             if (Aflag ) {  // if currentGameMenu is SELECTSPEED and A is pressed,
00183                 Aflag  = 0;  // reset flag
00184                 lcd.clear();  // cleat screen
00185                 currentGameMenu  = GAMEPLAY;  // segue to gameplay
00186             }
00187 
00188             Sleep();  // when flag is not set, got to sleep & wait for interrupt
00189 
00190         }
00191 
00192         if (currentGameMenu  == GAMEPLAY) {  // gameplay
00193 
00194             if (gameOver  == false) {  // whilst game is not over
00195 
00196                 if (xCentre  + yCentre  == 15) {  // if the addition of the coordinates of the centre of the selection circle = 15 i.e when selecting SLOW
00197                     speed  = 0.20;  // set wait time for moveSnake
00198                 }
00199                 if (xCentre  + yCentre  == 31) {  // medium
00200                     speed  = 0.12;
00201                 }
00202                 if (xCentre  + yCentre  == 47) {  // fast
00203                     speed  = 0.04;
00204                 }
00205                 if (xCentre  + yCentre  == 53) {  // insane
00206                     speed  = 0.02;
00207 
00208                     for (int y=0; y<23 ; y++) {   // set upper border
00209                         lcd.setPixel(43,y);
00210                         lcd.refresh();
00211                     }
00212 
00213                     for (int y=25; y<47; y++) { // set lower border
00214                         lcd.setPixel(43,y);
00215                         lcd.refresh();
00216                     }
00217                 }
00218 
00219                 previousDirection  = RIGHT;  // initialise first direction to be right
00220 
00221                 // set of initial coordinates
00222                 coordinate cord0 = {45, 24};
00223                 coordinate cord1 = {46, 24};
00224                 coordinate cord2 = {47, 24};
00225                 coordinate cord3 = {48, 24};
00226 
00227                 // add these coordinates to the snake vector
00228                 Snake.push_back(cord0);
00229                 Snake.push_back(cord1);
00230                 Snake.push_back(cord2);
00231                 Snake.push_back(cord3);
00232 
00233                 // set these co-ordinate's pixels
00234                 for (int i=0; i<Snake.size(); i++) {
00235                     lcd.setPixel(Snake.at(i).x, Snake.at(i).y);
00236                     lcd.refresh();
00237                 }
00238 
00239                 moveSnake();
00240             }
00241 
00242             if (gameOver  == true) {  // if game is over
00243 
00244                 // display game over splash screen
00245                 lcd.printString("Game Over!",14,1);
00246                 lcd.printString("Press B",23,4);
00247                 int printScore = sprintf(buffer,"Score = %d",score*5);  // print formatted data to buffer
00248                 if (printScore <= 14) { // if string fits on display
00249                     lcd.printString(buffer,16,3);
00250                 }
00251                 Snake.clear();  // clear snake vector
00252 
00253                 while (1) {  // flash leds
00254                     myleds = 15;
00255                     wait(0.5);
00256                     myleds = 0;
00257                     wait(0.5);
00258                     if (Bflag ) // if B is pressed, break out of infinite loop
00259                         break;
00260                 }
00261 
00262                 if (Bflag ) {  // if B is pressed,
00263                     Bflag  = 0;  // reset flag
00264                     collisionFlag  = 0;  // reset collision flag
00265                     score = 0;  // reset score
00266                     myleds = 0;  // switch off leds
00267                     borderFlag  = 0;
00268                     gameOver  = false;  // reset gameOver to false
00269                     lcd.clear();  // clear the screen
00270                     currentGameMenu  = STARTUP;  // go back to startup screen
00271                 }
00272 
00273             }
00274         }
00275 
00276     }
00277 }
00278 
00279 // read default positions of the joystick to calibrate later readings
00280 void calibrateJoystick()
00281 {
00282     button.mode(PullDown);
00283     // must not move during calibration
00284     joystick.x0 = xPot;  // initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
00285     joystick.y0 = yPot;
00286 }
00287 
00288 void updateJoystick()
00289 {
00290     // read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
00291     joystick.x = xPot - joystick.x0;
00292     joystick.y = yPot - joystick.y0;
00293     // read button state
00294     joystick.button = button;
00295 
00296     // calculate direction depending on x,y values
00297     // tolerance allows a little lee-way in case joystick not exactly in the stated direction
00298     if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
00299         joystick.direction = CENTRE;
00300     } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
00301         joystick.direction =  RIGHT;
00302     } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
00303         joystick.direction =  LEFT;
00304     } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
00305         joystick.direction =  DOWN;
00306     } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
00307         joystick.direction =  UP;
00308     } else {
00309         joystick.direction = UNKNOWN;
00310     }
00311 
00312     // set flag for printing
00313     printFlag = 1;
00314 }
00315 
00316 void moveSnake()
00317 {
00318     srand(time(NULL));  // use time as seed for rand
00319 
00320     int foodX = rand()%82+1;  // random x coordinate between 1-82
00321     int foodY = rand()%46+1;  // random y coordinate between 1-46
00322 
00323     // draw border
00324     lcd.drawRect(0,0,83,47,0);  // x-origin, y-origin, width, height, fill
00325     lcd.refresh();
00326 
00327     if (!lcd.getPixel(foodX,foodY))  // if pixel is not already set
00328         lcd.setPixel(foodX,foodY);  // set pixel of this coordinate (used for food)
00329         lcd.refresh();
00330 
00331     while (1) {  // infinite loop
00332 
00333         if (joystick.direction == CENTRE) {  // if the joystick is in the centre
00334             currentDirection  = previousDirection ;  // current direction is the previous direction of movement
00335         }
00336         if (joystick.direction == UNKNOWN) {  // if the joystick's direction is unknown
00337             currentDirection  = previousDirection ;  // current direction is the previous direction
00338         }
00339 
00340         // if joystick direction is left, right, up or down, set the current direction to be the joystick's direction
00341         if (joystick.direction == LEFT) {
00342             currentDirection  = joystick.direction;
00343         }
00344         if (joystick.direction == RIGHT) {
00345             currentDirection  = joystick.direction;
00346         }
00347         if (joystick.direction == UP) {
00348             currentDirection  = joystick.direction;
00349         }
00350         if (joystick.direction == DOWN) {
00351             currentDirection  = joystick.direction;
00352         }
00353 
00354         lcd.clearPixel(Snake.front().x, Snake.front().y);  // clear the tail pixel of snake
00355 
00356         for (int i=0; i<Snake.size()-1; i++) {  // shift along each element in the vector so that..
00357             Snake.at(i) = Snake.at(i+1);  // value of element Snake[0] = Snake[1], Snake[1] = Snake[2] etc.
00358         }
00359 
00360         switch (currentDirection ) {  // check the current direction
00361 
00362             case UP: // if up
00363                 if (previousDirection  == DOWN) {  // check if the previous direction was opposite to the current direction
00364                     currentDirection  = DOWN;  // if so, move in the previous direction
00365                     Snake.back().y++; // increment appropiate coordinate value
00366                 } else { // if the previous direction wasn't opposite to the current direction,
00367                     previousDirection  = UP;  // set the previous direction
00368                     Snake.back().y--;  // increment appropiate coordinate value
00369                 }
00370                 break;
00371 
00372             case DOWN:
00373                 if (previousDirection  == UP) {
00374                     currentDirection  = UP;
00375                     Snake.back().y--;
00376                 } else {
00377                     previousDirection  = DOWN;
00378                     Snake.back().y++;
00379                 }
00380                 break;
00381 
00382             case LEFT:
00383                 if (previousDirection  == RIGHT) {
00384                     currentDirection  = RIGHT;
00385                     Snake.back().x++;
00386                 } else {
00387                     previousDirection  = LEFT;
00388                     Snake.back().x--;
00389                 }
00390                 break;
00391 
00392             case RIGHT:
00393                 if (previousDirection  == LEFT) {
00394                     currentDirection  = LEFT;
00395                     Snake.back().x--;
00396                 } else {
00397                     previousDirection  = RIGHT;
00398                     Snake.back().x++;
00399                 }
00400                 break;
00401 
00402             default:
00403                 break;
00404         }
00405 
00406         if ((Snake.back().x == foodX) && (Snake.back().y == foodY)) {  // if the snake head hits the food
00407 
00408             switch (currentDirection ) {  // check the current direction
00409 
00410                 case UP:
00411                     Snake.push_back(Snake.back());  // add an element, which is equal to the penultimate element, to the end of the vector
00412                     Snake.back().y--;  // increment the appropiate coordinate of this new element for the direction of movement
00413                     foodX = rand()%82 + 1;  // x coordinate of food is now a new random number between 1-83
00414                     foodY = rand()%46 + 1;  // y coordinate of food is now a new random number between 1-47
00415 
00416                     if (!lcd.getPixel(foodX,foodY)) {
00417                         lcd.setPixel(foodX,foodY);
00418                         lcd.refresh();
00419                     }
00420 
00421                     score++;  // increment score value
00422 
00423                     // flash led
00424                     myleds = 1;
00425                     wait(0.2);
00426                     myleds = 0;
00427                     break;
00428 
00429                 case DOWN:
00430                     Snake.push_back(Snake.back());
00431                     Snake.back().y++;
00432                     foodX = rand()%82 + 1;
00433                     foodY = rand()%46 + 1;
00434 
00435                     if (!lcd.getPixel(foodX,foodY)) {
00436                         lcd.setPixel(foodX,foodY);
00437                         lcd.refresh();
00438                     }
00439                     score++;
00440 
00441                     myleds = 1;
00442                     wait(0.2);
00443                     myleds = 0;
00444                     break;
00445 
00446                 case LEFT:
00447                     Snake.push_back(Snake.back());
00448                     Snake.back().x--;
00449                     foodX = rand()%82 + 1;
00450                     foodY = rand()%46 + 1;
00451 
00452                     if (!lcd.getPixel(foodX,foodY)) {
00453                         lcd.setPixel(foodX,foodY);
00454                         lcd.refresh();
00455                     }
00456                     score++;
00457 
00458                     myleds = 1;
00459                     wait(0.2);
00460                     myleds = 0;
00461                     break;
00462 
00463                 case RIGHT:
00464                     Snake.push_back(Snake.back());
00465                     Snake.back().x++;
00466                     foodX = rand()%82 + 1;
00467                     foodY = rand()%46 + 1;
00468 
00469                     if (!lcd.getPixel(foodX,foodY)) {
00470                         lcd.setPixel(foodX,foodY);
00471                         lcd.refresh();
00472                     }
00473                     score++;
00474 
00475                     myleds = 1;
00476                     wait(0.2);
00477                     myleds = 0;
00478                     break;
00479 
00480                 default:
00481                     break;
00482             }
00483 
00484         }
00485 
00486 
00487         for (int i = 0; i < Snake.size()-1; i++) {  // iterate through all elements in the snake vector
00488             if ((Snake.back().x == Snake.at(i).x) && (Snake.back().y == Snake.at(i).y)) {  // if snake head touches any other part of the snake
00489                 collisionFlag  = 1;  // set colision flag
00490                 gameOver  = true; // set gameOver to true
00491             }
00492 
00493         }
00494 
00495         if (collisionFlag ) break;  // if collision flag is set, break out of infinite loop
00496 
00497         if (Snake.back().x > 82) {  // if snakeHead's x coordinate is 83 or larger (i.e touching the right hand side border)
00498             gameOver  = true;  // game over is true
00499             break;  // break out of infinite loop
00500         }
00501 
00502         if (Snake.back().x < 1) {  // touching left hand side border
00503             gameOver  = true;
00504             break;
00505         }
00506 
00507         if (Snake.back().y > 46) {  // touching top border
00508             gameOver  = true;
00509             break;
00510         }
00511 
00512         if (Snake.back().y < 1) {  // touching bottom border
00513             gameOver  = true;
00514             break;
00515         }
00516 
00517         if (xCentre  + yCentre  == 53) {  // insane
00518 
00519             if ((Snake.back().x == 43) && (Snake.back().y < 23)) {  // if snake touches upper border
00520                 gameOver  = true;  // game over is true
00521                 borderFlag  = 1;  // set border flag
00522             }
00523 
00524             if ((Snake.back().x == 43) && (Snake.back().y > 24)) {  // if snake touches lower border
00525                 gameOver  = true;  // game over is true
00526                 borderFlag  = 1;  // set border flag
00527             }
00528         }
00529 
00530         if (borderFlag ) break;  // if border flag is set, break out of infinite loop
00531 
00532         lcd.setPixel(Snake.back().x, Snake.back().y);  // set new snakeHead's pixel
00533         lcd.refresh();
00534         wait(speed );
00535 
00536     }
00537 }
00538 
00539 void speedSelect()
00540 {
00541     if (joystick.direction == DOWN) {  // if the joystick is moved down
00542 
00543         if (xCentre  == 4 && yCentre  == 11) {  // i.e. when the selection circle is on SLOW
00544             lcd.clear(); // clear the screen
00545 
00546             // print options
00547             lcd.printString("SLOW",10,1);
00548             lcd.printString("MEDIUM",10,3);
00549             lcd.printString("FAST",10,5);
00550             lcd.printString("INSANE",46,1);
00551 
00552             yCentre  = 27;  // set new y value for centre of selection circle
00553             lcd.drawCircle(xCentre ,yCentre ,3,1);  // draw new selection circle
00554             lcd.refresh();
00555             wait(0.3);
00556         }
00557 
00558         else if (xCentre  == 4 && yCentre  == 27) {  // medium
00559             lcd.clear();
00560             lcd.printString("SLOW",10,1);
00561             lcd.printString("MEDIUM",10,3);
00562             lcd.printString("FAST",10,5);
00563             lcd.printString("INSANE!",46,1);
00564             yCentre  = 43;
00565             lcd.drawCircle(xCentre ,yCentre ,3,1);
00566             lcd.refresh();
00567             wait(0.3);
00568         }
00569 
00570         else if (xCentre  == 4 && yCentre  == 43) {  // fast
00571             lcd.clear();
00572             lcd.printString("SLOW",10,1);
00573             lcd.printString("MEDIUM",10,3);
00574             lcd.printString("FAST",10,5);
00575             lcd.printString("INSANE",46,1);
00576             xCentre  = 42;
00577             yCentre  = 11;
00578             lcd.drawCircle(xCentre ,yCentre ,3,1);
00579             lcd.refresh();
00580             wait(0.3);
00581         }
00582     }
00583 
00584     if (joystick.direction == UP) {
00585 
00586         if (xCentre  == 42 && yCentre  == 11) {  // insane
00587             lcd.clear();
00588             lcd.printString("SLOW",10,1);
00589             lcd.printString("MEDIUM",10,3);
00590             lcd.printString("FAST",10,5);
00591             lcd.printString("INSANE",46,1);
00592             xCentre  = 4;
00593             yCentre  = 43;
00594             lcd.drawCircle(xCentre ,yCentre ,3,1);
00595             lcd.refresh();
00596             wait(0.3);
00597         }
00598 
00599         else if (xCentre  == 4 && yCentre  == 43) {  // fast
00600             lcd.clear();
00601             lcd.printString("SLOW",10,1);
00602             lcd.printString("MEDIUM",10,3);
00603             lcd.printString("FAST",10,5);
00604             lcd.printString("INSANE!",46,1);
00605             yCentre  = 27;
00606             lcd.drawCircle(xCentre ,yCentre ,3,1);
00607             lcd.refresh();
00608             wait(0.3);
00609         }
00610 
00611         else if (xCentre  == 4 && yCentre  == 27) {  // medium
00612             lcd.clear();
00613             lcd.printString("SLOW",10,1);
00614             lcd.printString("MEDIUM",10,3);
00615             lcd.printString("FAST",10,5);
00616             lcd.printString("INSANE",46,1);
00617             yCentre  = 11;
00618             lcd.drawCircle(xCentre ,yCentre ,3,1);
00619             lcd.refresh();
00620             wait(0.3);
00621         }
00622     }
00623 
00624 
00625 
00626 
00627 }