基于C/C++综合训练 ----- 贪吃蛇


该篇环境为Visual Studio2022

游戏简述 :在控制终端绘画出一个矩阵表示游戏界面(围墙),“ @ ”表示蛇头,“ * ”表示蛇身,“ # ”表示食物。通过向控制终端输入"a"、“s”、“w”、"d"分别表示贪吃蛇向左、向下、向上、向右移动,食物为随机出现(同一时刻只有一个食物出现),每吃掉一块食物,蛇的移动速度加快且游戏分数+10,若蛇撞到墙或吃到自身会导致游戏结束并打印游戏分数在终端上。

在这里插入图片描述

一、定义结构体对象

该游戏可划分为俩个对象,“贪吃蛇”和“食物”对象
而“贪吃蛇”对象 又可划分为“一节蛇头”和“多节蛇身”

1. 定义蛇身结构体

struct BODY {
    
    
	int X;   //x 和 y 表示蛇身的一个位置点(坐标)
	int Y;
};

2. 定义蛇对象
其中 body[0]为蛇头,其余都表示蛇身

struct SNAKE {
    
    
	struct BODY body[WIDE * HIGH];    //WIDE和HIGH表示游戏界面的宽和高
	int size;
}snake;

3. 定义食物对象

struct FOOD {
    
    
	int X;    //表示食物的位置点
	int Y;
}food;

二、游戏初始化

1. 蛇初始化

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;

	return;
}

2. 食物初始化

void initFood(void) {
    
    
	food.X = rand() % WIDE;  
	food.Y = rand() % HIGH;  

	return;
}

3. 围墙初始化

//画墙
void initWall(void) {
    
    
	for (size_t i = 0; i <= HIGH; i++)
	{
    
    
		for (size_t j = 0; j <= WIDE; j++)
		{
    
    
			if (j == WIDE)
				cout << "|";
			else if (i == HIGH)
				cout << "_";
			else
				cout << " ";
		}
		cout << endl;
	}
}

4. 界面初始化

void initUI(void) {
    
    
	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 = lastX;
	coord.Y = lastY;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
	putchar(' ');

	//画食物
	coord.X = food.X;
	coord.Y = food.Y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
	putchar('#');
}

三、逻辑编程

1. 启动游戏

void playGame(void) {
    
    

	char key = 'd';

	//判断蛇撞墙
	while (snake.body[0].X >= 0 && snake.body[0].X < WIDE
		&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH) {
    
    
		initUI();  //更新蛇

		//接收用户按键输入
		if (_kbhit()) {
    
         //为真时,说明用户按下按键   _kbhit()不阻塞判断用户输入
			key = _getch();   //                         _getch()不回显读取一个字符
		}
		switch (key) {
    
    
		case 'w':	kx = 0;  ky = -1; break;
		case 's':	kx = 0;  ky = +1; break;
		case 'a':	kx = -1; ky = 0;  break;
		case 'd':	kx = +1; ky = 0;  break;
		default:	break;
		}

		//蛇头撞身体 蛇头==任一一节身体
		for (size_t i = 1; i < snake.size; i++)
		{
    
    
			if (snake.body[0].X == snake.body[i].X && snake.body[0].Y == snake.body[i].Y)
				return;    //游戏结束
		}
		//蛇头撞食物
		if (snake.body[0].X == food.X && snake.body[0].Y == food.Y) {
    
    
			initFood();     //食物消失		
			snake.size++;   //身体增长
			score += 10;    //加分
			sleepSecond -= 25;//加速
		}

		//存储蛇尾坐标
		lastX = snake.body[snake.size - 1].X;
		lastY = snake.body[snake.size - 1].Y;

		//蛇移动,前一节身体给后一节身体赋值
		for (size_t k = snake.size - 1; k > 0; k--)
		{
    
    
			snake.body[k].X = snake.body[k - 1].X;
			snake.body[k].Y = snake.body[k - 1].Y;
		}

		snake.body[0].X += kx;   //蛇头坐标根据用户按键 修改
		snake.body[0].Y += ky;

		Sleep(sleepSecond);
	}
	return;
}

2. 打印成绩

void showScore(void) {
    
    
	//将光标默认位置移动至 不干扰游戏的位置
	COORD coord;
	coord.X = 0;
	coord.Y = HIGH + 2;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);

	cout << "Game Over!!!" << endl;
	cout << "成绩为:" << score << endl<<endl<<endl;
}

3. main函数

int main(void) {
    
    
	//去除光标
	CONSOLE_CURSOR_INFO cci;
	cci.dwSize = sizeof(cci);
	cci.bVisible = FALSE;  //设置为false则光标不可见
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);

	srand(time(NULL));  //播种随机数种子
	initWall();      //画墙
	initSnake();   //初始化蛇
	initFood();    //初始化食物
	initUI();      //画蛇和食物
	playGame();   //启动游戏

	showScore();  //打印分数
	system("pause");
	return 0;
}

四、细节处理

在该游戏的制作过程中,有以下几个方面的细节处理:

  • 1. 绘画问题
    每绘画蛇和食物图像时,都需要将光标移动到指定地方才能成功绘画。
    COORD 为光标移动处理结果体
COORD coord;
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
  • 2. 去除光标闪烁问题
    CONSOLE_CURSOR_INFO 为光标显示处理结构体
CONSOLE_CURSOR_INFO cci;    
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE;  //设置为false则光标不可见
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
  • 3. 蛇尾隐藏
    蛇每吃掉一块食物,蛇身便会增长一节,急需对蛇尾做隐藏处理
//存储蛇尾坐标
lastX = snake.body[snake.size - 1].X;
lastY = snake.body[snake.size - 1].Y;

coord.X = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); //移动光标
putchar(' '); //用“ ”覆盖蛇尾
  • 4. 接收用户按键输入
    _kbhit()不阻塞判断用户输入
    _getch()不回显读取一个字符
if (_kbhit()) {
    
         //为真时,说明用户按下按键   
	key = _getch();                         
}
  • 5. 延迟
    若不对移动时进行Sleep处理,则蛇移动速度飞快,游戏一下就结束了。
Sleep(sleepSecond);

五、程序源码

若需程序源码可留言邮箱至评论区或直接私信 即可。

猜你喜欢

转载自blog.csdn.net/Dustinthewine/article/details/129407825