首页 > 其他分享 >【C语言】贪吃蛇

【C语言】贪吃蛇

时间:2024-04-07 20:01:43浏览次数:22  
标签:body int void coord C语言 贪吃蛇 snake size

【C语言】贪吃蛇

文章目录


前言

相信大家都知道贪吃蛇这款游戏,它是一款经典的手机游戏。通过控制蛇头方向吃食物,使得蛇变长,从而获得积分,既简单又耐玩。通过上下左右键控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,分数越高蛇的速度越快。现在让我们通过C语言来实现贪吃蛇的代码吧。


模块描述

蛇的初始化
蛇的初始化实际就是二维数组的初始化,该二维数组存储两个值,里面包含该蛇身体的坐标信息,它出现的初始位置是横纵坐标的中间位置。

蛇的移动
蛇的移动是通改变二维数组坐标位置来实现的,例如当蛇向右前进一个单位,则将尾每一个身体位置的坐标更改,同时改变蛇头、蛇身以及蛇尾的方向。这样整体来看来蛇就前进了一个单位。

蛇的增长
当蛇吃了正常食物后,蛇的长度会增加。

蛇的死亡
当蛇撞上障碍物、自身或者时,蛇会死亡,游戏结束。

食物的产生
食物出现的位置产生都是随机的,这些因素由通过随机函数获取的随机数决定。食物的位置不能出现在障碍物和边界上。

控制键盘输入
通过获取键盘输入的W/w(上)、 S/s(下)、 A/a(左)、 D/d(右)来改变蛇模块中移动方向,从而影响蛇的移动方向。


效果展示

在这里插入图片描述在这里插入图片描述

完整代码

snake.h

#pragma once

#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>

#define WIDE 60		//宽度
#define HIGH 20		//高度

struct BODY {
	int X;
	int Y;
};			//一个身体的坐标
struct SNAKE {
	struct BODY body[WIDE * HIGH];		//蛇身体的上限,铺满整个空间。
	int size;							//蛇的大小
}snake;									//全局蛇变量

struct FOOD {
	int X;
	int Y;
}food;									//全局食物变量

int score = 0;			//分数
int dx = 0;				//用户按下 adws任意一个按键所得到的 坐标值。
int dy = 0;

int lastX = 0;			//蛇尾的坐标
int lastY = 0;

int count = 0;			//吃食物的次数

int sleepSecond = 300;

//声明函数
void initSnake(void);
void initFood(void);
void initUI(void);
void playGame(void);
void initWall(void);
void showScore(void);

main.h

#include "snake.h"		// 引入自定义头文件

int main()
{
	//去除光标
	CONSOLE_CURSOR_INFO cci;
	cci.dwSize = sizeof(cci);
	cci.bVisible = FALSE;	//0
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
	
	srand((unsigned int)time(NULL));		//播种随机数种子

	initSnake();			//初始化蛇
	initFood();				//初始化食物

	initWall();				//画墙 
	initUI();				//画蛇和食物

	playGame();				//启动游戏

	showScore();			//打印分数

	system("pause");
	return 0;
}

//初始化蛇
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;
}

//初始化食物
void initFood(void)
{
	food.X = rand() % WIDE;
	food.Y = rand() % HIGH;

	return;
}

//画墙
void initWall(void)
{
	for (size_t i = 0; i <= HIGH; i++)		//多行
	{
		for (size_t j = 0; j <= WIDE; j++)
		{
			if (j == WIDE)
			{
				putchar('|');
			}
			else if (i == HIGH)
			{
				putchar('_');
			}
			else
			{
				putchar(' ');
			}
		}
		printf("\n");
	}
}


//初始化界面控件
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('#');

}


//启动游戏
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();


		//接收用户按键 adws
		if (_kbhit()) {
			key = _getch();
		}

		switch (key)
		{
		case 'a': dx = -1; dy = 0;  break;
		case 'd': dx = 1;  dy = 0;  break;
		case 'w': dx = 0;  dy = -1; break;
		case 's': dx = 0;  dy = 1;  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;	//加分
			
			if (count <= 8)
			{
				sleepSecond -= 25;	//加速
			}
			count++;
		}

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

		//蛇移动,前一节身体给后一节身体赋值
		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 += dx;
		snake.body[0].Y += dy;

		Sleep(sleepSecond);
	}
}

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

	printf("Game Over!!!\n");
	printf("成绩为:%d\n\n\n", score);
}

