Snake Project ELEC2645 John A. C. Richards 200869600

Dependencies:   N5110 SDFileSystem mbed

Files at this revision

API Documentation at this revision

Comitter:
JAC__RICHARDS
Date:
Thu May 05 09:09:59 2016 +0000
Commit message:
Finished Project

Changed in this revision

N5110.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
main.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/N5110.lib	Thu May 05 09:09:59 2016 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/JAC__RICHARDS/code/N5110/#b921d8c99714
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Thu May 05 09:09:59 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/mbed_official/code/SDFileSystem/#7b35d1709458
--- /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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.h	Thu May 05 09:09:59 2016 +0000
@@ -0,0 +1,159 @@
+/**
+@file main.h
+@brief Header file containing functions prototypes, defines and global variables.
+@author John A. C. Richards
+@date   April 20156
+*/
+ 
+#ifndef MAIN_H
+#define MAIN_H
+
+#include "mbed.h"
+#include "N5110.h" 
+#include "string" 
+#include "SDFileSystem.h"
+
+#define DIRECTION_TOLERANCE 0.05f 
+#define maxPlayerSize 1000 
+
+/**  
+@namespace red_led
+@brief GPIO output for game-over LED
+*/
+DigitalOut red_led(LED_RED);
+
+/**  
+@namespace green_led
+@brief GPIO output for game-playing LED
+*/
+DigitalOut green_led(LED_GREEN);
+
+/**  
+@namespace N5110_lcd 
+@brief GPIO output for Nokia screen
+*/
+N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3);
+
+/**  
+@namespace yellowLED
+@brief GPIO output for collision warning
+*/
+DigitalOut yellowLED(PTA2);
+
+/**  
+@namespace greenLED
+@brief GPIO output for eating food
+*/
+DigitalOut greenLED(PTC2);
+
+/**  
+@namespace xPot
+@brief GPIO output for joystick in x plane
+*/
+AnalogIn xPot(PTB2);
+
+/**  
+@namespace yPot
+@brief GPIO output for joystick in y plane
+*/
+AnalogIn yPot(PTB3);
+
+/**  
+@namespace buzzer
+@brief GPIO output for buzzer
+*/
+PwmOut buzzer(PTA1);
+
+/**  
+@namespace volume
+@brief GPIO output for potentiometer
+*/
+AnalogIn volume(PTB10);
+
+
+/**  
+@namespace sd
+@brief GPIO output for SDcard
+*/
+SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS
+
+
+
+volatile int playerLength; /*!<length of player*/
+
+volatile int playerPositionsX[maxPlayerSize]; /*!<max player size x*/
+volatile int playerPositionsY[maxPlayerSize]; /*!<max player size y*/
+
+volatile int areaWidth = 41; /*!<width of game map*/
+volatile int areaHeight = 19; /*!<height of game map*/
+
+/**
+@brief Sets flag for bringing the next frame
+*/
+void nextFrame(); //go to next frame function
+
+/**
+@brief Sets the bool timerDone as true 
+*/
+void timerTrigger(); //function to set bool as true to be used again
+
+
+/**
+@brief Timeout which keeps the program at one point for a while
+@param seconds Time delayed, in seconds
+*/
+void screenDelay(float seconds); // timeout function
+
+/**
+@brief Turns off external green LED
+*/
+void greenOff (); 
+
+
+/**
+@brief Checks is snake has hit wall or self
+@param x - set x plane
+@param y - set y plane
+@returns true or false
+*/
+bool checkCollision(int x,int y); 
+
+/**
+@brief read default positions of the joystick to calibrate later readings
+*/
+void calibrateJoystick();
+
+/**
+@brief read current joystick values relative to calibrated values and calculate direction depending on x,y values
+*/
+void updateJoystick();
+
+/**
+@brief Contains all of the snake code 
+*/
+void snake();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu May 05 09:09:59 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/99a22ba036c9
\ No newline at end of file