ELEC2645 (2015/16) / Mbed 2 deprecated ELEC2645FinalProject

Dependencies:   N5110 SDFileSystem mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //ELEC2645 project
00002 //John A. C. Richards, 200869600
00003 
00004 
00005 #include "main.h"
00006 
00007 //Timer for LED to be on
00008 Timeout greenTimeout;
00009 
00010 bool nextFrameFlag = false; //initial setting for flag to change to next frame
00011 bool changeDirection = false; //initial setting for flag to change direction
00012 bool timerDone; //bool for timeout
00013 
00014 // timer to regularly read the joystick
00015 Ticker pollJoystick;
00016 // Serial for debug
00017 Serial serial(USBTX,USBRX);
00018 
00019 // create enumerated type (0,1,2,3 etc. for direction)
00020 // could be extended for diagonals etc.
00021 enum DirectionName {
00022     UP,
00023     DOWN,
00024     LEFT,
00025     RIGHT,
00026     CENTRE,
00027     UNKNOWN
00028 };
00029 
00030 // struct for Joystick
00031 typedef struct JoyStick Joystick;
00032 struct JoyStick {
00033     float x;    // current x value
00034     float x0;   // 'centred' x value
00035     float y;    // current y value
00036     float y0;   // 'centred' y value
00037     int button; // button state (assume pull-down used, so 1 = pressed, 0 = unpressed)
00038     DirectionName direction;  // current direction
00039 };
00040 // create struct variable
00041 Joystick joystick;
00042 
00043 int printFlag = 0;
00044 
00045 // function prototypes
00046 void calibrateJoystick();
00047 void updateJoystick();
00048 
00049 //Start main program
00050 int main()
00051 {
00052     snake();
00053 
00054 }
00055 
00056 void snake()
00057 {
00058     calibrateJoystick();  // get centred values of joystick
00059     pollJoystick.attach(&updateJoystick,1.0/10.0);  // read joystick 10 times per second
00060 
00061     serial.baud(115200);  // full-speed!
00062     serial.printf("High-Score\n");
00063     FILE *fp; // this is our file pointer
00064     wait(1);
00065 
00066     //set score and high score to 0
00067     int score = 0;
00068     int highScore = 0;
00069 
00070     //set high score as SD card value if one
00071     fp = fopen("/sd/highscore.txt", "r");
00072     int stored_high_score = -1;  // -1 to demonstrate it has changed after reading
00073 
00074     if (fp == NULL) {  // if it can't open the file then print error message
00075         serial.printf("Error! Unable to open file!\n");
00076         highScore = 0;
00077     } else {  // opened file so can write
00078         fscanf(fp, "%d",&stored_high_score); // ensure data type matches - note address operator (&)
00079         serial.printf("Read %d from file.\n",stored_high_score);
00080         fclose(fp);  // ensure you close the file after reading
00081         highScore = stored_high_score;
00082     }
00083 
00084     //start with mbed LEDs off
00085     green_led = 1;
00086     red_led = 1;
00087 
00088     //start up blank screen
00089     lcd.init();
00090     lcd.clear();
00091     lcd.setBrightness(1.0);
00092 
00093     //display splash screen
00094     lcd.printString("SNAKE",27,1);
00095     lcd.printString("By John A. C.",1,3);
00096     lcd.printString("Richards (JAC)",1,4);
00097     lcd.printString("200869600",1,5);
00098 
00099     //wait 5 seconds before moving on - using timeout
00100     screenDelay (5.0);
00101 
00102     //set tickers for refreshing the screen and changing direction
00103     Ticker refreshTicker;
00104     Ticker directionTicker;
00105 
00106     //while program is running
00107     while (1) {
00108         score = 0;
00109         bool gameOver = false; //start with game playing
00110 
00111         green_led = 0; //mbed LED green for game playing
00112         red_led = 1;
00113 
00114         //set initial snake parameters
00115         int playerX = 20; //snake start position x plane
00116         int playerY = 10; //snake start position y plane
00117         playerLength  = 5; //snake start length
00118         int playerSize = 2; //snake width
00119 
00120         //For moving, add one to start and take one from end
00121         for (int i=0; i<maxPlayerSize; i++) {
00122             playerPositionsX [i] = -1;
00123             playerPositionsY [i] = -1;
00124         }
00125 
00126         //Player direction - start by moving right
00127         int directionX = 1;
00128         int directionY = 0;
00129 
00130         //set initial fruit location
00131         int random = std::rand();
00132         int fruitPositionX = random % areaWidth ;
00133         random = std::rand();
00134         int fruitPositionY = random % areaHeight ;
00135 
00136         //game refresh rate - set with ticker
00137         refreshTicker.attach(&nextFrame, 0.15);
00138 
00139         //while player is alive
00140         while (!gameOver) {
00141 
00142             //sleep to conserve resources until reached again
00143             sleep();
00144 
00145             //set flag for refreshing the screen
00146             if (nextFrameFlag) {
00147                 nextFrameFlag = false;
00148 
00149 
00150                 // check joystick direction
00151                 switch (joystick.direction) {
00152                     case UP: //up
00153                         if (!(directionY == -1)) {
00154                             directionX = 0;
00155                             directionY = 1;
00156                         }
00157                         break;
00158                     case DOWN: //down
00159                         if (!(directionY == 1)) {
00160                             directionX = 0;
00161                             directionY = -1;
00162                         }
00163                         break;
00164                     case LEFT: //left
00165                         if (!(directionX == 1)) {
00166                             directionX = -1;
00167                             directionY = 0;
00168                         }
00169                         break;
00170                     case RIGHT: //right
00171                         if (!(directionX == -1)) {
00172                             directionX = 1;
00173                             directionY = 0;
00174                         }
00175                         break;
00176              
00177             }
00178 
00179             //Move the player
00180             playerX += directionX; //add direction x to snake head to move in x plane
00181             playerY += directionY; //add direction y to snake head to move in y plane
00182 
00183 
00184 
00185             //Grow snake to starting length
00186             for (int i=playerLength -1; i>=0; i--) {
00187                 playerPositionsX [i+1] = playerPositionsX [i];
00188                 playerPositionsY [i+1] = playerPositionsY [i];
00189             }
00190             playerPositionsX [0] = playerX; //set head as start of snake - x plane
00191             playerPositionsY [0] = playerY; //set head as start of snake - y plane
00192 
00193             //check if player hit something
00194             if(checkCollision(playerX,playerY))
00195                 gameOver = true; //end game
00196 
00197             //check if player is about to hit something
00198             if (checkCollision(playerX+directionX,playerY+directionY)) { //check if obstacle within one space
00199                 yellowLED = 1; //set yellow LED on if approaching obstacle
00200             } else if
00201             (checkCollision(playerX+directionX+directionX,playerY+directionY+directionY)) {//check if obstacle within two spaces
00202                 yellowLED = 1; //set yellow LED on if approaching obstacle
00203             } else {
00204                 yellowLED = 0; //set yellow LED off if not approaching obstacle
00205 
00206             }
00207             //If the player is in the same place as the fruit, then move it to another random position, increase the snake length, and increment score.
00208             if (playerX == fruitPositionX
00209                     && playerY == fruitPositionY) {
00210 
00211                 //increment score and update high score if necessary
00212                 score++;
00213                 if (score > highScore) {
00214                     highScore = score;
00215 
00216                     //write new high score to SD card
00217                     fp = fopen("/sd/highScore.txt", "w");
00218 
00219                     if (fp == NULL) {  // if it can't open the file then print error message
00220                         serial.printf("Error! Unable to open file!\n");
00221                     } else {  // opened file so can write
00222                         serial.printf("Writing to file....");
00223                         fprintf(fp, "%d",score); // ensure data type matches
00224                         serial.printf("Done.\n");
00225                         fclose(fp);  // ensure you close the file after writing
00226                     }
00227                 }
00228 
00229                 //make snake longer
00230                 playerLength ++;
00231 
00232                 //Turn on green LED
00233                 greenLED = 1;
00234                 greenTimeout.attach(greenOff,1.0); //turn off green LED after one second
00235 
00236                 //Move fruit to random location
00237                 random = std::rand();
00238                 fruitPositionX = random % areaWidth ; //random x location
00239                 random = std::rand();
00240                 fruitPositionY = random % areaHeight ; //random y location
00241 
00242                 //Make sure space for fruit is in empty space
00243                 for (int i=1; i<playerLength ; i++) {
00244                     if (fruitPositionX == playerPositionsX [i]
00245                             && fruitPositionY == playerPositionsY [i]) { //check if fruit is in same position as any bit of snake
00246                         random = std::rand();
00247                         fruitPositionX = random % areaWidth ; //random x location
00248                         random = std::rand();
00249                         fruitPositionY = random % areaHeight ; //random y location
00250                     }
00251                 }
00252             }
00253 
00254             //start of rendering code
00255             lcd.clear(); //clear the  screen
00256 
00257             //display score
00258             std::string scoreTag = "SCR:"; //string saying SCR for score
00259             char scoreStr[3]; //set 3 spaces for score value
00260             sprintf(scoreStr, "%d", score); //string with score value
00261             std::string result = scoreTag + scoreStr; // add two strings together
00262 
00263             lcd.printString(result.c_str(),0,0); //display score string
00264 
00265             //display high score
00266             std:: string highScoreTag = "HI:"; //string saying HI for high-score
00267             char highScoreStr[3]; //set 3 spaces for high-score value
00268             sprintf(highScoreStr, "%d", highScore); //string with high-score value
00269             std::string highResult = highScoreTag + highScoreStr; // add two strings together
00270 
00271             lcd.printString(highResult.c_str(),42,0); //display high-score string
00272 
00273             //Draw the walls
00274             lcd.drawRect(0,8,83,39,0);    //left side, right side, top, bottom, no fill
00275 
00276             //Draw player
00277             for (int i=0; i<playerLength ; i++) {
00278                 int actualPlayerX = playerPositionsX [i] * playerSize + 1;
00279                 int actualPlayerY = playerPositionsY [i] * playerSize + 9;
00280                 lcd.drawRect(actualPlayerX, actualPlayerY, playerSize-1, playerSize-1, 1); //left side, right side, top, bottom, filled
00281             }
00282 
00283             //Draw the fruit
00284             int actualFruitX = fruitPositionX * playerSize + 1;
00285             int actualFruitY = fruitPositionY * playerSize + 9;
00286             lcd.drawRect(actualFruitX, actualFruitY, playerSize-1, playerSize-1, 1); //left side, right side, top, bottom, filled
00287 
00288             lcd.refresh(); //refresh the screen
00289         }
00290 
00291     }
00292     //disable tickers
00293     refreshTicker.detach();
00294     directionTicker.detach();
00295 
00296     //clear screen for game over screen
00297     lcd.clear();
00298 
00299     //print game over texts
00300     lcd.printString("GAME OVER",15,1); //string saying game over
00301 
00302     std::string scoreTag = "SCORE:";
00303     char scoreStr[3];
00304     sprintf(scoreStr, "%d", score);
00305     std::string scoreResult = scoreTag + scoreStr;
00306     lcd.printString(scoreResult.c_str(),1,3); //string saying score and value
00307 
00308     std::string highScoreTag = "HIGH-SCORE:";
00309     char highScoreStr[3];
00310     sprintf(highScoreStr, "%d", highScore);
00311     std::string highScoreResult = highScoreTag + highScoreStr;
00312     lcd.printString(highScoreResult.c_str(),1,4); //string saying high-score and value
00313 
00314     //set mbed LEDs
00315     green_led = 1;
00316     red_led = 0; //red LED on for game over
00317 
00318     //refresh to display texts
00319     lcd.refresh();
00320 
00321     //make sure game LEDs is off
00322     yellowLED = 0;
00323     greenLED = 0;
00324 
00325     //set buzzer volume to potentiometer value
00326     buzzer = volume;
00327 
00328     //Play little tune on buzzer
00329     buzzer.period(1.0/500.0);
00330     screenDelay(0.5);
00331     buzzer = volume; //check if volume has changed
00332     buzzer.period(1.0/400.0);
00333     screenDelay(0.5);
00334     buzzer = volume;//check if volume has changed
00335     buzzer.period(1.0/300.0);
00336     screenDelay(1.0);
00337     buzzer = 0;
00338     screenDelay(1.5);
00339 
00340 }
00341 }
00342 
00343 // read default positions of the joystick to calibrate later readings
00344 void calibrateJoystick()
00345 {
00346 
00347     // must not move during calibration
00348     joystick.x0 = xPot;  // initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
00349     joystick.y0 = yPot;
00350 }
00351 void updateJoystick()
00352 {
00353     // read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
00354     joystick.x = xPot - joystick.x0;
00355     joystick.y = yPot - joystick.y0;
00356 
00357 
00358     // calculate direction depending on x,y values
00359     // tolerance allows a little lee-way in case joystick not exactly in the stated direction
00360     if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
00361         joystick.direction = CENTRE;
00362     } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
00363         joystick.direction = UP;
00364     } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
00365         joystick.direction = DOWN;
00366     } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
00367         joystick.direction = RIGHT;
00368     } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
00369         joystick.direction = LEFT;
00370     } else {
00371         joystick.direction = UNKNOWN;
00372     }
00373     // set flag for printing
00374     printFlag = 1;
00375 }
00376 
00377 void timerTrigger() //function to set bool as true to be used again
00378 {
00379     timerDone = true;
00380 }
00381 
00382 void screenDelay(float seconds) // timeout function
00383 {
00384 
00385     Timeout timer;
00386     timerDone = false;
00387     timer.attach(&timerTrigger, seconds);
00388     while (!timerDone)
00389         sleep();
00390 }
00391 
00392 void greenOff () //turn off LED after use
00393 {
00394     greenLED = 0;
00395 }
00396 
00397 bool checkCollision(int x,int y) //bool for collision checking
00398 {
00399     //check if hit walls
00400     if (x < 0 //x in same space as left wall
00401             || x == areaWidth  //or in same space as right wall
00402             || y < 0 //or in same space as bottom wall
00403             || y == areaHeight ) { // or in same space as top wall
00404         return true; //crashed
00405     }
00406 //check if hit self
00407     for (int i=1; i<playerLength ; i++) {
00408         if (x == playerPositionsX [i] // if x head position is on snake body in x plane
00409                 && y == playerPositionsY [i]) { //and y head position is on snake body in y plane
00410             return true; //crashed
00411         }
00412 
00413     }
00414     return false; //else not crashed
00415 }
00416 
00417 //Set flag for next frame
00418 void nextFrame()
00419 {
00420     nextFrameFlag = true;
00421 }