代码拆分

定义蛇对象

蛇有身体和长度,通过结构体来储存相关信息。

#define WIDE 60		//宽度
#define HIGH 20		//高度
struct BODY {
	int X;
	int Y;
};			//一个身体的坐标
struct SNAKE {
	struct BODY body[WIDE * HIGH];		//蛇身体的上限,铺满整个空间。body[0]蛇头
	int size;							//蛇的大小
}snake;									//全局蛇变量


定义食物对象

struct FOOD {
	int X;
	int Y;
}food;									//全局食物变量

int score = 0;			//分数定义

初始化蛇对象

默认将蛇头位于空间中心,蛇头朝右。

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;
}

食物的初始化

食物在空间内的任意位置,用随机数生成。

#include <stdlib.h>
#include <time.h>
srand((unsigned int)time(NULL));		//播种随机数种子
void initFood(void)
{
	food.X = rand() % WIDE;
	food.Y = rand() % HIGH;

	return;
}

修改控制台光标位置

默认光标在起始位置,画蛇要现将光标移动到蛇头和蛇身的位置在将蛇头和蛇身打印到屏幕这里的蛇头用@蛇身用*,食物用#来表示。

需要函数:

SetConsoleCursorPosition函数:
包含头文件 : include<conio.h> <Windows.h>
typedef struct_COORD{
SHORT X; //x坐标
SHORT Y; //y坐标
}COORD; //COORD是Win对哦晚上API中定义的一种结构,表示一个字符在控制台屏幕上的坐标。
COORD coord;
coord.X=10;
coord.Y=20;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);


画蛇和食物

	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('#');

蛇移动控制基础知识

按 adws 来控制蛇移动方向,影响蛇头位置的变化:
W:(0,-1) S:(0,+1) A:(-1,0) D:(+1,0)
要将输入的 adws 不显示屏幕上且光标一直闪在需要函数:

getch() 无回显接收用户输入一个字符。
用法: char key = getch();
kbhit() 以非阻塞方式,检查当前是否有键盘输入。
用法:if(kbhit()){…}


游戏控制逻辑实现,接收键盘输入

判断蛇撞墙,撞上自己,吃到食物

//判断蛇撞墙
while (snakebody[0].X >= 0 && snake.body[0].X < WIDE
	&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH)
{
	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;	//加分
	}
}


蛇的移动控制

通过adws控制蛇移动,蛇头单独移动,蛇的每一个身体由前一节身体赋值。不按按键默认项右跑。改变后的坐标要重画一遍蛇,这样蛇才可以运动起来。更新的蛇都向前一个单位,要将之前的蛇尾位置的*消掉的用‘ ’代替。每次更新的间隔时间就是蛇运动的速度。用Sleep()函数处理。

//更新蛇
initUI();

int dx = 0;				//用户按下 adws任意一个按键所得到的 坐标值。
int dy = 0;

char key = 'd'; 	//初值
//接收用户按键 adws
if (_kbhit()) {
	key = _getch();
}
switch (key)
{
case 'a': dx = -1; dy = 0;  break;
case 'd': dx = 1;  dy = 0;  break;
case 'w': dx = 0;  dy = -1; break;
case 's': dx = 0;  dy = 1;  break;
default:  break;
}
//蛇移动,前一节身体给后一节身体赋值
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 += dx;		//蛇头改变
snake.body[0].Y += dy;
//储存蛇尾坐标
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(' ');


画墙

将边缘用 ‘|’ 和 ‘_’ 来占据空间其余的空间用 ‘ ’占据。

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

设置光标不可见

需要函数:

SetConsoleCursorInfo函数
CONSOLE_CURSOR_INFO 结构体,描述终端光标信息。包含两成员变量。
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(GetStdHandle(STD_OUTPUT_HANDLE), &cci);	//设置光标不可见生效,只需在main函数中调用一次

加速和显示成绩

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

	printf("Game Over!!!\n");
	printf("成绩为:%d\n\n\n", score);
}

吃到8个食物后速度达到最大值

int sleepSecond = 300;
int count = 0;			//吃食物的次数
if (count <= 8)
{
	sleepSecond -= 25;	//加速
}
count++;
Sleep(sleepSecond);

总结

