Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: N5110 SDFileSystem mbed
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 }
Generated on Thu Jul 14 2022 13:33:05 by
1.7.2