Code for simple game of snake with four playing modes.
Dependencies: N5110 PinDetect PowerControl mbed
main.cpp
- Committer:
- fiifimills
- Date:
- 2015-05-11
- Revision:
- 12:fa654504b51f
- Parent:
- 11:f421defe6f55
File content as of revision 12:fa654504b51f:
#include "mbed.h" #include "N5110.h" #include "PinDetect.h" #include "PowerControl/PowerControl.h" #include "PowerControl/EthernetPowerControl.h" #include <vector> #include <stdlib.h> /* srand, rand */ #include <time.h> /* Code for Snake game B.F. Mills April 12th 2015 */ // change this to alter tolerance of joystick direction #define DIRECTION_TOLERANCE 0.05 // vcc, sce, rst, dc, mosi, sck, backlight N5110 lcd(p7, p8, p9, p10, p11, p13, p26); // joystick connections AnalogIn yPot(p15); AnalogIn xPot(p16); DigitalIn button(p17); // leds BusOut myleds(LED1, LED2, LED3, LED4); // buttons PinDetect buttonA(p30); PinDetect buttonB(p29); // 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 }; DirectionName currentDirection; // enum variable for current direction of snake's movement DirectionName previousDirection; // enum variable for previous direction of snake's movement // enumerated type for game menu screen enum GameMenu { STARTUP, SELECTSPEED, GAMEPLAY }; GameMenu currentGameMenu; // create game menu variable // 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; // struct for a coordinate struct coordinate { int x; // x coordinate int y; // y coordinate }; char buffer [14]; // buffer for printing score to screen // flags int printFlag = 0; int Aflag = 0; // flag for notification of A button interrupt int Bflag = 0; // flag for notification of B button interrupt int collisionFlag = 0; // flag for notification of self snake collision int borderFlag = 0; // flag for hitting border in insane mode // global variables int score = 0; // score value bool gameOver; // boolean variable for game over int xCentre = 4; // x coordinate for centre of selection circle int yCentre = 11; // y coordinate for centre of selection circle float speed; // wait time for moveSnake function void pressedA() { Aflag = 1; // set flag when A button is pressed } void pressedB() { Bflag = 1; // set flag when B button is pressed } // function prototypes void calibrateJoystick(); void updateJoystick(); void moveSnake(); void speedSelect(); std::vector<coordinate> Snake; // create a vector that stores coordinate structs int main() { calibrateJoystick(); // get centred values of joystick pollJoystick.attach(&updateJoystick,1.0/20.0); // read joystick 20 times per second lcd.init(); // initialise display lcd.setBrightness(0.5); // set brightness of backlight PHY_PowerDown(); // power down ethernet // set button modes to pull down buttonA.mode(PullDown); buttonB.mode(PullDown); buttonA.attach_asserted(&pressedA); // call pressedA function when button is pressed buttonB.attach_asserted(&pressedB); // call pressedB function when button is presed // set sample frequency for buttons (default = 20ms) buttonA.setSampleFrequency(); buttonB.setSampleFrequency(); currentGameMenu = STARTUP; // initialise game menu to be splash screen gameOver = false; // initialise gameOver as false while (1) { // infinite loop if (currentGameMenu == STARTUP) { // start up screen // splash screen for startup lcd.printString("SNAKE",28,1); lcd.printString("PRESS A",21,5); // draw snake logo lcd.drawRect(26,27,5,5,0); // bottom rectangle of snake lcd.drawRect(26,22,5,5,0); // the rectangle directly above lcd.drawRect(31,22,5,5,0); // the rectangle one to the right lcd.drawRect(36,22,5,5,0); // one to the right lcd.drawRect(41,22,5,5,0); // one to the right lcd.drawRect(51,22,5,5,1); // "food" lcd.refresh(); Sleep(); // when flag is not set, go to sleep & wait for interrupt if (Aflag) { // if currentGameMenu is STARTUP and A is pressed, Aflag = 0; // reset flag lcd.clear(); // clear screen currentGameMenu = SELECTSPEED; // segue to select speed menu } } if (currentGameMenu == SELECTSPEED) { // select speed menu // print menu options to screen lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE",46,1); lcd.drawCircle(xCentre,yCentre,3,1); // draw selection circle (starting on SLOW) lcd.refresh(); speedSelect(); if (Aflag) { // if currentGameMenu is SELECTSPEED and A is pressed, Aflag = 0; // reset flag lcd.clear(); // cleat screen currentGameMenu = GAMEPLAY; // segue to gameplay } Sleep(); // when flag is not set, got to sleep & wait for interrupt } if (currentGameMenu == GAMEPLAY) { // gameplay if (gameOver == false) { // whilst game is not over if (xCentre + yCentre == 15) { // if the addition of the coordinates of the centre of the selection circle = 15 i.e when selecting SLOW speed = 0.20; // set wait time for moveSnake } if (xCentre + yCentre == 31) { // medium speed = 0.12; } if (xCentre + yCentre == 47) { // fast speed = 0.04; } if (xCentre + yCentre == 53) { // insane speed = 0.02; for (int y=0; y<23 ; y++) { // set upper border lcd.setPixel(43,y); lcd.refresh(); } for (int y=25; y<47; y++) { // set lower border lcd.setPixel(43,y); lcd.refresh(); } } previousDirection = RIGHT; // initialise first direction to be right // set of initial coordinates coordinate cord0 = {45, 24}; coordinate cord1 = {46, 24}; coordinate cord2 = {47, 24}; coordinate cord3 = {48, 24}; // add these coordinates to the snake vector Snake.push_back(cord0); Snake.push_back(cord1); Snake.push_back(cord2); Snake.push_back(cord3); // set these co-ordinate's pixels for (int i=0; i<Snake.size(); i++) { lcd.setPixel(Snake.at(i).x, Snake.at(i).y); lcd.refresh(); } moveSnake(); } if (gameOver == true) { // if game is over // display game over splash screen lcd.printString("Game Over!",14,1); lcd.printString("Press B",23,4); int printScore = sprintf(buffer,"Score = %d",score*5); // print formatted data to buffer if (printScore <= 14) { // if string fits on display lcd.printString(buffer,16,3); } Snake.clear(); // clear snake vector while (1) { // flash leds myleds = 15; wait(0.5); myleds = 0; wait(0.5); if (Bflag) // if B is pressed, break out of infinite loop break; } if (Bflag) { // if B is pressed, Bflag = 0; // reset flag collisionFlag = 0; // reset collision flag score = 0; // reset score myleds = 0; // switch off leds borderFlag = 0; gameOver = false; // reset gameOver to false lcd.clear(); // clear the screen currentGameMenu = STARTUP; // go back to startup screen } } } } } // read default positions of the joystick to calibrate later readings void calibrateJoystick() { button.mode(PullDown); // 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; // read button state joystick.button = button; // 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 = RIGHT; } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) { joystick.direction = LEFT; } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) { joystick.direction = DOWN; } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) { joystick.direction = UP; } else { joystick.direction = UNKNOWN; } // set flag for printing printFlag = 1; } void moveSnake() { srand(time(NULL)); // use time as seed for rand int foodX = rand()%82+1; // random x coordinate between 1-82 int foodY = rand()%46+1; // random y coordinate between 1-46 // draw border lcd.drawRect(0,0,83,47,0); // x-origin, y-origin, width, height, fill lcd.refresh(); if (!lcd.getPixel(foodX,foodY)) // if pixel is not already set lcd.setPixel(foodX,foodY); // set pixel of this coordinate (used for food) lcd.refresh(); while (1) { // infinite loop if (joystick.direction == CENTRE) { // if the joystick is in the centre currentDirection = previousDirection; // current direction is the previous direction of movement } if (joystick.direction == UNKNOWN) { // if the joystick's direction is unknown currentDirection = previousDirection; // current direction is the previous direction } // if joystick direction is left, right, up or down, set the current direction to be the joystick's direction if (joystick.direction == LEFT) { currentDirection = joystick.direction; } if (joystick.direction == RIGHT) { currentDirection = joystick.direction; } if (joystick.direction == UP) { currentDirection = joystick.direction; } if (joystick.direction == DOWN) { currentDirection = joystick.direction; } lcd.clearPixel(Snake.front().x, Snake.front().y); // clear the tail pixel of snake for (int i=0; i<Snake.size()-1; i++) { // shift along each element in the vector so that.. Snake.at(i) = Snake.at(i+1); // value of element Snake[0] = Snake[1], Snake[1] = Snake[2] etc. } switch (currentDirection) { // check the current direction case UP: // if up if (previousDirection == DOWN) { // check if the previous direction was opposite to the current direction currentDirection = DOWN; // if so, move in the previous direction Snake.back().y++; // increment appropiate coordinate value } else { // if the previous direction wasn't opposite to the current direction, previousDirection = UP; // set the previous direction Snake.back().y--; // increment appropiate coordinate value } break; case DOWN: if (previousDirection == UP) { currentDirection = UP; Snake.back().y--; } else { previousDirection = DOWN; Snake.back().y++; } break; case LEFT: if (previousDirection == RIGHT) { currentDirection = RIGHT; Snake.back().x++; } else { previousDirection = LEFT; Snake.back().x--; } break; case RIGHT: if (previousDirection == LEFT) { currentDirection = LEFT; Snake.back().x--; } else { previousDirection = RIGHT; Snake.back().x++; } break; default: break; } if ((Snake.back().x == foodX) && (Snake.back().y == foodY)) { // if the snake head hits the food switch (currentDirection) { // check the current direction case UP: Snake.push_back(Snake.back()); // add an element, which is equal to the penultimate element, to the end of the vector Snake.back().y--; // increment the appropiate coordinate of this new element for the direction of movement foodX = rand()%82 + 1; // x coordinate of food is now a new random number between 1-83 foodY = rand()%46 + 1; // y coordinate of food is now a new random number between 1-47 if (!lcd.getPixel(foodX,foodY)) { lcd.setPixel(foodX,foodY); lcd.refresh(); } score++; // increment score value // flash led myleds = 1; wait(0.2); myleds = 0; break; case DOWN: Snake.push_back(Snake.back()); Snake.back().y++; foodX = rand()%82 + 1; foodY = rand()%46 + 1; if (!lcd.getPixel(foodX,foodY)) { lcd.setPixel(foodX,foodY); lcd.refresh(); } score++; myleds = 1; wait(0.2); myleds = 0; break; case LEFT: Snake.push_back(Snake.back()); Snake.back().x--; foodX = rand()%82 + 1; foodY = rand()%46 + 1; if (!lcd.getPixel(foodX,foodY)) { lcd.setPixel(foodX,foodY); lcd.refresh(); } score++; myleds = 1; wait(0.2); myleds = 0; break; case RIGHT: Snake.push_back(Snake.back()); Snake.back().x++; foodX = rand()%82 + 1; foodY = rand()%46 + 1; if (!lcd.getPixel(foodX,foodY)) { lcd.setPixel(foodX,foodY); lcd.refresh(); } score++; myleds = 1; wait(0.2); myleds = 0; break; default: break; } } for (int i = 0; i < Snake.size()-1; i++) { // iterate through all elements in the snake vector if ((Snake.back().x == Snake.at(i).x) && (Snake.back().y == Snake.at(i).y)) { // if snake head touches any other part of the snake collisionFlag = 1; // set colision flag gameOver = true; // set gameOver to true } } if (collisionFlag) break; // if collision flag is set, break out of infinite loop if (Snake.back().x > 82) { // if snakeHead's x coordinate is 83 or larger (i.e touching the right hand side border) gameOver = true; // game over is true break; // break out of infinite loop } if (Snake.back().x < 1) { // touching left hand side border gameOver = true; break; } if (Snake.back().y > 46) { // touching top border gameOver = true; break; } if (Snake.back().y < 1) { // touching bottom border gameOver = true; break; } if (xCentre + yCentre == 53) { // insane if ((Snake.back().x == 43) && (Snake.back().y < 23)) { // if snake touches upper border gameOver = true; // game over is true borderFlag = 1; // set border flag } if ((Snake.back().x == 43) && (Snake.back().y > 24)) { // if snake touches lower border gameOver = true; // game over is true borderFlag = 1; // set border flag } } if (borderFlag) break; // if border flag is set, break out of infinite loop lcd.setPixel(Snake.back().x, Snake.back().y); // set new snakeHead's pixel lcd.refresh(); wait(speed); } } void speedSelect() { if (joystick.direction == DOWN) { // if the joystick is moved down if (xCentre == 4 && yCentre == 11) { // i.e. when the selection circle is on SLOW lcd.clear(); // clear the screen // print options lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE",46,1); yCentre = 27; // set new y value for centre of selection circle lcd.drawCircle(xCentre,yCentre,3,1); // draw new selection circle lcd.refresh(); wait(0.3); } else if (xCentre == 4 && yCentre == 27) { // medium lcd.clear(); lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE!",46,1); yCentre = 43; lcd.drawCircle(xCentre,yCentre,3,1); lcd.refresh(); wait(0.3); } else if (xCentre == 4 && yCentre == 43) { // fast lcd.clear(); lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE",46,1); xCentre = 42; yCentre = 11; lcd.drawCircle(xCentre,yCentre,3,1); lcd.refresh(); wait(0.3); } } if (joystick.direction == UP) { if (xCentre == 42 && yCentre == 11) { // insane lcd.clear(); lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE",46,1); xCentre = 4; yCentre = 43; lcd.drawCircle(xCentre,yCentre,3,1); lcd.refresh(); wait(0.3); } else if (xCentre == 4 && yCentre == 43) { // fast lcd.clear(); lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE!",46,1); yCentre = 27; lcd.drawCircle(xCentre,yCentre,3,1); lcd.refresh(); wait(0.3); } else if (xCentre == 4 && yCentre == 27) { // medium lcd.clear(); lcd.printString("SLOW",10,1); lcd.printString("MEDIUM",10,3); lcd.printString("FAST",10,5); lcd.printString("INSANE",46,1); yCentre = 11; lcd.drawCircle(xCentre,yCentre,3,1); lcd.refresh(); wait(0.3); } } }