以上贪吃蛇的基本规则算是完成了。每一个项目,在实现之前都要进行分析设计,项目整体要实现哪些功能。将这些功能划分成不同的模块,如果模块较大还可以在内部划分成更小的功能模块。这样逐个实现每个模块,条理清晰。在实现各个模块后,需要将模块整合,使各个功能协调有序的进行。在进行模块划分和模块整合时,可以使用流程图来表示模块之间的联系与运行流程。

标签:body,int,void,coord,C语言,贪吃蛇,snake,size
From: https://blog.csdn.net/2301_80035097/article/details/137285083

相关文章

  • 每日一题:C语言经典例题之小球蹦蹦跳跳
    题目描述调皮的小明将皮球从100m的高度自由落下,每次落地后反弹回原高度的一半,再落下,再反弹。求它在第N次落地时,共经过了多少米,第N次反弹多高。输入一个正整数N,表示球落地的次数。输出 length=球第N次落地时所经过了距离high=球第N次落地反弹的高度小数点后保留4位......
  • C语言文件操作
    本篇文章从文件是什么,为什么使用文件,到怎么使用文件来介绍文件。一.文件是什么?磁盘(硬盘)上的文件是文件。但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。1.文件名文件名包含3部分:文件路径+文件名主干+文件按后缀。2.程序文件程序......
  • C语言游戏实战(11):贪吃蛇大作战(多人对战)
         成果展示:贪吃蛇(多人对战) 前言:这款贪吃蛇大作战是一款多人游戏,玩家需要控制一条蛇在地图上移动,吞噬其他蛇或者食物来增大自己的蛇身长度和宽度。本游戏使用C语言和easyx图形库编写,旨在帮助初学者了解游戏开发的基本概念和技巧。在开始编写代码之前,我们需要先......
  • C语言05-(跳转控制语句、断点调试)
    8.3跳转控制语句①break在switchcase结构中使用:跳出所在的case在循环结构(dowhile、while、for)中使用:跳出整个循环,循环结束注:跳出所在的循环!②continue在循环结构(dowhile、while、for)中使用:跳出本次循环,下次继续注:跳出所在的循环!③goto1.使用goto......
  • c语言程序实验————实验报告四
    c语言程序实验————实验报告四实验项目名称:实验报告2数据描述实验项目类型:验证性实验日期:2024年3月21日一、实验目的1.在熟练掌握if语句和switch语句的基础上,能灵活使用if语句和switch语句进行选择结构的程序设计2.学习调试程序二、实验硬、软件环境Windows计......
  • C语言高效的网络爬虫:实现对新闻网站的全面爬取
    1.背景搜狐是一个拥有丰富新闻内容的网站,我们希望能够通过网络爬虫系统,将其各类新闻内容进行全面地获取和分析。为了实现这一目标,我们将采用C语言编写网络爬虫程序,通过该程序实现对news.sohu.com的自动化访问和数据提取。2.网络爬虫系统设计2.1网络请求与响应处理......
  • C语言--指针终章
     目录 1.sizeof和strlen的对⽐1.1sizeof1.2strlen1.3sizeof和strlen的对⽐ 2.数组和指针的理解——题目理解2.1.sizeof代码1:代码2:代码3:代码4:代码5(二维数组):2.2:strlen代码1:代码2: 代码3:代码4(模拟实现strlen的三种方式):冰冻三尺,非一日之寒1.siz......
  • C语言完结篇(17)
    编译和链接1.翻译环境和运⾏环境2.翻译环境:预编译+编译+汇编+链接我们知道计算机能够执行的是二进制的指令而我们的C语言代码都是文本信息所以我们需要让C语言代码转变为二进制的指令(这是需要编译器来进行处理的)翻译环境和运⾏环境在ANSIC的任何⼀种实现中,存在......
  • 中国电子学会(CEIT)2021年12月真题C语言软件编程等级考试四级(含详细解析答案)
    中国电子学会(CEIT)考评中心历届真题(含解析答案)C语言软件编程等级考试四级2021年12月编程题五道 总分:100分一、移动路线(25分)桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格......
  • 【C语言】:自定义类型__结构体
    这里写目录标题1、结构体的声明1.1结构体的声明1.2特殊的声明2、结构体变量的定义和初始化3、结构的自引用4、结构体内存对齐4.1结构体内存的对齐规则4.2为什么存在内存对齐4.3修改默认对齐数5、结构体传参6、结构体实现位段6.1什么是位段6.2位段的内存分配6.3......