Snake Project ELEC2645 John A. C. Richards 200869600

Dependencies:   N5110 SDFileSystem mbed

Revision:
0:3ea41570bc9f
diff -r 000000000000 -r 3ea41570bc9f main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu May 05 09:09:59 2016 +0000
@@ -0,0 +1,421 @@
+//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;
+}
\ No newline at end of file