catalogue
1, Game Description
1.1 game key description
1.2 scoring system
2, Game running
2.1 game effect display
2.2 correction of an error
2.3 game code
3, Game framework construction
3.1 size of game interface
3.2 snake head and body
3.2. 1 snakehead
3.2. 2 snake body
3.3 marking the game area
3.3. 1 what are the locations where the game area is stored
3.3. 2 use macros to make some numbers special
3.4 setting of menu bar
IV Hide cursor settings
4.1 structure members of cursor information
4.2 implementation of hidden cursor
4.3 getstdhandle function
Introduction to use
4.4 SetConsoleCursorInfo function
Introduction to use
V Setting of cursor jump
5.1 structure type at cursor position
5.2 setconsolecursor position function
Introduction to use
5.3 realization of cursor jump
Vi Initialization interface
6.1 code
6.2 system function
Introduction to use
6.3 SetConsoleTextAttribute function
Introduction to use
VII Initialize snake
VIII Print snake and overlay snake
9, Randomly generated food
9.1 effect display
9.2 srand and rand functions
Ten. Mobile snake
11, Game subject logic function
11.1 main logic function:
11.2 execute key function
11.3 judgment score and end
11.4 reading historical data from files
11.5 updating data to file
11.6 main function
11.7 game background music
1, Game Description
1.1 game key description
Press the direction key up, down, left and right to change the moving direction of the snake.
Press one of the direction keys up, down, left and right for a short time to accelerate the snake in this direction for a short time.
Press the space bar to pause, and then press any key to continue the game.
Press Esc to exit the game directly. Press the R key to restart the game.
1.2 scoring system
Save the player's highest record in history
2, Game running
2.1 game effect display
#include <stdio.h> #include <Windows.h> #include <stdlib.h> #include <time.h> #include <conio.h> #include<mmsystem.h> #pragma comment(lib,"Winmm.lib") //First, define the size of the game interface, and define the number of rows and columns in the game area #define ROW 22 / / number of rows in the game area #define COL 42 / / number of columns in the game area #define KONG 0 / / the tag is empty (nothing) #define WALL 1 / / mark wall #define FOOD 2 / / mark food #define HEAD 3 / / mark snakehead #define BODY 4 / / mark snake body #define UP 72 / / direction key: up #define DOWN 80 / / arrow keys: down #define LEFT 75 / / direction key: left #define RIGHT 77 / / direction key: right #define SPACE 32 / / pause #define ESC 27 / / exit //Snakehead struct Snake { int len; //Record the length of the snake int x; //Snake head abscissa int y; //Snake head ordinate }snake; //Snake body struct Body { int x; //Abscissa of snake body int y; //Longitudinal coordinate of snake body }body[ROW*COL]; //Open up an array of structures sufficient to store the snake's body int face[ROW][COL]; What are the locations where the game area is stored,For example, whether it is a wall or an empty one, or a snake's body or a snake's head, the purpose can be achieved by storing different numbers //menu bar void menu(); //hide cursor void HideCursor(); //Cursor jump void CursorJump(int x, int y); //Initialization interface void InitInterface(); //color setting void color(int c); //Read highest score from file void ReadGrade(); //Update highest score to file void WriteGrade(); //Initialize snake void InitSnake(); //Randomly generated food void RandFood(); //Judgment score and end void JudgeFunc(int x, int y); //Print snake and overlay snake void DrawSnake(int flag); //Mobile snake void MoveSnake(int x, int y); //Execute key void run(int x, int y); //Game subject logic function void Game(); int max, grade; //global variable int main() { //#pragma warning(disable: n) sets an alarm as invalid #pragma warning (disable:4996) / / you can use the library functions provided by the standard C language menu(); max = 0, grade = 0; //initialize variable srand((size_t)time(NULL));//Generate random seed based on current time system("title Greedy snake"); //Set the name of the cmd window system("mode con cols=84 lines=23"); //Sets the size of the cmd window HideCursor(); //hide cursor ReadGrade(); //Read the highest score from the file to the max variable InitInterface(); //Initialization interface InitSnake(); //Initialize snake RandFood(); //Randomly generated food DrawSnake(1); //Print snake PlaySound(TEXT("bgmusic.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); Game(); //Start the game return 0; } void menu() { system("title Greedy snake"); system("mode con cols=84 lines=23"); //Sets the size of the cmd window color(14);//Set text to light yellow printf("*****************************************************************\n"); printf("******************Welcome to the snake game!!!*******************\n"); printf("*****************************************************************\n"); printf("*********Press the direction key up, down, left and right to change the moving direction of the snake**************\n"); printf("*****************************************************************\n"); printf("**********Press the space bar to pause, and then press any key to continue the game*************\n"); printf("*****************************************************************\n"); printf("*********************Press Esc Key to exit the game directly***********************\n"); printf("*********************Press R Key to restart the game*************************\n"); printf("*****************************************************************\n"); system("pause"); } //When developing game programs with C language, the problem of cursor flicker can be solved by hiding cursor function void HideCursor() { CONSOLE_CURSOR_INFO curInfo; //Structure variable defining cursor information, header file < windows h> curInfo.dwSize = 1; //If there is no assignment, cursor hiding is invalid //curInfo.bVisible = TRUE; // Set cursor to visible curInfo.bVisible = FALSE; //Set the cursor to invisible HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //Get console handle SetConsoleCursorInfo(handle, &curInfo); //Set cursor information } //Cursor jump void CursorJump(int x, int y) { COORD pos; //Structure variable that defines the cursor position pos.X = x; //Abscissa pos.Y = y; //Ordinate HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //Get console handle SetConsoleCursorPosition(handle, pos); //Set cursor position } //Initialization interface void InitInterface() { color(3); //The color is set to lake blue for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { if (j == 0 || j == COL - 1) { face[i][j] = WALL; //Mark the location as a wall CursorJump(2 * j, i); printf("■"); } else if (i == 0 || i == ROW - 1) { face[i][j] = WALL; //Mark the location as a wall printf("■"); } else { face[i][j] = KONG; //Mark this position as empty } } } color(4); //The color is set to red CursorJump(0, ROW); printf("Current score:%d", grade); CursorJump(COL, ROW); printf("Highest score in history:%d", max); } //color setting void color(int c) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //color setting //Note: SetConsoleTextAttribute is an API (Application Programming Interface) } //Read highest score from file void ReadGrade() { FILE* pf = fopen("Snake's highest score.txt", "r"); //Open the file as read-only if (pf == NULL) //fail to open file { pf = fopen("Snake's highest score.txt", "w"); //Open file in write only mode fwrite(&max, sizeof(int), 1, pf); //Write Max to the file (max is 0 at this time), that is, initialize the highest score to 0 } fseek(pf, 0, SEEK_SET); //Make the file pointer pf point to the beginning of the file fread(&max, sizeof(int), 1, pf); //Read the highest score in the file to max fclose(pf); //Close file pf = NULL; //The file pointer is set to null in time } //Update highest score to file void WriteGrade() { FILE* pf = fopen("Snake's highest score.txt", "w"); //Open file in write only mode if (pf == NULL) //fail to open file { printf("Failed to save the highest score record\n"); exit(0); } fwrite(&grade, sizeof(int), 1, pf); //Write the game score of this bureau into the file fclose(pf); //Close file pf = NULL; //The file pointer is set to null in time } //Initialize snake void InitSnake() { snake.len = 2; //The snake's body length is initialized to 2 snake.x = COL / 2; //Abscissa of snake head position snake.y = ROW / 2; //Ordinate of snake head position //Initialization of snake body coordinates body[0].x = COL / 2 - 1; body[0].y = ROW / 2; body[1].x = COL / 2 - 2; body[1].y = ROW / 2; //Mark the position of snake head and body face[snake.y][snake.x] = HEAD; face[body[0].y][body[0].x] = BODY; face[body[1].y][body[1].x] = BODY; } //Randomly generated food int my_time = 1; void RandFood() { int i, j; do { //Randomly generate the abscissa and ordinate of food i = rand() % ROW; j = rand() % COL; } while (face[i][j] != KONG); //Make sure that the location where the food is generated is empty. If it is not empty, it will be regenerated face[i][j] = FOOD; //Mark the food location color(12); //The color is set to red CursorJump(2 * j, i); //The cursor jumps to the generated random position printf("●"); //Print food } //Judgment score and end void JudgeFunc(int x, int y) { //Score if the position of the snake head is food if (face[snake.y + y][snake.x + x] == FOOD) { snake.len++; //Snake body lengthening grade += 10; //Update current score color(7); //The color is set to white CursorJump(0, ROW); printf("Current score:%d", grade); //Reprint current score RandFood(); //Re randomly generate food } //If the snake head is about to reach the wall or the snake body, the game is over else if (face[snake.y + y][snake.x + x] == WALL || face[snake.y + y][snake.x + x] == BODY) { Sleep(1000); //Leave players reaction time system("cls"); //Clear screen color(7); //The color is set to white CursorJump(2 * (COL / 3), ROW / 2 - 3); if (grade > max) { printf("Congratulations on breaking the record. The record has been updated to%d", grade); WriteGrade(); } else if (grade == max) { printf("And the highest record:%d Flat, come on, make another success", grade); } else { printf("Please continue to refuel. There is a difference between the current record and the highest record%d", max - grade); } CursorJump(2 * (COL / 3), ROW / 2); printf("GAME OVER"); while (1) //Ask the player whether to play another game { char ch; CursorJump(2 * (COL / 3), ROW / 2 + 3); printf("One more game?(y/n):"); scanf("%c", &ch); if (ch == 'y' || ch == 'Y') { system("cls"); main(); } else if (ch == 'n' || ch == 'N') { CursorJump(2 * (COL / 3), ROW / 2 + 5); exit(0); } else { CursorJump(2 * (COL / 3), ROW / 2 + 5); printf("Wrong selection, please select again"); } } } } //Print snake and overlay snake void DrawSnake(int flag) { if (flag == 1) //Print snake { color(10); //The color is set to green CursorJump(2 * snake.x, snake.y); printf("■"); //Print snakehead for (int i = 0; i < snake.len; i++) { CursorJump(2 * body[i].x, body[i].y); printf("□"); //Print snake body } } else //Cover snake { if (body[snake.len - 1].x != 0) //Prevent the wall at position (0, 0) from being covered after len + + (i.e. the snake becomes longer) { //Just overwrite the snake tail with a space CursorJump(2 * body[snake.len - 1].x, body[snake.len - 1].y); printf(" "); } } } //Mobile snake void MoveSnake(int x, int y) { DrawSnake(0); //Overwrite the currently displayed snake first face[body[snake.len - 1].y][body[snake.len - 1].x] = KONG; //After the snake moves, the snake tail is re marked as empty face[snake.y][snake.x] = BODY; //After the snake moves, the position of the snake's head becomes the snake's body //After the snake moves, the position coordinates of each snake need to be updated for (int i = snake.len - 1; i > 0; i--) { body[i].x = body[i - 1].x; body[i].y = body[i - 1].y; } //After the snake moves, the position information of the snake head becomes the position information of the first snake body body[0].x = snake.x; body[0].y = snake.y; //Snake head position change snake.x = snake.x + x; snake.y = snake.y + y; DrawSnake(1); //Print moved snake } //Execute key void run(int x, int y) { int t = 0; while (1) { if (t == 0) t = 3000; //The smaller the t here, the faster the snake moves (you can set the difficulty of the game according to times) while (--t)//To control the moving speed, 3000 cycles will take a little time { if (kbhit() != 0) //If the keyboard is struck, exit the cycle break; } if (t == 0) //The keyboard is not tapped { JudgeFunc(x, y); //Judge whether to score and end the game after reaching this position MoveSnake(x, y); //Mobile snake } else //The keyboard is struck { break; //Return the Game function to read the key value } } } //Game subject logic function void Game() { int n = RIGHT; //When you start the game, move backward by default int tmp = 0; //Record the moving direction of the snake goto first; //The first time you enter the cycle, advance in the default direction first while (1) { n = getch(); //Read Key //Before execution, the read keys need to be adjusted switch (n) { case UP: case DOWN: //If you hit "up" or "down" if (tmp != LEFT && tmp != RIGHT) //And the last time the snake moved in a direction other than "left" or "right" { n = tmp; //Then the moving direction of the next snake is set to the moving direction of the previous snake } break; case LEFT: case RIGHT: //If you hit "left" or "right" if (tmp != UP && tmp != DOWN) //And the moving direction of the snake last time was not "up" or "down" { n = tmp; //Then the moving direction of the next snake is set to the moving direction of the previous snake } case SPACE: case ESC: case 'r': case 'R': break; //These four do not need to be adjusted default: n = tmp; //Other keys are invalid. The default is the direction of the last snake movement break; } first: //The first time you enter the cycle, advance in the default direction first switch (n) { case UP: //Direction keys: up run(0, -1); //Move up (abscissa offset is 0, ordinate offset is - 1) tmp = UP; //Record the moving direction of the current snake break; case DOWN: //Direction keys: down run(0, 1); //Move down (abscissa offset is 0, ordinate offset is 1) tmp = DOWN; //Record the moving direction of the current snake break; case LEFT: //Direction key: left run(-1, 0); //Move left (abscissa offset is - 1, ordinate offset is 0) tmp = LEFT; //Record the moving direction of the current snake break; case RIGHT: //Direction key: right run(1, 0); //Move right (abscissa offset is 1, ordinate offset is 0) tmp = RIGHT; //Record the moving direction of the current snake break; case SPACE: //suspend system("pause>nul"); //Press any key to continue after pause break; case ESC: //sign out system("cls"); //Clear screen color(7); //The color is set to white CursorJump(COL - 8, ROW / 2); printf(" game over "); CursorJump(COL - 8, ROW / 2 + 2); exit(0); case 'r': case 'R': //restart system("cls"); //Clear screen main(); //Re execute the main function } } }
2.2 correction of an error
If this happens, believe that this is a compiler problem
(in order to prevent this article from being too long, some knowledge points that do not affect the game logic are displayed in the form of links)
Solution
2.3 game code
Note: the code test environment is visual studio 2017
Music file (extraction code 6666)
3, Game framework construction
3.1 size of game interface
First, define the size of the game interface, and define the number of rows and columns in the game area.
#define ROW 22 / / number of rows in the game area
#define COL 42 / / number of columns in the game area
Here, the snake activity area is called the game area, and the score prompt area is called the prompt area (the prompt area occupies one line).
3.2 snake head and body
In addition, we also need two structures to represent snake head and snake body. The snake head structure stores the length of the current snake body and the position coordinates of the snake head.
3.2. 1 snakehead
struct Snake
{
int len; // Record the length of the snake
int x; // Snake head abscissa
int y; // Snake head ordinate
}snake;
3.2. 2 snake body
The position coordinates of the snake body are stored in the snake body structure
struct Body
{
int x; // Abscissa of snake body
int y; // Longitudinal coordinate of snake body
}body[ROW*COL]; // Open up an array of structures sufficient to store the snake's body
3.3 marking the game area
3.3. 1 what are the locations where the game area is stored
At the same time, we need a two-dimensional array to store what each position in the game area is (the position is empty, wall, food, snake head and snake body).
int face[ROW][COL]; // The purpose of storing the location of the game area can be achieved by storing different numbers
3.3. 2 use macros to make some numbers special
In order to increase the readability of the code, it is best to use macros to define empty space, wall, food, snake head and snake body,
#define KONG 0 / / the tag is empty (nothing) #define WALL 1 / / mark wall #define FOOD 2 / / mark food #define HEAD 3 / / mark snakehead #define BODY 4 / / mark snake body Of course, for the readability of the code, we'd better also define the key values of the keys to be used with macros #define UP 72 / / direction key: up #define DOWN 80 / / arrow keys: down #define LEFT 75 / / direction key: left #define RIGHT 77 / / direction key: right #define SPACE 32 / / pause #define ESC 27 / / exit 3.4 Menu bar settings void menu() { system("title Greedy snake");//Set window title system("mode con cols=84 lines=23"); //Sets the size of the cmd window color(14);//Set text to light yellow printf("*****************************************************************\n"); printf("******************Welcome to the snake game!!!*******************\n"); printf("*****************************************************************\n"); printf("*********Press the direction key up, down, left and right to change the moving direction of the snake**************\n"); printf("*****************************************************************\n"); printf("**********Press the space bar to pause, and then press any key to continue the game*************\n"); printf("*****************************************************************\n"); printf("*********************Press Esc Key to exit the game directly***********************\n"); printf("*********************Press R Key to restart the game*************************\n"); printf("*****************************************************************\n"); system("pause");//Pause the program and press any key to continue }
The functions that appear here will be described below to ensure that we don't wonder!
IV Hide cursor settings
It is relatively simple to hide the cursor. Define a structure variable of the cursor information (the structure type system has been defined), then assign a value to the cursor information, and finally set the cursor information with the structure variable of the cursor information.
4.1 structure members of cursor information
Member details
4.2 implementation of hidden cursor
void HideCursor(){ CONSOLE_CURSOR_INFO curInfo; //Structure variable defining cursor information, header file < windows h> curInfo.dwSize = 1; //If there is no assignment, it is a random value and the cursor is invalid curInfo.bVisible = FALSE; //Set the cursor to invisible HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //Get console handle SetConsoleCursorInfo(handle, &curInfo); //Set cursor information }
4.3 getstdhandle function
Introduction to use
4.4 SetConsoleCursorInfo function
Introduction to use
V Setting of cursor jump
Cursor jump, that is, let the cursor jump to the specified position for output. Similar to the operation steps of hiding the cursor, first define a structure variable at the cursor position, then set the horizontal and vertical coordinates of the cursor, and finally set the cursor position with the structure variable at the cursor position.
5.1 structure type at cursor position
typedef struct _COORD { SHORT X; SHORT Y; } COORD, *PCOORD;
Where typedef short short; 5.2 setconsolecursor position function
Introduction to use
5.3 realization of cursor jump
void CursorJump(int x, int y){ COORD pos; //Structure variable that defines the cursor position pos.X = x; //Abscissa pos.Y = y; //Ordinate HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //Get console handle SetConsoleCursorPosition(handle, pos); //Set cursor position }
Vi Initialization interface
Initialize the interface to print the "wall" in the game area and the prompt area.
6.1 code
int main() { //#pragma warning(disable: n) sets an alarm as invalid #pragma warning (disable:4996) / / you can use the library functions provided by the standard C language system("title Greedy snake"); //Set the name of the cmd window system("mode con cols=84 lines=23"); //Sets the size of the cmd window HideCursor(); //Hide cursor InitInterface(); //Initialization interface Sleep(10000);//Pause for 10000ms, and the header file is < windows h> return 0; } //Initialization interface void InitInterface() { color(6); //The color is set to khaki for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { if (j == 0 || j == COL - 1) { face[i][j] = WALL; //Mark the location as a wall CursorJump(2 * j, i); printf("■"); } else if (i == 0 || i == ROW - 1) { face[i][j] = WALL; //Mark the location as a wall printf("■"); } else { face[i][j] = KONG; //Mark this position as empty } } } color(4); //The color is set to red CursorJump(0, ROW); printf("Current score:%d", grade); CursorJump(COL, ROW); printf("Highest score in history:%d", max); } //color setting void color(int c) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //color setting //Note: SetConsoleTextAttribute is an API (Application Programming Interface) }
6.2 system function
Introduction to use
Note: the last system("color xx") in a program always works
Therefore, the game does not use system("color xx") to control the color of the game interface, but uses
SetConsoleTextAttribute function
6.3 SetConsoleTextAttribute function
Introduction to use
VII Initialize snake
When initializing the snake, the length of the snake body is initialized to 2. The starting position of the snake head is in the center of the game area. The snake head is the 0th snake body and the 1st snake body to the left.
//Initialize snake void InitSnake(){ snake.len = 2; //The snake's body length is initialized to 2 snake.x = COL / 2; //Abscissa of snake head position snake.y = ROW / 2; //Ordinate of snake head position //Initialization of snake body coordinates body[0].x = COL / 2 - 1; body[0].y = ROW / 2; body[1].x = COL / 2 - 2; body[1].y = ROW / 2; //Mark the position of snake head and body face[snake.y][snake.x] = HEAD; face[body[0].y][body[0].x] = BODY; face[body[1].y][body[1].x] = BODY; }
VIII Print snake and overlay snake
Print snake and overlay snake are directly implemented by a function here. If the incoming parameter flag is 1, the snake will be printed; If the passed in parameter is 0, the snake is overwritten with a space.
Print Snake:
First, obtain the coordinates of the snake head according to the structure variable snake, and print the snake head at the corresponding position. Then obtain the coordinates of the snake body according to the structure array body, and print them at the corresponding position.
Cover the snake (please come back to this part after watching the moving snake):
Just cover the last snake with a space.
However, it is important to judge whether the covered position is (0,0) before overwriting, because when the snake body length increases after scoring, and the new Snake tail has not been assigned (the compiler generally initializes to 0 by default), it is not necessary to overwrite the current new Snake tail (just assign a new snake tail and print the snake). The coordinates obtained from the last snake body are (0,0) , if you overwrite, the (0,0) position will be overwritten with spaces, and if the (0,0) position is a wall, the (0,0) position wall will disappear.
Remove the judgment, observe the change of the position wall (0,0) after the snake eats the food, and then analyze it
//Print snake and overlay snake void DrawSnake(int flag) { if (flag == 1) //Print snake { color(10); //The color is set to green CursorJump(2 * snake.x, snake.y); printf("■"); //Print snakehead for (int i = 0; i < snake.len; i++) { CursorJump(2 * body[i].x, body[i].y); printf("□"); //Print snake body } } else //Cover snake { if (body[snake.len - 1].x != 0) //Prevent the wall at position (0, 0) from being covered after len + + (i.e. the snake becomes longer) { //Just overwrite the snake tail with a space CursorJump(2 * body[snake.len - 1].x, body[snake.len - 1].y); printf(" "); } } }
9, Randomly generated food
//Randomly generated food void RandFood() { int i, j; do { //Randomly generate the abscissa and ordinate of food i = rand() % ROW; j = rand() % COL; } while (face[i][j] != KONG); //Make sure that the location where the food is generated is empty. If it is not empty, it will be regenerated face[i][j] = FOOD; //Mark the food location color(12); //The color is set to red CursorJump(2 * j, i); //The cursor jumps to the generated random position printf("●"); //Print food }
9.1 effect display
int main(){ //#pragma warning(disable: n) sets an alarm as invalid #pragma warning (disable:4996) / / you can use the library functions provided by the standard C language srand((size_t)time(NULL));//Generate random seed based on current time system("title Greedy snake"); //Set the name of the cmd window system("mode con cols=84 lines=23"); //Sets the size of the cmd window HideCursor(); //Hide cursor InitInterface(); //Initialization interface InitSnake(); //Initialize snake DrawSnake(1); //Print snake RandFood(); //Randomly generated food Sleep(10000); return 0; }
9.2 srand and rand functions
instructions
Ten. Mobile snake
The move snake function is used to overwrite the currently displayed snake, and then print the moved snake.
Parameter Description:
x: The change of the abscissa of the snake after moving relative to the abscissa of the current snake.
y: The change of the vertical coordinate of the snake after moving relative to the vertical coordinate of the current snake.
After the snake moves, various information needs to be changed:
The last snake body in the game area needs to be re marked as empty. Snake head position in the game area needs to be re marked as snake body. In the structure array body storing snake body coordinate information, it is necessary to update the coordinate information of section i snake body to the coordinate information of section i-1 snake body, while the coordinate information of section 0, that is, the coordinate information of the first snake body, needs to be updated to the coordinate information of the current snake head. The coordinate information of snake head needs to be recalculated according to the input parameters x and y. (please imagine the snake moving in the above process)
//Mobile snake void MoveSnake(int x, int y){ DrawSnake(0); //Overwrite the currently displayed snake first face[body[snake.len - 1].y][body[snake.len - 1].x] = KONG; //After the snake moves, the snake tail is re marked as empty face[snake.y][snake.x] = BODY; //After the snake moves, the position of the snake's head becomes the snake's body //After the snake moves, the position coordinates of each snake need to be updated for (int i = snake.len - 1; i > 0; i--) { body[i].x = body[i - 1].x; body[i].y = body[i - 1].y; } //After the snake moves, the position information of the snake head becomes the position information of the 0th snake body body[0].x = snake.x; body[0].y = snake.y; //Snake head position change snake.x = snake.x + x; snake.y = snake.y + y; DrawSnake(1); //Print moved snake }
11, Game subject logic function
11.1 main logic function:
First, enter the function Game for the first time. By default, the snake moves to the right, and then executes the run function. Until the keyboard is hit, return from the run function to the Game function for key reading. After reading the key value, you need to adjust the read key (this is necessary). After adjustment, press the key to execute, and then press the key to read, so as to cycle.
//Game subject logic function void Game(){ int n = RIGHT; //When you start the game, move backward by default int tmp = 0; //Record the moving direction of the snake goto first; //The first time you enter the cycle, advance in the default direction first while (1){ n = getch(); //Read Key //Before execution, the read keys need to be adjusted switch (n){ case UP: case DOWN: //If you hit "up" or "down" if (tmp != LEFT && tmp != RIGHT) {//And the last time the snake moved in a direction other than "left" or "right" n = tmp; //Then the moving direction of the next snake is set to the moving direction of the previous snake } break; case LEFT: case RIGHT: //If you hit "left" or "right" if (tmp != UP && tmp != DOWN) {//And the moving direction of the snake last time was not "up" or "down" n = tmp; //Then the moving direction of the next snake is set to the moving direction of the previous snake } case SPACE: case ESC: case 'r': case 'R': break; //These four do not need to be adjusted default: n = tmp; //Other keys are invalid. The default is the direction of the last snake movement break; } first: //The first time you enter the cycle, advance in the default direction first switch (n){ case UP: //Direction keys: up run(0, -1); //Move up (abscissa offset is 0, ordinate offset is - 1) tmp = UP; //Record the moving direction of the current snake break; case DOWN: //Direction keys: down run(0, 1); //Move down (abscissa offset is 0, ordinate offset is 1) tmp = DOWN; //Record the moving direction of the current snake break; case LEFT: //Direction key: left run(-1, 0); //Move left (abscissa offset is - 1, ordinate offset is 0) tmp = LEFT; //Record the moving direction of the current snake break; case RIGHT: //Direction key: right run(1, 0); //Move right (abscissa offset is 1, ordinate offset is 0) tmp = RIGHT; //Record the moving direction of the current snake break; case SPACE: //suspend system("pause>nul"); //Press any key to continue after pause break; case ESC: //sign out system("cls"); //Clear screen color(7); //The color is set to white CursorJump(COL - 8, ROW / 2); printf(" game over "); CursorJump(COL - 8, ROW / 2 + 2); exit(0); case 'r': case 'R': //restart system("cls"); //Clear screen main(); //Re execute the main function } } }
11.2 execute key function
Key adjustment mechanism:
If you hit the "up" or "down" key, and the moving direction of the previous snake is not "left" or "right", set the moving direction of the next snake to the moving direction of the previous snake, that is, the moving direction remains unchanged. If you hit the "left" or "right" key, and the moving direction of the previous snake is not "up" or "down", set the moving direction of the next snake to the moving direction of the previous snake, that is, the moving direction remains unchanged. If the keystroke is a space, Esc, R or R, no adjustment will be made. Other keys are invalid. The moving direction of the next snake is set to the moving direction of the previous snake, that is, the moving direction remains unchanged.
//Execute key void run(int x, int y){ int t = 0; while (1){ if (t == 0) t = 3000; //The smaller the t here, the faster the snake moves (you can set the difficulty of the game according to times) while (--t){ //To control the moving speed, 3000 cycles will take a little time if (kbhit() != 0) //If the keyboard is struck, exit the cycle break; } if (t == 0) //The keyboard is not tapped{ JudgeFunc(x, y); //Judge whether to score and end the game after reaching this position MoveSnake(x, y); //Mobile snake } else //The keyboard is struck{ break; //Return the Game function to read the key value } } } kbhit()function Return Value kbhit returns a nonzero value if a key has been pressed. Otherwise, it returns 0.
Execute key
Parameter Description:
x: The change of the abscissa of the snake after moving relative to the abscissa of the current snake.
y: The change of the vertical coordinate of the snake after moving relative to the vertical coordinate of the current snake.
Given a certain time interval, if the keyboard is knocked within this time interval, exit the run function and return to the Game function for key reading. If it is not knocked, judge whether the snake scores or the Game ends after reaching the moved position, and then move the snake's position. If the keyboard has not been tapped, the while function in the run function will be executed, and the snake will move in one direction until the end of the Game
11.3 judgment score and end
Judgment score: if the position where the snake head is about to reach is food, score. After scoring, you need to lengthen the snake body and update the current score. In addition, you also need to regenerate food.
End of judgment: if the snake head is about to reach the wall or snake body, the game is over. After the game, compare the score of this game with the highest score in history, give the corresponding prompt statement, and ask the player whether to play another game, which can be played freely.
11.4 reading historical data from files
First, you need to use the fopen function to open the "greedy snake highest score record. txt" file. If you run the code for the first time, the file will be automatically created and the historical highest record will be set to 0. Then read the historical highest record in the file, store it in the max variable, and close the file.
void JudgeFunc(int x, int y){ //Score if the position of the snake head is food if (face[snake.y + y][snake.x + x] == FOOD){ snake.len++; //Snake body lengthening grade += 10; //Update current score color(7); //The color is set to white CursorJump(0, ROW); printf("Current score:%d", grade); //Reprint current score RandFood(); //Re randomly generate food } //If the snake head is about to reach the wall or the snake body, the game is over else if (face[snake.y + y][snake.x + x] == WALL || face[snake.y + y][snake.x + x] == BODY){ Sleep(1000); //Leave players reaction time system("cls"); //Clear screen color(7); //The color is set to white CursorJump(2 * (COL / 3), ROW / 2 - 3); if (grade > max){ printf("Congratulations on breaking the record. The record has been updated to%d", grade); WriteGrade(); } else if (grade == max){ printf("And the highest record:%d Flat, come on, make another success", grade); } else{ printf("Please continue to refuel. There is a difference between the current record and the highest record%d", max - grade); } CursorJump(2 * (COL / 3), ROW / 2); printf("GAME OVER"); while (1) {//Ask the player whether to play another game char ch; CursorJump(2 * (COL / 3), ROW / 2 + 3); printf("One more game?(y/n):"); scanf("%c", &ch); if (ch == 'y' || ch == 'Y'){ system("cls"); main(); } else if (ch == 'n' || ch == 'N'){ CursorJump(2 * (COL / 3), ROW / 2 + 5); exit(0); } else{ CursorJump(2 * (COL / 3), ROW / 2 + 5); printf("Wrong selection, please select again"); } } } }
11.5 updating data to file
First, use the fopen function to open the "greedy snake highest score record. txt", and then write the score grade of this game into the file (overlay).
//Update highest score to file void WriteGrade() { FILE* pf = fopen("Snake's highest score.txt", "w"); //Open file in write only mode if (pf == NULL) //fail to open file { printf("Failed to save the highest score record\n"); exit(0); } fwrite(&grade, sizeof(int), 1, pf); //Write the game score of this bureau into the file fclose(pf); //Close file pf = NULL; //The file pointer is set to null in time }
11.6 main function
int main() { //#pragma warning(disable: n) sets an alarm as invalid #pragma warning (disable:4996) / / you can use the library functions provided by the standard C language menu(); max = 0, grade = 0; //initialize variable srand((size_t)time(NULL));//Generate random seed based on current time system("title Greedy snake"); //Set the name of the cmd window system("mode con cols=84 lines=23"); //Sets the size of the cmd window HideCursor(); //hide cursor ReadGrade(); //Read the highest score from the file to the max variable InitInterface(); //Initialization interface InitSnake(); //Initialize snake RandFood(); //Randomly generated food DrawSnake(1); //Print snake PlaySound(TEXT("bgmusic.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); Game(); //Start the game return 0; }
11.7 game background music
--------
Copyright notice: This is the original article of CSDN blogger "wandering orphans", which follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this notice for reprint.
Original link: https://blog.csdn.net/qq_42591783/article/details/121684126