Using C language to realize the classic game - Snake

Table of contents

1. The idea of ​​game realization

(1) Define the snake object

(2) Food objects

(3) Score: 

(4) Initialize the snake

(5) Initialize food

(6) Modify the console cursor position

(7) Draw the snake and food

(8) Movement control of the snake

(9) Start the game 

(10) Snake Move

(11) Painting the wall

(12) Remove snake tail

(13) Remove the cursor

(14) Display score

(15) speed up

2. Game implementation code and header files


This project is suitable for those who have just learned the C language structure and have a certain basic C language practice. This small project can help you practice your object-oriented programming thinking.

1. The idea of ​​game realization

In order to realize the Snake game, according to the object-oriented thinking, the following modules must be realized

1. Define snake objects and food objects

2. Initialize the snake, initialize the food

3. Control process:

        1) The collision between the snake head and the wall

        2) Collision between snake head and snake body

        3) Collision between snake head and food

            1> Snake body growth

            2> Food disappears -- new food is created

            3> Score accumulation

            4> Increased movement speed

      4) Movement of the snake

            automatic movement

            Manually control the movement: ASWD --- Left, bottom, top, right

       5) Show score

            leaderboard 

  4. Graphical interface.


(1) Define the snake object

The principle of snake object implementation is coordinates, and X and Y are set to represent the abscissa and ordinate respectively. The body can be represented by an array. body[0] represents the head of the snake, and others represent the body of the snake. And increase.

struct BODY {

		int x;

		int Y;
	};

	struct SNAKE {

		struct BODY body[20*60];	// 蛇身 。 body[0] -- 蛇头

		int size;			// 蛇的大小
	}snake;

 

(2) Food objects

The implementation of the food object is the same as that of the snake object

struct FOOD {

		int X;

		int Y;
	}food;

(3) Score: 
 

    int score;

(4) Initialize the snake

Encapsulate a function to complete the initial snake. The initial size of the snake is 2, representing the snake body and snake head respectively.


	void initSnake(void)
	{
		snake.size = 2;

		snake.body[0].X = WIDE/2;		// 初始化好了蛇头
		snake.body[0].Y = HiGH/2;

		snake.body[1].X = WIDE/2 - 1;		// 初始化一节蛇身
		snake.body[1].Y = HIGH/2;
	}

(5) Initialize food

void initFood(void)
	{	
		food.X = rand() % WIDE;  // 0-59
		food.Y = rand() % HIGH;  // 0-59

		return;
	}

(6) Modify the console cursor position

The cursor position will be positioned at the initialized snake head position (WIDE/2, HIGH/2). The middle of the screen. Note that header files are required to implement the following code: #include <conio.h>, #include <Windows.h>

COORD coord;		// COORD  --> 结构体, 有两个成员变量:x,y 坐标

	coord.X = snake.body[0].X;
	coord.Y = snake.body[0].Y;

	setConsoleCursorPositon(GetStdHandle(STD_OUTPUT_HANDLE), coord);

(7) Draw the snake and food

"@" means the head of the snake, and "*" means the body of the snake. "#" means food

封装函数, initUI()

	COORD coord = {0};					// 光标移动的位置。

	// 画蛇
	for (size_t i = 0; i < snake.size; i++)
	{
		coord.X = snake.body[i].X;
		coord.Y = snake.body[i].Y;

		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);

		if (i == 0)
			putchar('@');
		else
			putchar('*');
	}

	// 画食物
	coord.X = food.X;
	coord.Y = food.Y;

	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);

	putchar('#');

(8) Movement control of the snake

keyboard input

  W: (0, -1) --> Affects snake heads.

    s:(0, +1)

    A:(-1, 0)

    D:(+1, 0)


    No echo: can make the asdw typed by the keyboard not displayed on the input interface

        getch() receives user input.    

        char key = getch();

        Error while compiling, try to use _getch();


    Non-blocking: the input snake cursor can be made non-blocking

        kbhit(); Does not block to judge user input.

        If there is user input, return "true", otherwise return "false".

        Error while compiling, try to use _kbhit();

