Snake Project ELEC2645 John A. C. Richards 200869600
Dependencies: N5110 SDFileSystem mbed
main.cpp
- Committer:
- JAC__RICHARDS
- Date:
- 2016-05-05
- Revision:
- 0:3ea41570bc9f
File content as of revision 0:3ea41570bc9f:
//ELEC2645 project //John A. C. Richards, 200869600 #include "main.h" //Timer for LED to be on Timeout greenTimeout; bool nextFrameFlag = false; //initial setting for flag to change to next frame bool changeDirection = false; //initial setting for flag to change direction bool timerDone; //bool for timeout // timer to regularly read the joystick Ticker pollJoystick; // Serial for debug Serial serial(USBTX,USBRX); // create enumerated type (0,1,2,3 etc. for direction) // could be extended for diagonals etc. 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; // function prototypes void calibrateJoystick(); void updateJoystick(); //Start main program int main() { snake(); } void snake() { calibrateJoystick(); // get centred values of joystick pollJoystick.attach(&updateJoystick,1.0/10.0); // read joystick 10 times per second serial.baud(115200); // full-speed! serial.printf("High-Score\n"); FILE *fp; // this is our file pointer wait(1); //set score and high score to 0 int score = 0; int highScore = 0; //set high score as SD card value if one fp = fopen("/sd/highscore.txt", "r"); int stored_high_score = -1; // -1 to demonstrate it has changed after reading if (fp == NULL) { // if it can't open the file then print error message serial.printf("Error! Unable to open file!\n"); highScore = 0; } else { // opened file so can write fscanf(fp, "%d",&stored_high_score); // ensure data type matches - note address operator (&) serial.printf("Read %d from file.\n",stored_high_score); fclose(fp); // ensure you close the file after reading highScore = stored_high_score; } //start with mbed LEDs off green_led = 1; red_led = 1; //start up blank screen lcd.init(); lcd.clear(); lcd.setBrightness(1.0); //display splash screen lcd.printString("SNAKE",27,1); lcd.printString("By John A. C.",1,3); lcd.printString("Richards (JAC)",1,4); lcd.printString("200869600",1,5); //wait 5 seconds before moving on - using timeout screenDelay (5.0); //set tickers for refreshing the screen and changing direction Ticker refreshTicker; Ticker directionTicker; //while program is running while (1) { score = 0; bool gameOver = false; //start with game playing green_led = 0; //mbed LED green for game playing red_led = 1; //set initial snake parameters int playerX = 20; //snake start position x plane int playerY = 10; //snake start position y plane playerLength = 5; //snake start length int playerSize = 2; //snake width //For moving, add one to start and take one from end for (int i=0; i<maxPlayerSize; i++) { playerPositionsX[i] = -1; playerPositionsY[i] = -1; } //Player direction - start by moving right int directionX = 1; int directionY = 0; //set initial fruit location int random = std::rand(); int fruitPositionX = random % areaWidth; random = std::rand(); int fruitPositionY = random % areaHeight; //game refresh rate - set with ticker refreshTicker.attach(&nextFrame, 0.15); //while player is alive while (!gameOver) { //sleep to conserve resources until reached again sleep(); //set flag for refreshing the screen if (nextFrameFlag) { nextFrameFlag = false; // check joystick direction switch (joystick.direction) { case UP: //up if (!(directionY == -1)) { directionX = 0; directionY = 1; } break; case DOWN: //down if (!(directionY == 1)) { directionX = 0; directionY = -1; } break; case LEFT: //left if (!(directionX == 1)) { directionX = -1; directionY = 0; } break; case RIGHT: //right if (!(directionX == -1)) { directionX = 1; directionY = 0; } break; } //Move the player playerX += directionX; //add direction x to snake head to move in x plane playerY += directionY; //add direction y to snake head to move in y plane //Grow snake to starting length for (int i=playerLength-1; i>=0; i--) { playerPositionsX[i+1] = playerPositionsX[i]; playerPositionsY[i+1] = playerPositionsY[i]; } playerPositionsX[0] = playerX; //set head as start of snake - x plane playerPositionsY[0] = playerY; //set head as start of snake - y plane //check if player hit something if(checkCollision(playerX,playerY)) gameOver = true; //end game //check if player is about to hit something if (checkCollision(playerX+directionX,playerY+directionY)) { //check if obstacle within one space yellowLED = 1; //set yellow LED on if approaching obstacle } else if (checkCollision(playerX+directionX+directionX,playerY+directionY+directionY)) {//check if obstacle within two spaces yellowLED = 1; //set yellow LED on if approaching obstacle } else { yellowLED = 0; //set yellow LED off if not approaching obstacle } //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. if (playerX == fruitPositionX && playerY == fruitPositionY) { //increment score and update high score if necessary score++; if (score > highScore) { highScore = score; //write new high score to SD card fp = fopen("/sd/highScore.txt", "w"); if (fp == NULL) { // if it can't open the file then print error message serial.printf("Error! Unable to open file!\n"); } else { // opened file so can write serial.printf("Writing to file...."); fprintf(fp, "%d",score); // ensure data type matches serial.printf("Done.\n"); fclose(fp); // ensure you close the file after writing } } //make snake longer playerLength++; //Turn on green LED greenLED = 1; greenTimeout.attach(greenOff,1.0); //turn off green LED after one second //Move fruit to random location random = std::rand(); fruitPositionX = random % areaWidth; //random x location random = std::rand(); fruitPositionY = random % areaHeight; //random y location //Make sure space for fruit is in empty space for (int i=1; i<playerLength; i++) { if (fruitPositionX == playerPositionsX[i] && fruitPositionY == playerPositionsY[i]) { //check if fruit is in same position as any bit of snake random = std::rand(); fruitPositionX = random % areaWidth; //random x location random = std::rand(); fruitPositionY = random % areaHeight; //random y location } } } //start of rendering code lcd.clear(); //clear the screen //display score std::string scoreTag = "SCR:"; //string saying SCR for score char scoreStr[3]; //set 3 spaces for score value sprintf(scoreStr, "%d", score); //string with score value std::string result = scoreTag + scoreStr; // add two strings together lcd.printString(result.c_str(),0,0); //display score string //display high score std:: string highScoreTag = "HI:"; //string saying HI for high-score char highScoreStr[3]; //set 3 spaces for high-score value sprintf(highScoreStr, "%d", highScore); //string with high-score value std::string highResult = highScoreTag + highScoreStr; // add two strings together lcd.printString(highResult.c_str(),42,0); //display high-score string //Draw the walls lcd.drawRect(0,8,83,39,0); //left side, right side, top, bottom, no fill //Draw player for (int i=0; i<playerLength; i++) { int actualPlayerX = playerPositionsX[i] * playerSize + 1; int actualPlayerY = playerPositionsY[i] * playerSize + 9; lcd.drawRect(actualPlayerX, actualPlayerY, playerSize-1, playerSize-1, 1); //left side, right side, top, bottom, filled } //Draw the fruit int actualFruitX = fruitPositionX * playerSize + 1; int actualFruitY = fruitPositionY * playerSize + 9; lcd.drawRect(actualFruitX, actualFruitY, playerSize-1, playerSize-1, 1); //left side, right side, top, bottom, filled lcd.refresh(); //refresh the screen } } //disable tickers refreshTicker.detach(); directionTicker.detach(); //clear screen for game over screen lcd.clear(); //print game over texts lcd.printString("GAME OVER",15,1); //string saying game over std::string scoreTag = "SCORE:"; char scoreStr[3]; sprintf(scoreStr, "%d", score); std::string scoreResult = scoreTag + scoreStr; lcd.printString(scoreResult.c_str(),1,3); //string saying score and value std::string highScoreTag = "HIGH-SCORE:"; char highScoreStr[3]; sprintf(highScoreStr, "%d", highScore); std::string highScoreResult = highScoreTag + highScoreStr; lcd.printString(highScoreResult.c_str(),1,4); //string saying high-score and value //set mbed LEDs green_led = 1; red_led = 0; //red LED on for game over //refresh to display texts lcd.refresh(); //make sure game LEDs is off yellowLED = 0; greenLED = 0; //set buzzer volume to potentiometer value buzzer = volume; //Play little tune on buzzer buzzer.period(1.0/500.0); screenDelay(0.5); buzzer = volume; //check if volume has changed buzzer.period(1.0/400.0); screenDelay(0.5); buzzer = volume;//check if volume has changed buzzer.period(1.0/300.0); screenDelay(1.0); buzzer = 0; screenDelay(1.5); } } // read default positions of the joystick to calibrate later readings void calibrateJoystick() { // 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() { // read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred) joystick.x = xPot - joystick.x0; joystick.y = yPot - joystick.y0; // 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 printing printFlag = 1; } void timerTrigger() //function to set bool as true to be used again { timerDone = true; } void screenDelay(float seconds) // timeout function { Timeout timer; timerDone = false; timer.attach(&timerTrigger, seconds); while (!timerDone) sleep(); } void greenOff () //turn off LED after use { greenLED = 0; } bool checkCollision(int x,int y) //bool for collision checking { //check if hit walls if (x < 0 //x in same space as left wall || x == areaWidth //or in same space as right wall || y < 0 //or in same space as bottom wall || y == areaHeight) { // or in same space as top wall return true; //crashed } //check if hit self for (int i=1; i<playerLength; i++) { if (x == playerPositionsX[i] // if x head position is on snake body in x plane && y == playerPositionsY[i]) { //and y head position is on snake body in y plane return true; //crashed } } return false; //else not crashed } //Set flag for next frame void nextFrame() { nextFrameFlag = true; }