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: Joystick N5110 SDFileSystem beep fsmMenu mbed
Fork of SnakeProjectRev1 by
main.cpp
- Committer:
- meurigp
- Date:
- 2016-05-04
- Revision:
- 17:4e6f0f7f22fb
- Parent:
- 16:68b9460d4c76
- Child:
- 18:67d5ae64fbd1
File content as of revision 17:4e6f0f7f22fb:
/** @file main.cpp @brief Program implementation of Snake Game */ #include "mbed.h" #include "main.h" #include "N5110.h" #include "beep.h" #include "SDFileSystem.h" #include "Joystick.h" #include "fsmMenu.h" // VCC, SCE, RST, D/C, MOSI, SCLK, LED N5110 lcd (PTD3, PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3); // Can also power (VCC) directly from VOUT (3.3 V) - // Can give better performance due to current limitation from GPIO pin // Connections to SD card holder on K64F (SPI interface) SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS /// Serial for debug Serial serial(USBTX,USBRX); Ticker pollJoystick; Ticker gameTicker; FILE *fp; // this is our file pointer void timer_isr(); void rb_isr(); void lb_isr(); int main() { calibrateJoystick(); // get centred values of joystick pollJoystick.attach(&updateJoystick,0.5/10.0); // read joystick 20 times per second srand(time(NULL)); greenLed = 1; redLed = 0; lcd.init(); //snakeIntro(); //hardWall(); //wrapAround(); //generateFood(); gamePlaying = false; //initSnakeTail(); button.rise(&buttonISR); gameTicker.attach(&timer_isr,0.1); RB.mode(PullDown); LB.mode(PullDown); RB.rise(&rb_isr); LB.rise(&lb_isr); while(1) { lcd.printString("Classic",0,1); lcd.printString("Infinite",0,3); lcd.printString("Hard Map",0,5); if (rb_flag == 1) { rb_flag = 0; gamePlaying = true; break; } // check if flag i.e. interrupt has occured if (printFlag ==1) { printFlag = 0; // if it has, clear the flag // swap direction when button has been pressed // (could just use ! but want this to be explicit to aid understanding) if (joystick.direction == CENTRE) { serial.printf(" CENTRE\n"); menuDirection = menuSTOP; } else if (joystick.direction == UP) { serial.printf(" UP\n"); menuDirection = menuUP; buzzer.beep(2000,0.2); } else if (joystick.direction == DOWN) { serial.printf(" DOWN\n"); menuDirection = menuDOWN; buzzer.beep(2000,0.2); } } menuFSM(); wait(0.2); // small delay if (state ==0) { lcd.clear(); lcd.printString("*",70,1); gameType = classicMode; } else if (state ==1) { lcd.clear(); lcd.printString("*",70,3); gameType = infiniteMode; } else if (state ==2) { lcd.clear(); lcd.printString("*",70,5); gameType = hardMode; } } mainGame(); } void generateFood() { if (gameType == classicMode || gameType == hardMode) { while (randomXoddEven ==0 || randomYoddEven ==0 || lcd.getPixel(randomX,randomY) >= 1) { // do while x or y is even or pixel is on randomX = rand() % 83 + 1; // randomX in the range 1 to 83 randomY = rand() % 47 + 1; // randomY in the range 1 to 47 randomXoddEven = randomX%2; // find out whether odd or even randomYoddEven = randomY%2; } lcd.drawRect(randomX,randomY,1,1,1); } else { while (randomXoddEven ==1 || randomYoddEven ==1 || lcd.getPixel(randomX,randomY) >= 1) { // do while x or y is even or pixel is on randomX = rand() % 83 + 1; // randomX in the range 1 to 83 randomY = rand() % 47 + 1; // randomY in the range 1 to 47 randomXoddEven = randomX%2; // find out whether odd or even randomYoddEven = randomY%2; } lcd.drawRect(randomX,randomY,1,1,1); } } void newFruitXY() // new fruit coordinate values are given before it is passed to the generateFood function { randomX = rand() % 83 + 1; // randomX in the range 1 to 81 randomY = rand() % 47 + 1; // randomY in the range 1 to 47 randomXoddEven = randomX%2; // find out whether odd or even randomYoddEven = randomY%2; } void moveSnake() { if (joystick.direction == LEFT) { if (currentDirection != right) { // change the currentDirection according to joystick input, providing currentDirection = left; // it's not the opposite direction to the current direction } } else if (joystick.direction == RIGHT) { if (currentDirection != left) { // change the currentDirection according to joystick input, providing currentDirection = right; // it's not the opposite direction to the current direction } } else if (joystick.direction == UP) { if (currentDirection != down) { // change the currentDirection according to joystick input, providing currentDirection = up; // it's not the opposite direction to the current direction } } else if (joystick.direction == DOWN) { if (currentDirection != up) { // change the currentDirection according to joystick input, providing currentDirection = down; // it's not the opposite direction to the current direction } } } void gameLogic() { lcd.clear(); greenLed = 1; prev_i = snakeTailX[0]; prev_j = snakeTailY[0]; snakeTailX[0] = i; snakeTailY[0] = j; for (int a=1; a<snakeTailLength; a++) { // loops through snakeTail array and assigns previous seg's coordinates to current one prev2_i = snakeTailX[a]; prev2_j = snakeTailY[a]; snakeTailX[a] = prev_i; snakeTailY[a] = prev_j; prev_i = prev2_i; prev_j = prev2_j; } if (currentDirection == left) { // shift snake head coordinates according to current direction i -= 2; } // move left else if (currentDirection == right) { i += 2; } // move right else if (currentDirection == up) { j -= 2; } // move up else if (currentDirection == down) { j += 2; } // move down lcd.drawRect(i,j,1,1,1); // snake head for (int b=0; b<snakeTailLength; b++) { lcd.drawRect(snakeTailX[b],snakeTailY[b],1,1,1); } lcd.refresh(); lcd.drawRect(randomX,randomY,1,1,1); // food if (gameType == classicMode) { hardWall(); } else if (gameType == infiniteMode) { wrapAround(); } else { specialMap(); } if (i == randomX && j == randomY) { // if fruit is eaten greenLed = 0; buzzer.beep(2000,0.2); scoreCalculation(); snakeTailLength++; newFruitXY(); generateFood(); } if (snakeTailLength > 4) { // if snake eats itself for (int q=1; q<snakeTailLength; q++) { if (snakeTailX[q] == i && snakeTailY[q] == j) { gameOver(); } } } } void hardWall() { lcd.drawRect(0,0,83,47,0); lcd.refresh(); if (i == 0 || i+1 == 0 || i == 83 || i+1 == 83 || // if any of the 4 pixels within the snake head touch the border j == 0 || j+1 == 0 || j == 47 || j+1 == 47) { gameOver(); } } void gameOver() { redLed = 1; if(score > top_score) { ////////////////////// Simple writing example ////////////////////////// // open file for writing ('w') - creates file if it doesn't exist and overwrites // if it does. If you wish to add a score onto a list, then you can // append instead 'a'. This will open the file if it exists and start // writing at the end. It will create the file if it doesn't exist. fp = fopen("/sd/topscore.txt", "w"); int top_score = score; 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",top_score); // ensure data type matches serial.printf("Done.\n"); fclose(fp); // ensure you close the file after writing } } gamePlaying = false; lcd.clear(); buzzer.beep(294,0.5); wait(0.5); lcd.printString("Game Over",15,0); // width(6) * n(9) = 54, 84-54 = 30, 30/2 = 15 buzzer.beep(277,0.5); wait(0.5); char buffer[14]; int length = sprintf(buffer,"Score:%i",score); // display score of round if (length <= 14) { // if string will fit on display lcd.printString(buffer,0,1); } // display on screen buzzer.beep(262,2); ////////////////////// Simple reading example ////////////////////////// // now open file for reading fp = fopen("/sd/topscore.txt", "r"); // int stored_top_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"); } else { // opened file so can write fscanf(fp, "%d",&top_score); // ensure data type matches - note address operator (&) serial.printf("Read %d from file.\n",top_score); char buffer[14]; int length = sprintf(buffer,"HI Score:%i",top_score); // display score of round if (length <= 14) { // if string will fit on display lcd.printString(buffer,0,2); } // display on screen fclose(fp); // ensure you close the file after reading } wait(0.5); redLed = 0; lcd.printString("RB - Restart",0,4); wait(0.5); lcd.printString("LB - Menu",0,5); /* if (RB == 0) { moveSnake(); } */ } void specialMap() { for (int x=41; x<43; x++) { // vertical cross line for (int y=14; y<34; y++) { lcd.setPixel(i,j); lcd.refresh(); } } for (int x=32; x<52; x++) { // horizontal cross line for (int y=23; y<25; y++) { lcd.setPixel(i,j); lcd.refresh(); } } } void wrapAround() { if (i == -2) { i = 82; } if (i == 84) { i = 0; } if (j == -2) { j = 46; } if (j == 48) { j = 0; } } void scoreCalculation() { score += fruitValue; // each time fruit is eaten score is calculated and fruit value will increase by 1 fruitValue++; //serial.printf("score = %i\n",score); //serial.printf("fruitValue = %i\n\n",fruitValue); } void initSnakeTail() { if (gameType == classicMode) { prev_i = 39; prev_j = 23; prev2_i = 37; prev2_j = 23; } else if (gameType == infiniteMode) { prev_i = 38; prev_j = 22; prev2_i = 36; prev2_j = 22; } else { prev_i = 11; prev_j = 5; prev2_i = 9; prev2_j = 5; } snakeTailX[1] = prev_i; snakeTailY[1] = prev_j; snakeTailX[2] = prev2_i; snakeTailY[2] = prev2_j; lcd.drawRect(i,j,1,1,1); // snake head for (int b=0; b<snakeTailLength; b++) { lcd.drawRect(snakeTailX[b],snakeTailY[b],1,1,1); } currentDirection = right; } void snakeIntro() { for(int i=0; i<WIDTH; i++) { for(int j=0; j<HEIGHT; j++) { lcd.setPixel(i,j); } } for (int q=0; q<WIDTH/2; q++) { lcd.drawCircle(WIDTH/2,HEIGHT/2,q,2); wait_ms(2); } // x,y,radius,white fill lcd.printString("Snake",27,0); buzzer.beep(2000,0.5); wait(0.5); lcd.printString("by",36,2); buzzer.beep(1000,0.5); wait(0.5); lcd.printString("Meurig",24,3); buzzer.beep(500,0.5); wait(0.5); lcd.printString("Phillips",18,4); buzzer.beep(250,2); wait(2); lcd.clear(); } void gamePaused() { wait_ms(100); pauseCount++; //gamePlaying = false; lcd.clear(); char buffer[14]; int length = sprintf(buffer,"%i left",3-pauseCount); // number of pauses left if (length <= 14) { // if string will fit on display lcd.printString(buffer,24,3); } // display on screen lcd.printString("Paused 5",18,1); wait(1); lcd.printString("Paused 4",18,1); wait(1); lcd.printString("Paused 3",18,1); wait(1); lcd.printString("Paused 2",18,1); wait(1); lcd.printString("Paused 1",18,1); wait(1); } void mainGame() { if(gameType == classicMode) { hardWall(); i = 41; j = 23; } else if(gameType == infiniteMode) { wrapAround(); i = 40; j = 22; } else { specialMap(); i = 13; j = 5; } generateFood(); initSnakeTail(); score = 0; fruitValue = 10; // init everything while(gamePlaying == true) { lcd.setBrightness(1-pot); // turn pot right for brightness if (buttonFlag ==1) { buttonFlag = 0; if (pauseCount < 3) { gamePaused(); } } if(game_timer_flag) { game_timer_flag = 0; gameLogic(); } if (printFlag) { // if flag set, clear flag and print joystick values to serial port printFlag = 0; moveSnake(); } sleep(); // put the MCU to sleep until an interrupt wakes it up } } void timer_isr() { game_timer_flag = 1; } void rb_isr() { rb_flag = 1; } void lb_isr() { lb_flag = 1; }