(9) Start the game 

void playGame(void)
	{

		char key = 'd'; // 默认蛇向右移动

		// 蛇头和墙壁的碰撞:

		while ( 判断是否撞墙 ) {

			// 重画蛇身 intiUI

			// 接收用户键盘输入。

				在全局 添加:kx, ky --》 根据 asdw 按键得不同坐标,影响蛇头

			// 蛇头和身体的碰撞

			// 蛇与食物的碰撞
			
			// 蛇身体移动 : 前一节给后一节赋值,蛇头收 kx ky 的影响。

			system("cls");  清屏 -- 去除蛇尾。
		}
	}

Collision of snake head and wall

Analyzing conditions

snake.body[0].X > 0 && snake.body[0].X < WIDE 
		&&
		  snake.body[0].Y > 0 && snake.body[0].Y < HIGH

Snake head and body collision    

The coordinates of the snake head are exactly the same as the coordinates of any segment of the body.

for(i = 1; i < snake.size; i++)
		{
			if (snake.body[0].X == snake.body[i].X && snake.body[0].Y == snake.body[i].Y )
			{
				终止游戏。
				return ;
			}
		}


    Collision of snake head and food

if (snake.body[0].X == food.X && snake.body[0].Y == food.Y)
		{
			蛇身增长: snake.size++;

			食物消失:(产生一个新食物)initFood()

			加分:score += 10;

			加速:sleepSecond -= 20;
		}

(10) Snake Move

    The body of the previous section assigns a value to the body of the next section. The snake head is transformed according to the coordinate value converted by aswd.

      

  for (size_t i = snake.size-1; i > 0; i--)
        {
            snake.body[i].X = snake.body[i - 1].X;
            snake.body[i].Y = snake.body[i - 1].Y;
        }
        snake.body[0].X += kx;        // 蛇头坐标根据用户按键,修改。
        snake.body[0].Y += ky;

(11) Painting the wall

void initWall(void)
{
	for (size_t i = 0; i <= HIGH; i++)	// 多行
	{
		for (size_t j = 0; j <= WIDE; j++)			// 一行中的多列
		{
			if (j == WIDE)
			{
				printf("|");
			}
			else if (i == HIGH)
			{
				printf("_");
			}
			else
			{
				printf(" ");
			}
		}
		printf("\n");
	}
}

(12) Remove snake tail

Save the snake tail coordinates before the snake moves.

    Define global variables: lastX, lastY;

    lastX = snake.body[snake.size-1].X ;

    lastY = snake.body[snake.size-1].Y ;

    In initUI, replace snake tail with ' '

coord.X = lastX;

		coord.Y = lastY;

		setConsoleCursorPosition(GetSTDHandler(STD_OUTPUT_HANDLE), coord);

		putchar(' ');

(13) Remove the cursor

Cancel the displayed cursor: please press anywhere to continue to make the interface more beautiful

typedef struct _CONSOLE_CURSOR_INFO {
    		DWORD  dwSize;		// 大小
    		BOOL   bVisible;	// 是否可见。
	} CONSOLE_CURSOR_INFO;

	定义结构体变量:

		CONSOLE_CURSOR_INFO  cci;

		cci.dwSize = sizeof(cci);

		cci.bVisible = FALSE; //  0 假 --- 不可见

	设置光标不可见生效:

		setConsoleCursorInfo(GetSTDHandler(STD_OUTPUT_HANDLE), &cci);


	在main函数中,调用一次即可生效。

(14) Display score

    When the playGame call ends, print the global score value.

(15) speed up

Define variables globally: sleepSecond = 400;

            Sleep(sleepSecond);

            successfully eat food, sleepSecond -= 20;

2. Game implementation code and header files

It is recommended to use the VS editor for the game, and it is not recommended for beginners to use the dev editor. The complete code and the implemented exe file are below. If you are interested, you can pack it and take it away.

The figure below is after the code is implemented

 


 

Guess you like

Origin blog.csdn.net/qq_64691289/article/details/131399924