Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 8 months ago.
Snake Game, The Snake Tail not working as intended.
I'm trying to make a simple snake game, on FRDM-k64F. Everything works fine, the snake moves, it grows if a food's eaten or i press a button (to simulate food eaten, for debugging). Except, all the snake tail section changes direction everytime I change the snake head direction. I know that's my code's problem, I identified it, but I couldn't get a way to write my code correctly. Any suggestions?
SnakeGame
#include "mbed.h" #include "N5110.h" #include "SNAKELIB.h" // VCC, SCE, RST, D/C, MOSI, SCLK, LED N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3); Ticker SnakeSpeed; //Variables int FoodPattern[3][3] = {{1,0,1},{0,1,0},{1,0,1}}; int SnakeHead[4][3] = {{1,1,1},{1,1,1},{1,1,1},{0,1,1}}; //Snake head template int SnakeTail[4][3] = {{0,0,1},{0,1,1},{1,1,1},{0,1,1}}; //Snake tail template int RandX, RandY; //Random food coordinate int x, y; //The SnakeHead 1st pixel, max (19,10) because it's 4 blocks(and 2 blank pixel space) int tailX[100], tailY[100], SnakeLength; //The SnakeTail pixel, max (19,10) (same above) int prevX, prevY; //Store Previous Snake Tail X,Y status int prev2X, prev2Y; //Store Previous Previous Snake Tail X,Y //Functions void RandFoodCoordinate(); //Randomize the food coordinate void SetFoodCoordinate(); //Set the food coordinate void SetSnakeHead(); void SetSnakeTail(); void SnakeMoving(); void DrawBorders(); //Draw the outline border. void MainGame(); //This is the game function which's called every ticker time void InitSnakeTail(); //Declarations void RandFoodCoordinate() { RandX = rand()%19; //randomize a number between 0-18, i.e. max x coordinate = 76 RandY = rand()%10; //randomize a number between 0-9, i.e. max y coordinate = 40 } void SetFoodCoordinate() { for (int a = 0; a < 3; a++){ for (int b = 0; b < 3; b++){ if (FoodPattern[a][b] == 1){ //The +2 is to make sure the food would not spawn in the border. Maximum (x,y)of food is (78,42) //and the last pixel of food would be (80,44) [[maybe i could make it 83,47 later. need testing]] lcd.setPixel(4*RandX+a+2,4*RandY+b+2); } } } } void SetSnakeHead() { if (snakedirection == right){ for (int c = 0; c < 4; c++){ for (int d = 0; d < 3; d++){ if (SnakeHead[c][d] == 1){ lcd.setPixel(4*x+c+1,4*y+d+2); //The +1, +2 is just to align the pixel with the food correctly } } } } else if (snakedirection == left){ for (int c = 0; c < 4; c++){ for (int d = 0; d < 3; d++){ if (SnakeHead[c][d] == 1){ lcd.setPixel(4*x-c+5,4*y+d+2); //The +5, +2 is to align the pixel with food correctly } } } } else if (snakedirection == up){ for (int c = 0; c < 4; c++){ for (int d = 0; d < 3; d++){ if (SnakeHead[c][d] == 1){ lcd.setPixel(4*x+d+2,4*y-c+6); //+2, +6 is to align pixel with food } } } } else if (snakedirection == down){ for (int c = 0; c < 4; c++){ for (int d = 0; d < 3; d++){ if (SnakeHead[c][d] == 1){ lcd.setPixel(4*x+d+2,4*y+c+2); //+2 +2 for pixel alignment } } }for (int c = 0; c < 4; c++){ for (int d = 0; d < 3; d++){ if (SnakeHead[c][d] == 1){ lcd.setPixel(4*x+c+1,4*y+d+2); //The +1, +2 is just to align the pixel with the food correctly } } } } else{ for (int c = 0; c < 4; c++){ for (int d = 0; d < 3; d++){ if (SnakeHead[c][d] == 1){ lcd.setPixel(4*x+c+1,4*y+d+2); //The +1, +2 is just to align the pixel with the food correctly } } } } } void SetSnakeTail() //This is the function which consists of problem. { prevX = tailX[0]; //Stores the value of SnakeHead(x,y) so that the tail[i] can move to tail[i-1] (which is 0 in this case] prevY = tailY[0]; // tailX[0] = x; //tailX[0] is actually the x coordinate of SnakeHead. This makes sure the tail is following head. tailY[0] = y; //tailY[0] is actually the y coordinate of SnakeHead. This makes sure the tail is following head. for (int i = 1; i<SnakeLength; i++){ prev2X = tailX[i]; //Stores (x,y) of tailX[i], e.g. tailX[1] prev2Y = tailY[i]; // tailX[i] = prevX; //tailX[i] moves to tailX[i-1], e.g. tailX[1] to tailX[0] i.e. x (head position). Remember head already moved. tailY[i] = prevY; //tailY[i] moves to tailY[i-1]. prevX = prev2X; //prevX becomes prev2X. So that in the next for loop tailX[i] would update to the next element. prevY = prev2Y; if (snakedirection == right){ for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+e+1,4*tailY[i]+f+2); //move right } } } } else if (snakedirection == left){ for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]-e+5,4*tailY[i]+f+2); //move left } } } } else if (snakedirection == up){ for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+f+2,4*tailY[i]-e+6); //move up } } } } else if (snakedirection == down){ for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+f+2,4*tailY[i]+e+2); //move down } } } } } } void SnakeMoving() //karnaugh warping of pixels. { readJoystick(); if (snakedirection == right){ x++; if (x > 19){ x = 0;}} else if (snakedirection == left){ x--; if (x < 0){ x = 19;}} else if (snakedirection == up){ y--; if (y < 0){ y = 10;}} else if (snakedirection == down){ y++; if (y > 10){ y = 1;}} else {} } void DrawBorders() //function name says it all { lcd.drawRect(0,0,83,47,0); lcd.refresh(); } void MainGame() { lcd.clear(); SetSnakeHead(); if (button == 1 || (x == RandX && y == RandY)){ SnakeLength++; RandFoodCoordinate(); SetFoodCoordinate(); } else{ SetFoodCoordinate(); } SetSnakeTail(); SnakeMoving(); DrawBorders(); } //MAIN CODE int main() { //Calibrate Joystick First. calibrateJoystick(); // get centred values of joystick // button.mode(PullDown); srand(time(0)); //what srand do, is to tell the program make a new set of random numbers every second the program is running //Start the lcd initialisation lcd.init(); RandFoodCoordinate(); SetFoodCoordinate(); x = 10; y = 5; SnakeLength = 2; SetSnakeHead(); InitSnakeTail(); DrawBorders(); readJoystick(); snakedirection = centre; //And then start calling the ticker function of game while (snakedirection == centre){ updateJoystick(); readJoystick(); if (snakedirection != centre) break; } pollJoystick.attach(&updateJoystick,1.0/30.0); // read joystick 10 times per second SnakeSpeed.attach(&MainGame,0.2); //address of the function to be attached (Main Game) and speed (0.2) while(1) {} } void InitSnakeTail() { tailX[0] = x; tailY[0] = y; for (int i = 1; i < SnakeLength; i++){ tailX[i] = x-i; tailY[i] = y; for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+e+1,4*tailY[i]+f+2); //That +2 is to match the snake placement. } } } } }
This is the link to a video showing how my code doesn't work. https://www.youtube.com/watch?v=sk5fL_qBxTo
1 Answer
8 years, 8 months ago.
OK so you're using full redraw, Personally I prefer selective erase it might give less flicker if the display doesn't have a double buffer.
Looking at the "draw tail" loop it seems to use the same "snakedirection" variable for the whole tail. I think you have two options:
Either store the tail direction in an array the way you store the tail positions... or ...Determine the direction of a tail section based on the position of the previous section.
something like
if (tailX[i] > prevX) { for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+e+1,4*tailY[i]+f+2); //move right } } } } else if (tailX[i] < prevX) { for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]-e+5,4*tailY[i]+f+2); //move left } } } } else if (tailY[i] < prevY) { for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+f+2,4*tailY[i]-e+6); //move up } } } } else if (tailY[i] > prevY) ){ for (int e = 0; e < 4; e++){ for (int f = 0; f < 3; f++){ if (SnakeTail[e][f] == 1){ lcd.setPixel(4*tailX[i]+f+2,4*tailY[i]+e+2); //move down } } } }
I might have got left/right flipped but I think it shows how it might be fixed