• 纯C语言编写贪吃蛇(附源码,无EasyX、MFC)


           大一下学期,我所选的C语言工程实践是写一个贪吃蛇游戏。那几天真的挺肝的,完成本专业的答辩之后就没怎么动过这程序了。那时候写的贪吃蛇,还有一个栈溢出的问题没有解决,是因为当时所学知识有限,还没想到较好的解决方法。现在大二上学期,在上了好几节数据结构之后,对栈有了一定的了解,随着对栈的学习,我想出了解决我写的贪吃蛇栈溢出的办法。其实是前两天刚刚有这个想法,刚刚才测试并实现了,办法可行。现在我加入了计算机学院的创新开放实验室,打算做的一个项目是微信小程序。以后想记录一下我的开发过程和一些经历,又刚刚完善好贪吃蛇的代码,就简单记录一下吧。
           因为代码比较长,先把参考资料写一下,想自己手写一遍的建议先看参考资料,再看这里的代码

    参考资料

    [1] C语言如何编写贪吃蛇小游戏基础_百度经验:
    https://jingyan.baidu.com/article/e9fb46e14624487520f76658.html
    [2] C语言学习:三天写好贪吃蛇小游戏(一):
    http://baijiahao.baidu.com/s?id=1600645476423742053&wfr=spider&for=pc
    [3] C语言学习:三天写好贪吃蛇小游戏(二):
    http://baijiahao.baidu.com/s?id=1600729030233953401&wfr=spider&for=pc
    [4] C语言学习:三天写好贪吃蛇小游戏(三):
    http://baijiahao.baidu.com/s?id=1600902215143197241&wfr=spider&for=pc
    [5] 用C语言实现一个贪吃蛇游戏 - Calm的博客 - CSDN博客:
    https://blog.csdn.net/huaijiu123/article/details/82054208
    [6] 谁能解释一下 HANDLE hConsole =GetStdHandle((STD_OUTPUT_HANDLE))在C语言中是什么意思_百度知道:
    https://zhidao.baidu.com/question/529197139.html
    [7] 纯C语言实现贪吃蛇游戏(VC6.0) - CSDN博客:
    https://blog.csdn.net/gin1008/app/article/details/52781106
    [8] 在c语言中怎么实现输入esc退出 其他键继续_百度知道:
    https://zhidao.baidu.com/question/403428708.html

    源代码

    /*预处理*/
    #include <windows.h>
    #include <stdio.h>
    #include <conio.h>
    #include <string.h>
    #include <time.h>
    
    /*宏定义*/
    #define YES 1
    #define NO 0
    			//蛇的移动方向
    #define U 1	//上
    #define D 2	//下
    #define L 3	//左
    #define R 4	//右
    #define RESPEED 250	//蛇的移动速度
    
    /*定义节点*/
    typedef struct SNAKE
    {
    	int x;
    	int y;
    	struct SNAKE* next;
    }snake;
    
    /*全局变量*/
    snake* head, * food;	//蛇头指针,食物指针
    snake* q;	//遍历蛇的时候用到的指针
    
    /*【以下为所有函数的声明】*/
    void HideCursor(void);	//隐藏光标
    void color(short int num);	//颜色函数
    void StartWindow(void);	//开始界面
    int gotoxy(int x, int y);	//定位光标位置
    void creatMap(void);	//创建地图
    void notice(int* score, int* highscore, int* Time, int* LongTime);	//提示
    void initsnake(void);	//初始化蛇身 
    int biteself(unsigned long* sleeptime);	//判断是否咬到了自己
    int createfood(void);	//随机出现食物
    void endgame(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime);	//结束游戏
    void pause(int* PauseBegin, int* PauseEnd);	//暂停游戏
    
    void gamecontrol(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
    	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd);	//控制游戏(包含蛇不能穿墙)
    
    void snakemove(unsigned long* sleeptime, int* count, int* score, int* status, int* endgamestatus);	//蛇移动
    void gamestart(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime, int* TimeBegin);	//游戏初始化
    
    void gamecontinue(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
    	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd);	//再来一局
    
    void stop(unsigned long* sleeptime);	//蛇停止移动
    void start(unsigned long* sleeptime);	//蛇恢复移动
    void reset(int* count, int* score, int* Time, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd);	//重置多项数据
    void updatescore(int* score, int* highscore, int* Time, int* LongTime);	//更新多项数据
    
    int main(void)
    {
    	unsigned long sleeptime = RESPEED;
    	int score = 0, highscore = 0, count = 0;	//count是记录吃到食物的次数
    	int status, endgamestatus = 0;	//游戏结束情况,0未开始游戏前退出,1撞到墙,2咬到自己,3主动退出游戏,4通关
    	int TimeBegin, TimeEnd;
    	int Time, LongTime, TimePause, PauseBegin, PauseEnd;
    
    	Time = LongTime = TimePause = PauseBegin = PauseEnd = 0;
    
    	HideCursor();
    	gamestart(&score, &highscore, &endgamestatus, &Time, &LongTime, &TimeBegin);
    	gamecontrol(&sleeptime, &count, &score, &highscore, &status, &endgamestatus, &Time, &LongTime, &TimeBegin, &TimeEnd, &TimePause, &PauseBegin, &PauseEnd);
    	endgame(&score, &highscore, &endgamestatus, &Time, &LongTime);
    	gamecontinue(&sleeptime, &count, &score, &highscore, &status, &endgamestatus, &Time, &LongTime, &TimeBegin, &TimeEnd, &TimePause, &PauseBegin, &PauseEnd);
    
    	return 0;
    }
    
    void HideCursor(void)	//隐藏光标
    {
    	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
    	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
    }
    
    void color(short int num)
    {
    	HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE));
    	SetConsoleTextAttribute(hConsole, num);
    }
    
    void StartWindow(void)
    {
    	short int i;
    
    	system("mode con cols=120 lines=30");	//设置窗口大小
    
    	printf("温馨提示:请使用键盘操作(鼠标点击可能会导致程序出错)
    ");
    	printf("╔═══════════════════════════════════════════════════╗ 
    ");
    	for (i = 0; i < 26; i++)
    	{
    		printf("║						  ║ 
    ");
    	}
    	printf("╚═══════════════════════════════════════════════════╝ 
    ");
    	gotoxy(23, 2);
    	color(3);
    	printf("贪吃蛇");
    	for (i = 15; ; i--)
    	{
    		gotoxy(18, 4);
    		color(i);
    		printf("按任意键加载程序");
    		Sleep(600);
    		if (i == 1)
    		{
    			i = 15;
    		}
    		if (kbhit())	//判断是否按键,等待输入按键为0,按键为1
    		{
    			break;
    		}
    	}
    	gotoxy(10, 4);
    	printf("1.开始游戏          2.退出游戏");
    	getch();
    }
    
    int gotoxy(int x, int y)
    {
    	HANDLE handle;	//定义句柄变量handle,创建一个句柄
    	COORD pos;	//定义结构体coord (坐标系coord)
    	pos.X = x;	//横坐标x
    	pos.Y = y;	//纵坐标y
    	handle = GetStdHandle(STD_OUTPUT_HANDLE);	//获取控制台输出句柄(值为-11)
    	SetConsoleCursorPosition(handle, pos);	//移动光标
    	return YES;
    }
    
    void creatMap(void)
    {
    	int i;
    	//地图大小:长24×宽20
    	for (i = 2; i < 52; i += 2)	//打印上下边框
    	{
    		color(195);
    		gotoxy(i, 6);
    		printf("■");
    		gotoxy(i, 27);
    		printf("■");
    	}
    	for (i = 7; i < 28; i++)	//打印左右边框
    	{
    		gotoxy(2, i);
    		printf("■");
    		gotoxy(50, i);
    		printf("■");
    	}
    }
    
    void notice(int* score, int* highscore, int* Time, int* LongTime)
    {
    	system("title 2018051170 Project:贪吃蛇");
    	gotoxy(4, 4);
    	color(15);
    	printf("得分:%3d 最高分:%3d 生存:%4ds 最久生存:%4ds", *score, *highscore, *Time, *LongTime);
    	gotoxy(60, 7);
    	printf("Author: 2018051170 Project: 贪吃蛇");
    	gotoxy(60, 9);
    	printf("游戏说明:");
    	gotoxy(60, 10);
    	printf("不能穿墙,不能咬到自己");
    	gotoxy(60, 11);
    	printf("↑ ↓ ← →控制蛇的移动");
    	gotoxy(60, 12);
    	printf("ESC:退出游戏	空格:暂停游戏");
    }
    
    void initsnake(void)
    {
    	int i;
    	snake* tail;
    
    	tail = (snake*)malloc(sizeof(snake));	//从蛇尾开始,插头法,以x,y设定开始的位置 
    	tail->x = 26;
    	tail->y = 14;
    	tail->next = NULL;
    	for (i = 1; i < 3; i++)
    	{
    		head = (snake*)malloc(sizeof(snake));
    		head->next = tail;
    		head->x = 26 - 2 * i;
    		head->y = 14;
    		tail = head;
    	}
    	while (tail != NULL)	//从头到为,输出蛇身
    	{
    		gotoxy(tail->x, tail->y);
    		if (i == 3)
    		{
    			color(2);
    			printf("●");
    			i++;
    		}
    
    		else if (tail != NULL)
    		{
    			color(2);
    			printf("■");
    		}
    		tail = tail->next;
    	}
    }
    
    int biteself(unsigned long* sleeptime)
    {
    	snake* self;
    
    	self = head->next;
    	while (self != NULL)
    	{
    		if (self->x == head->x && self->y == head->y)
    		{
    			stop(sleeptime);
    			return YES;
    		}
    		self = self->next;
    	}
    	return NO;
    }
    
    int createfood(void)
    {
    	snake* food_1;
    
    	food_1 = (snake*)malloc(sizeof(snake));
    	srand((unsigned)time(NULL));	//产生一个随机数
    
    	while ((food_1->x % 2) != 0)	//保证其为偶数,使得食物能与蛇头对其
    	{
    		food_1->x = rand() % 50;	//保证其在墙壁里X1 < X < X2
    		if (food_1->x <= 4)
    		{
    			food_1->x = food_1->x + 4;
    		}
    	}
    	food_1->y = rand() % 27;	//保证其在墙壁里Y1 < Y < Y2
    	if (food_1->y < 7)
    	{
    		food_1->y = food_1->y + 7;
    	}
    	q = head;
    
    	while (q != NULL)	//判断蛇身是否与食物重合
    	{
    		if (q->x == food_1->x && q->y == food_1->y)
    		{
    			free(food_1);
    			return 1;
    		}
    
    		if (q->next == NULL)
    		{
    			break;
    		}
    		q = q->next;
    	}
    
    	gotoxy(food_1->x, food_1->y);
    	food = food_1;
    	color(3);
    	printf("★");
    	return 0;
    }
    
    void endgame(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime)
    {
    	color(15);
    	gotoxy(60, 14);
    	if (*endgamestatus == 0)
    	{
    		printf("您退出了游戏。");
    	}
    	else
    	{
    		if (*endgamestatus == 1)
    		{
    			printf("您撞到墙了,游戏结束。");
    		}
    		else if (*endgamestatus == 2)
    		{
    			printf("您咬到自己了,游戏结束。");
    		}
    		else if (*endgamestatus == 3)
    		{
    			printf("您已经结束了游戏。");
    		}
    		else if (*endgamestatus == 4)
    		{
    			printf("恭喜您通关了游戏!");
    		}
    		gotoxy(60, 15);
    		printf("您的得分是: %d", *score);
    		updatescore(score, highscore, Time, LongTime);
    	}
    }
    
    void pause(int* PauseBegin, int* PauseEnd)
    {
    	*PauseBegin = time(NULL);
    	while (1)
    	{
    		Sleep(300);
    		if (GetAsyncKeyState(VK_SPACE))
    		{
    			*PauseEnd = time(NULL);
    			break;
    		}
    	}
    }
    
    void gamecontrol(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
    	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd)
    {
    	*status = L;
    	while (1)
    	{
    		*TimeEnd = time(NULL);
    		*TimePause = *TimePause + *PauseEnd - *PauseBegin;
    		*PauseBegin = *PauseEnd = 0;
    		*Time = *TimeEnd - *TimeBegin - *TimePause;
    
    		//实时更新得分
    		gotoxy(4, 4);
    		color(15);
    		printf("得分:%3d 最高分:%3d 生存:%4ds 最久生存:%4ds", *score, *highscore, *Time, *LongTime);
    
    		//如果撞墙,停止蛇的移动
    		if (head->x == 2 || head->x == 50 || head->y == 6 || head->y == 27)
    		{
    			stop(sleeptime);
    			*endgamestatus = 1;
    			break;
    		}
    		//如果咬到自己(在biteself函数里停止蛇的移动)
    		if (biteself(sleeptime) == 1)
    		{
    			*endgamestatus = 2;
    			break;
    		}
    		//如果通关
    		if (*endgamestatus == 4)
    		{
    			break;
    		}
    		//读取到【↑】且蛇头指向不为【↓】
    		if (GetAsyncKeyState(VK_UP) && *status != D)
    		{
    			*status = U;
    		}
    		//读取到【↓】且蛇头指向不为【↑】
    		else if (GetAsyncKeyState(VK_DOWN) && *status != U)
    		{
    			*status = D;
    		}
    		//读取到【←】且蛇头指向不为【→】
    		else if (GetAsyncKeyState(VK_LEFT) && *status != R)
    		{
    			*status = L;
    		}
    		//读取到【→】且蛇头指向不为【←】
    		else if (GetAsyncKeyState(VK_RIGHT) && *status != L)
    		{
    			*status = R;
    		}
    		else if (GetAsyncKeyState(VK_SPACE))	//读取到【空格】
    		{
    			pause(PauseBegin, PauseEnd);
    		}
    		else if (GetAsyncKeyState(VK_ESCAPE))	//读取到【ESC】
    		{
    			stop(sleeptime);
    			*endgamestatus = 3;
    			break;
    		}
    
    		Sleep(*sleeptime);
    		snakemove(sleeptime, count, score, status, endgamestatus);
    	}
    }
    
    void snakemove(unsigned long* sleeptime, int* count, int* score, int* status, int* endgamestatus)
    {
    	int i = 0, flag = 1;
    	snake* nexthead;
    	nexthead = (snake*)malloc(sizeof(snake));
    
    	if (*count == 477)
    	{
    		stop(sleeptime);
    		*endgamestatus = 4;
    	}
    	else
    	{
    		if (*status == U)
    		{
    			nexthead->x = head->x;
    			nexthead->y = head->y - 1;
    			if (nexthead->x == food->x && nexthead->y == food->y) //如果前面有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				(*score)++;
    				(*count)++;
    				if (*count != 477)
    				{
    					while (flag)
    					{
    						flag = createfood();
    					}
    				}
    			}
    			else	//如果没有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q->next->next != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				gotoxy(q->next->x, q->next->y);
    				color(0);
    				printf("  ");
    				free(q->next);
    				q->next = NULL;
    			}
    		}
    		if (*status == D)
    		{
    			nexthead->x = head->x;
    			nexthead->y = head->y + 1;
    			if (nexthead->x == food->x && nexthead->y == food->y)	//如果前面有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				(*score)++;
    				(*count)++;
    				if (*count != 477)
    				{
    					while (flag)
    					{
    						flag = createfood();
    					}
    				}
    			}
    			else	//如果没有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q->next->next != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				gotoxy(q->next->x, q->next->y);
    				color(0);
    				printf("  ");
    				free(q->next);
    				q->next = NULL;
    			}
    		}
    		if (*status == L)
    		{
    			nexthead->x = head->x - 2;
    			nexthead->y = head->y;
    			if (nexthead->x == food->x && nexthead->y == food->y)	//如果前面有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				(*score)++;
    				(*count)++;
    				if (*count != 477)
    				{
    					while (flag)
    					{
    						flag = createfood();
    					}
    				}
    			}
    			else	//如果没有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q->next->next != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				gotoxy(q->next->x, q->next->y);
    				color(0);
    				printf("  ");
    				free(q->next);
    				q->next = NULL;
    			}
    		}
    		if (*status == R)
    		{
    			nexthead->x = head->x + 2;
    			nexthead->y = head->y;
    			if (nexthead->x == food->x && nexthead->y == food->y)	//如果前面有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				(*score)++;
    				(*count)++;
    				if (*count != 477)
    				{
    					while (flag)
    					{
    						flag = createfood();
    					}
    				}
    			}
    			else	//如果没有食物
    			{
    				nexthead->next = head;
    				head = nexthead;
    				q = head;
    				while (q->next->next != NULL)
    				{
    					gotoxy(q->x, q->y);
    					if (i == 0)
    					{
    						color(2);
    						printf("●");
    						i++;
    					}
    					else
    					{
    						color(2);
    						printf("■");
    					}
    					q = q->next;
    				}
    				gotoxy(q->next->x, q->next->y);
    				color(0);
    				printf("  ");
    				free(q->next);
    				q->next = NULL;
    			}
    		}
    	}
    }
    
    void gamestart(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime, int* TimeBegin)
    {
    	int tmp, flag = 1;
    
    	StartWindow();
    	while (1)
    	{
    		tmp = getch();
    		if (tmp == 50)	//数字2的键码值为50
    		{
    			endgame(score, highscore, endgamestatus, Time, LongTime);
    			exit(0);
    		}
    		else if (tmp == 49)	//数字1的键码值为49
    		{
    			break;
    		}
    	}
    	creatMap();
    	notice(score, highscore, Time, LongTime);
    	initsnake();
    	while (flag)
    	{
    		flag = createfood();
    	}
    	*TimeBegin = time(NULL);	//开始程序计时
    }
    
    void gamecontinue(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
    	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd)
    {
    	char note[4];
    
    	gotoxy(60, 16);
    	printf("再来一局?(yes or 任意其他字符)");
    	gets(note);
    	if (strcmp(note, "yes") == 0)
    	{
    		system("cls");
    		start(sleeptime);
    		reset(count, score, Time, TimeBegin, TimeEnd, TimePause, PauseBegin, PauseEnd);
    		gamestart(score, highscore, endgamestatus, Time, LongTime, TimeBegin);
    		gamecontrol(sleeptime, count, score, highscore, status, endgamestatus, Time, LongTime, TimeBegin, TimeEnd, TimePause, PauseBegin, PauseEnd);
    		endgame(score, highscore, endgamestatus, Time, LongTime);
    		gamecontinue(sleeptime, count, score, highscore, status, endgamestatus, Time, LongTime, TimeBegin, TimeEnd, TimePause, PauseBegin, PauseEnd);
    	}
    	else
    	{
    		gotoxy(60, 17);
    		printf("您已经结束了游戏。");
    	}
    }
    
    void stop(unsigned long* sleeptime)
    {
    	*sleeptime = 1000000000;
    }
    
    void start(unsigned long* sleeptime)
    {
    	*sleeptime = RESPEED;
    }
    
    void reset(int* count, int* score, int* Time, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd)
    {
    	*score = *count = *Time = *TimeBegin = *TimeEnd = *TimePause = *PauseBegin = *PauseEnd = 0;
    }
    
    void updatescore(int* score, int* highscore, int* Time, int* LongTime)
    {
    	if (*score > * highscore)
    	{
    		*highscore = *score;
    	}
    	if (*Time > * LongTime)
    	{
    		*LongTime = *Time;
    	}
    }
    
  • 相关阅读:
    mysql alter table时的表锁是mysql服务层加的还是存储引擎加的
    show databases in redis
    Docker-compose中的使用技巧
    debian切换源
    C# MVC(File)控件多张图片上传加预览
    C# DateTime日期格式化
    DropDownList的使用,RadioButtonList的使用
    access数据库连接问题
    动态获取ul,li的数据
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/ast935478677/p/13157058.html
Copyright © 2020-2023  润新知