【C语言项目】贪吃蛇(下)

【C语言项目】贪吃蛇(下)

码农世界 2024-05-16 前端 70 次浏览 0个评论

个人主页~

源码在Gitee仓库~

上一篇贪吃蛇(上)~


贪吃蛇

  • 四、核心的实现
    • 游戏测试
    • 1、GameStart
      • (1)控制台窗口大小和名字设置
      • (2)光标隐藏
      • (3)打印欢迎界面
      • (4)创建地图
      • (5)初始化蛇
      • (6)创建第一个食物
      • 最终的GameStart
      • 2、GameRun
        • (1)定义一个宏来检测按键状态
        • (2)PrintHelpInfo
        • (3)SnakeMove
        • (4)NextIsFood
        • (5)EatFood
        • (6)NoFood
        • (7)KillBySelf
        • (8)KillByWall
        • 最终的GameRun
        • 3、GameEnd
        • 五、源代码拷贝
          • Snake.h
          • Snake.c
          • game.h
          • 实际运行

            四、核心的实现

            游戏测试

            #include 
            void test()
            {
                int ch = 0;
                srand((unsigned int)time(NULL));//时间戳,用来实现随机数
                do
                {
                    Snake snake = { 0 };
                    GameStart(&snake);
             
                    GameRun(&snake);
             
                    GameEnd(&snake);
             
                    SetPos(20, 15);
                    printf("再来⼀局吗?(Y/N):");
                    ch = getchar();
                    getchar();
                } while (ch == 'Y');
                SetPos(0, 27);
               }
            int main()
            {
                //修改当前地区为本地模式,为了⽀持中⽂宽字符的打印
                setlocale(LC_ALL, "");
                //测试逻辑
                test();
                return 0;
            }
            

            1、GameStart

            (1)控制台窗口大小和名字设置

            system("mode con cols=100 lines=30");
            system("title 贪吃蛇");
            

            (2)光标隐藏

            	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
            	CONSOLE_CURSOR_INFO CursorInfo;
            	GetConsoleCursorInfo(houtput, &CursorInfo);
            	CursorInfo.bVisible = false;
            	SetConsoleCursorInfo(houtput, &CursorInfo);
            

            (3)打印欢迎界面

            void WelcomeToGame()
            {
                SetPos(40, 15);
                printf("欢迎来到贪吃蛇⼩游戏");
                SetPos(40, 25);// “按任意键继续”的出现的位置
                system("pause");//可以让页面暂停在这个位置,直到用户按下一个键
                system("cls");//清除屏幕
                SetPos(25, 12);
                printf("⽤ ↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
                SetPos(25, 13);
                printf("加速将能得到更⾼的分数。\n");
                SetPos(40, 25);
                // “按任意键继续”的出现的位置,这里可以让文字出现的位置看起来比较美观
                system("pause");
                system("cls");
            }
            

            (4)创建地图

            组成地图的小格子需要用宽字符打印

            58行就打印29次

            #define WALL L'□'  
            //在头文件中定义
            void CreateMap()
            {
            	//上
            	int i = 0;
            	for (i = 0; i < 29; i++)
            	{
            		wprintf(L"%lc", WALL);
            	}
            	//下
            	SetPos(0, 26);
            	for (i = 0; i < 29; i++)
            	{
            		wprintf(L"%lc", WALL);
            	}
            	//左
            	for (i = 1; i <= 25; i++)
            	{
            		SetPos(0, i);
            		wprintf(L"%lc", WALL);
            	}
            	//右
            	for (i = 1; i <= 25; i++)
            	{
            		SetPos(56, i);
            		wprintf(L"%lc", WALL);
            	}
            }
            

            (5)初始化蛇

            void InitSnake(pSnake ps)
            {
            	int i = 0;
            	pSnakeNode cur = NULL;
            	for (i = 0; i < 5; i++)
            	{
            		cur = (pSnakeNode)malloc(sizeof(SnakeNode));//创建蛇身节点
            		if (cur == NULL)
            		{
            			perror("malloc fail");
            			exit(1);
            		}
            		cur->next = NULL;
            		cur->x = POS_X + 2 * i;//将蛇的节点由蛇尾到蛇头创建好
            		cur->y = POS_Y;
            		if (ps->_pSnake == NULL)
            		{
            			ps->_pSnake = cur;//若没有蛇身节点则建立的节点为蛇身节点
            		}
            		else
            		{
            			cur->next = ps->_pSnake;
            			ps->_pSnake = cur;//若有蛇身节点则新创建的节点成为头节点
            		}
            	}
            	cur = ps->_pSnake;
            	while (cur)
            	{
            		SetPos(cur->x, cur->y);
            		wprintf(L"%lc", BODY);//将蛇的身体依据链表打印出来
            		cur = cur->next;
            	}
            	ps->_dir = RIGHT;//初始蛇的方向
            	ps->_food_weight = 10;//每个食物的分数
            	ps->_sleep_time = 200;//每两次打印蛇身的间隔,也就是蛇身的速度
            	ps->_sorce = 0;//初始总分数
            	ps->_status = OK;//蛇的初始状态
            }
            

            (6)创建第一个食物

            void CreateFood(pSnake ps)
            {
            	int x = 0;
            	int y = 0;
            again:	
            	do
            	{
            		x = rand() % 53 + 2;//我们要的x坐标值介于2~54间,任意数%53得到的值介于0~52,加上2就在2~56范围
            		y = rand() % 25 + 1;//我们要的y坐标值介于1~25间,任意数%25得到的值介于0~24,加上1就在1~25范围
            		//随机数时间戳,根据时间计算的数据,由于时间是不可修改切没有相同时候的,所以它产生的数字被认为是随机数
            	} while (x % 2 != 0);
            	pSnakeNode cur = ps->_pSnake;//记录蛇头结点
            	while (cur)
            	{
            		if (x == cur->x && y == cur->y)
            		{
            			goto again;
            		}
            		cur = cur->next;
            	}//如果食物与蛇身上某一节点重合了,则回到again处重新生成
            	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));//不重合就生成食物
            	if (pFood == NULL)
            	{
            		perror("malloc fail");
            		exit(2);
            	}
            	pFood->x = x;
            	pFood->y = y;
            	pFood->next = NULL;
            	SetPos(x, y);
            	wprintf(L"%lc", FOOD);//在对应位置处打印食物
            	ps->_pFood = pFood;
            }
            

            最终的GameStart

            void GameStart(pSnake ps)
            {
                //设置控制台窗⼝的⼤⼩,30⾏,100列
                //mode 为DOS命令
                system("mode con cols=100 lines=30");
                //设置cmd窗⼝名称
                system("title 贪吃蛇"); 
                //获取标准输出的句柄(⽤来标识不同设备的数值)
                HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                //影藏光标操作
                CONSOLE_CURSOR_INFO CursorInfo;
                //获取控制台光标信息
                GetConsoleCursorInfo(hOutput, &CursorInfo);
                //隐藏控制台光标
                CursorInfo.bVisible = false; 
                //设置控制台光标状态
                SetConsoleCursorInfo(hOutput, &CursorInfo);
                
                //打印欢迎界⾯
                WelcomeToGame();
                //打印地图
                CreateMap();
                //初始化蛇
                InitSnake(ps);
                //创造第⼀个⻝物
                CreateFood(ps);
            }
            

            2、GameRun

            (1)定义一个宏来检测按键状态

            #define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)
            

            在上一篇博文中我们介绍了GetAsyncKeyState函数,我们封装一个宏可以判断某个键是否被按下

            (2)PrintHelpInfo

            void PrintHelpInfo()
            {
            	SetPos(64, 14);
            	wprintf(L"%ls", L"不能穿墙,不能咬到自己");
            	SetPos(64, 16);
            	wprintf(L"%ls", L"用 ↑. ↓ . ← . → 来控制蛇的移动");
            	SetPos(64, 18);
            	wprintf(L"%ls", L"按F3加速,F4减速");
            	SetPos(64, 20);
            	wprintf(L"%ls", L"按ESC退出游戏,按空格暂停游戏");
            	SetPos(64, 24);
            	wprintf(L"%ls", L"s_little_monster_倾情制作");
            }
            

            (3)SnakeMove

            void SnakeMove(pSnake ps)
            {
            	pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));//开辟预测的下一个节点
            	if (pNextNode == NULL)
            	{
            		perror("malloc fail");
            		exit(3);
            	}
            	switch (ps->_dir)//用switch语句判断此时蛇的走向
            	{
            	case UP:
            		pNextNode->x = ps->_pSnake->x;
            		pNextNode->y = ps->_pSnake->y - 1;
            		break;
            	case DOWN:
            		pNextNode->x = ps->_pSnake->x;
            		pNextNode->y = ps->_pSnake->y + 1;
            		break;
            	case LEFT:
            		pNextNode->x = ps->_pSnake->x - 2;//注意左右移动是加减2
            		pNextNode->y = ps->_pSnake->y;
            		break;
            	case RIGHT:
            		pNextNode->x = ps->_pSnake->x + 2;
            		pNextNode->y = ps->_pSnake->y;
            		break;
            	}
            	if (NextIsFood(pNextNode, ps))
            	{
            		EatFood(pNextNode,ps);
            	}
            	else
            	{
            		NoFood(pNextNode, ps);
            	}
            	//判断下一个位置是否为食物,是则进入EatFood,不是则进入NoFood
            	KillBySelf(ps);
            	
            	KillByWall(ps);//检查是否撞到自己或墙而死亡
            }
            

            (4)NextIsFood

            int NextIsFood(pSnakeNode pn,pSnake ps)
            {
            	return (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y);
            	//如果当前位置是食物则返回非0值,不是返回0
            }
            

            (5)EatFood

            void EatFood(pSnakeNode pn, pSnake ps)
            {
            	ps->_pFood->next = ps->_pSnake;
            	ps->_pSnake = ps->_pFood;//吃掉食物,让食物成为蛇的头节点
            	free(pn);//因为节点pn与节点_pFood是一个节点,所以free掉其中的一个
            	pn = NULL;
            	pSnakeNode cur = ps->_pSnake;
            	while (cur)
            	{
            		SetPos(cur->x, cur->y);
            		wprintf(L"%lc", BODY);
            		cur = cur->next;
            	}//打印蛇身
            	ps->_sorce += ps->_food_weight;//加分
            	CreateFood(ps);//重新制造食物
            }
            

            (6)NoFood

            void NoFood(pSnakeNode pn, pSnake ps)
            {
            	pn->next = ps->_pSnake;
            	ps->_pSnake = pn;//同EatFood,将下一节点成为头结点
            	pSnakeNode cur = ps->_pSnake;
            	while (cur->next->next != NULL)
            	{
            		SetPos(cur->x, cur->y);
            		wprintf(L"%lc", BODY);
            		cur = cur->next;
            	}//将除了尾节点以外的节点打印
            	SetPos(cur->next->x, cur->next->y);
            	printf("  ");//将尾节点打印为空格
            	free(cur->next);//free掉尾节点
            	cur->next = NULL;
            }
            

            (7)KillBySelf

            void KillBySelf(pSnake ps)
            {
            	pSnakeNode pur = ps->_pSnake->next;
            	while (pur)
            	{
            		//当此时的蛇头位置与蛇身某一节点重合时
            		if (pur->x == ps->_pSnake->x && pur->y == ps->_pSnake->y)
            		{
            			ps->_status = KILL_BY_SELF;//修改状态为 KILL_BY_SELF
            			break;
            		}
            		pur = pur->next;
            	}
            }
            

            (8)KillByWall

            void KillByWall(pSnake ps)
            {
            	//当此时的蛇头位置与墙体重合时
            	if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 || ps->_pSnake->y == 0 || ps->_pSnake->y == 26)
            	{
            		ps->_status = KILL_BY_WALL;//修改状态为 KILL_BY_WALL
            	}
            }
            

            最终的GameRun

            void GameRun(pSnake ps)
            {
            	PrintHelpInfo();//游戏玩法帮助打印
            	do
            	{
            		SetPos(64, 10);
            		printf("总分数:%d\n", ps->_sorce);
            		SetPos(64, 11);
            		printf("当前食物的分数:%2d\n", ps->_food_weight);
            		//检测键是否被按下
            		if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
            		{
            			ps->_dir = UP;
            		}
            		else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
            		{
            			ps->_dir = DOWN;
            		}
            		else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
            		{
            			ps->_dir = LEFT;
            		}
            		else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
            		{
            			ps->_dir = RIGHT;
            		}
            		else if (KEY_PRESS(VK_SPACE))
            		{
            			Pause();//暂停,等待再按下空格继续
            		}
            		else if (KEY_PRESS(VK_ESCAPE))
            		{
            			ps->_status = END_NORMAL;
            		}
            		else if (KEY_PRESS(VK_F3))//F3为加速,休眠时间变少也就是蛇的速度变快,每个食物分数增加2
            		{
            			if(ps->_sleep_time > 80)//速度不能太快
            			{
            				ps->_sleep_time -= 30;
            				ps->_food_weight += 2;
            			}
            		}
            		else if (KEY_PRESS(VK_F4))//F4为减速,休眠时间变多也就是蛇的速度变慢,每个食物分数减少2
            		{
            			if(ps->_food_weight > 2)//食物分数要在2分以上
            			{
            				ps->_sleep_time += 30;
            				ps->_food_weight -= 2;
            			}
            		}
            		SnakeMove(ps);//蛇每走一步要进行的活动
            		Sleep(ps->_sleep_time);//走一步休眠的时间,也就是蛇的速度
            	} while (ps->_status == OK);//当游戏状态为OK时循环继续
            }
            

            3、GameEnd

            当游戏状态不为OK时,告知游戏结束的原因并释放蛇身

            void GameEnd(pSnake ps)
            {
            	SetPos(24, 12);
            	switch (ps->_status)
            	{
            	case END_NORMAL:
            		wprintf(L"主动结束游戏");
            		break;
            	case KILL_BY_SELF:
            		wprintf(L"撞到自己了,游戏结束");
            		break;
            	case KILL_BY_WALL:
            		wprintf(L"撞到墙了,游戏结束");
            		break;
            	}
            	pSnakeNode pur = ps->_pSnake;
            	while (pur)
            	{
            		pSnakeNode del = pur;
            		pur = pur->next;
            		free(del);
            	}
            }
            

            五、源代码拷贝

            Snake.h

            #pragma once
            #include 
            #include 
            #include 
            #include 
            #include 
            #define POS_X 24
            #define POS_Y 5
            #define WALL L'□'
            #define BODY L'◆'
            #define FOOD L'★'
            enum DIRECTION
            {
            	UP = 1,
            	DOWN,
            	LEFT,
            	RIGHT
            };
            enum GAME_STATUS
            {
            	OK,
            	KILL_BY_WALL,
            	KILL_BY_SELF,
            	END_NORMAL
            };
            typedef struct SnakeNode 
            {
            	int x;
            	int y;
            	struct SnakeNode* next;
            }SnakeNode, *pSnakeNode;
            typedef struct Snake
            {
            	pSnakeNode _pSnake;
            	pSnakeNode _pFood;
            	enum DRECTION _dir;
            	enum GAME_STATUS _status;
            	int _food_weight;
            	int _sorce;
            	int _sleep_time;
            }Snake,*pSnake;
            void SetPos(short x, short y);
            void GameStart(pSnake ps);
            void CreateMap();
            void WelcomeToGame();
            void InitSnake(pSnake ps);
            void CreateFood(pSnake ps);
            void GameRun(pSnake ps);
            void SnakeMove(pSnake ps);
            int NextIsFood(pSnakeNode pn, pSnake ps);
            void EatFood(pSnakeNode pn, pSnake ps);
            void NoFood(pSnakeNode pn, pSnake ps);
            void KillByWall(pSnake ps);
            void KillBySelf(pSnake ps);
            void GameEnd(pSnake ps);
            

            Snake.c

            #include "snake.h"
            void SetPos(short x, short y)
            {
            	HANDLE houtput = NULL;
            	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
            	COORD pos = { x,y };
            	SetConsoleCursorPosition(houtput, pos);
            }
            void WelcomeToGame()
            {
            	SetPos(40, 14);
            	wprintf(L"欢迎来到贪吃蛇小游戏\n");
            	SetPos(42, 20);
            	system("pause");
            	system("cls");
            	SetPos(25, 14);
            	wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");
            	SetPos(25, 15);
            	wprintf(L"加速能够得到更高的分数\n");
            	SetPos(42, 20);
            	system("pause");
            	system("cls");
            }
            void CreateMap()
            {
            	//上
            	int i = 0;
            	for (i = 0; i < 29; i++)
            	{
            		wprintf(L"%lc", WALL);
            	}
            	//下
            	SetPos(0, 26);
            	for (i = 0; i < 29; i++)
            	{
            		wprintf(L"%lc", WALL);
            	}
            	//左
            	for (i = 1; i <= 25; i++)
            	{
            		SetPos(0, i);
            		wprintf(L"%lc", WALL);
            	}
            	//右
            	for (i = 1; i <= 25; i++)
            	{
            		SetPos(56, i);
            		wprintf(L"%lc", WALL);
            	}
            }
            void InitSnake(pSnake ps)
            {
            	int i = 0;
            	pSnakeNode cur = NULL;
            	for (i = 0; i < 5; i++)
            	{
            		cur = (pSnakeNode)malloc(sizeof(SnakeNode));//创建蛇身节点
            		if (cur == NULL)
            		{
            			perror("malloc fail");
            			exit(1);
            		}
            		cur->next = NULL;
            		cur->x = POS_X + 2 * i;//将蛇的节点由蛇尾到蛇头创建好
            		cur->y = POS_Y;
            		if (ps->_pSnake == NULL)
            		{
            			ps->_pSnake = cur;//若没有蛇身节点则建立的节点为蛇身节点
            		}
            		else
            		{
            			cur->next = ps->_pSnake;
            			ps->_pSnake = cur;//若有蛇身节点则新创建的节点成为头节点
            		}
            	}
            	cur = ps->_pSnake;
            	while (cur)
            	{
            		SetPos(cur->x, cur->y);
            		wprintf(L"%lc", BODY);//将蛇的身体依据链表打印出来
            		cur = cur->next;
            	}
            	ps->_dir = RIGHT;//初始蛇的方向
            	ps->_food_weight = 10;//每个食物的分数
            	ps->_sleep_time = 200;//每两次打印蛇身的间隔,也就是蛇身的速度
            	ps->_sorce = 0;//初始总分数
            	ps->_status = OK;//蛇的初始状态
            }
            void CreateFood(pSnake ps)
            {
            	int x = 0;
            	int y = 0;
            again:	
            	do
            	{
            		x = rand() % 53 + 2;//我们要的x坐标值介于2~54间,任意数%53得到的值介于0~52,加上2就在2~56范围
            		y = rand() % 25 + 1;//我们要的y坐标值介于1~25间,任意数%25得到的值介于0~24,加上1就在1~25范围
            		//随机数时间戳,根据时间计算的数据,由于时间是不可修改切没有相同时候的,所以它产生的数字被认为是随机数
            	} while (x % 2 != 0);
            	pSnakeNode cur = ps->_pSnake;//记录蛇头结点
            	while (cur)
            	{
            		if (x == cur->x && y == cur->y)
            		{
            			goto again;
            		}
            		cur = cur->next;
            	}//如果食物与蛇身上某一节点重合了,则回到again处重新生成
            	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));//不重合就生成食物
            	if (pFood == NULL)
            	{
            		perror("malloc fail");
            		exit(2);
            	}
            	pFood->x = x;
            	pFood->y = y;
            	pFood->next = NULL;
            	SetPos(x, y);
            	wprintf(L"%lc", FOOD);//在对应位置处打印食物
            	ps->_pFood = pFood;
            }
            void GameStart(pSnake ps)
            {
            	system("mode con cols=100 lines=30");
            	system("title 贪吃蛇");
            	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
            	//隐藏光标
            	CONSOLE_CURSOR_INFO CursorInfo;
            	GetConsoleCursorInfo(houtput, &CursorInfo);
            	CursorInfo.bVisible = false;
            	SetConsoleCursorInfo(houtput, &CursorInfo);
            	WelcomeToGame();
            	
            	CreateMap();
            	InitSnake(ps);
            	CreateFood(ps);
            }
            void PrintHelpInfo()
            {
            	SetPos(64, 14);
            	wprintf(L"%ls", L"不能穿墙,不能咬到自己");
            	SetPos(64, 16);
            	wprintf(L"%ls", L"用 ↑. ↓ . ← . → 来控制蛇的移动");
            	SetPos(64, 18);
            	wprintf(L"%ls", L"按F3加速,F4减速");
            	SetPos(64, 20);
            	wprintf(L"%ls", L"按ESC退出游戏,按空格暂停游戏");
            	SetPos(64, 24);
            	wprintf(L"%ls", L"s_little_monster_倾情制作");
            }
            #define KEY_PRESS(vk)  ((GetAsyncKeyState(vk)&1)?1:0)
            void Pause()
            {
            	while (1)
            	{
            		Sleep(200);
            		if (KEY_PRESS(VK_SPACE))
            		{
            			break;
            		}
            	}
            }
            int NextIsFood(pSnakeNode pn,pSnake ps)
            {
            	return (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y);
            	//如果当前位置是食物则返回非0值,不是返回0
            }
            void EatFood(pSnakeNode pn, pSnake ps)
            {
            	ps->_pFood->next = ps->_pSnake;
            	ps->_pSnake = ps->_pFood;//吃掉食物,让食物成为蛇的头节点
            	free(pn);//因为节点pn与节点_pFood是一个节点,所以free掉其中的一个
            	pn = NULL;
            	pSnakeNode cur = ps->_pSnake;
            	while (cur)
            	{
            		SetPos(cur->x, cur->y);
            		wprintf(L"%lc", BODY);
            		cur = cur->next;
            	}//打印蛇身
            	ps->_sorce += ps->_food_weight;//加分
            	CreateFood(ps);//重新制造食物
            }
            void NoFood(pSnakeNode pn, pSnake ps)
            {
            	pn->next = ps->_pSnake;
            	ps->_pSnake = pn;//同EatFood,将下一节点成为头结点
            	pSnakeNode cur = ps->_pSnake;
            	while (cur->next->next != NULL)
            	{
            		SetPos(cur->x, cur->y);
            		wprintf(L"%lc", BODY);
            		cur = cur->next;
            	}//将除了尾节点以外的节点打印
            	SetPos(cur->next->x, cur->next->y);
            	printf("  ");//将尾节点打印为空格
            	free(cur->next);//free掉尾节点
            	cur->next = NULL;
            }
            void KillBySelf(pSnake ps)
            {
            	pSnakeNode pur = ps->_pSnake->next;
            	while (pur)
            	{
            		//当此时的蛇头位置与蛇身某一节点重合时
            		if (pur->x == ps->_pSnake->x && pur->y == ps->_pSnake->y)
            		{
            			ps->_status = KILL_BY_SELF;//修改状态为 KILL_BY_SELF
            			break;
            		}
            		pur = pur->next;
            	}
            }
            void KillByWall(pSnake ps)
            {
            	//当此时的蛇头位置与墙体重合时
            	if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 || ps->_pSnake->y == 0 || ps->_pSnake->y == 26)
            	{
            		ps->_status = KILL_BY_WALL;//修改状态为 KILL_BY_WALL
            	}
            }
            void SnakeMove(pSnake ps)
            {
            	pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));//开辟预测的下一个节点
            	if (pNextNode == NULL)
            	{
            		perror("malloc fail");
            		exit(3);
            	}
            	switch (ps->_dir)//用switch语句判断此时蛇的走向
            	{
            	case UP:
            		pNextNode->x = ps->_pSnake->x;
            		pNextNode->y = ps->_pSnake->y - 1;
            		break;
            	case DOWN:
            		pNextNode->x = ps->_pSnake->x;
            		pNextNode->y = ps->_pSnake->y + 1;
            		break;
            	case LEFT:
            		pNextNode->x = ps->_pSnake->x - 2;//注意左右移动是加减2
            		pNextNode->y = ps->_pSnake->y;
            		break;
            	case RIGHT:
            		pNextNode->x = ps->_pSnake->x + 2;
            		pNextNode->y = ps->_pSnake->y;
            		break;
            	}
            	if (NextIsFood(pNextNode, ps))
            	{
            		EatFood(pNextNode,ps);
            	}
            	else
            	{
            		NoFood(pNextNode, ps);
            	}
            	//判断下一个位置是否为食物,是则进入EatFood,不是则进入NoFood
            	KillBySelf(ps);
            	
            	KillByWall(ps);//检查是否撞到自己或墙而死亡
            }
            void GameRun(pSnake ps)
            {
            	PrintHelpInfo();//游戏玩法帮助打印
            	do
            	{
            		SetPos(64, 10);
            		printf("总分数:%d\n", ps->_sorce);
            		SetPos(64, 11);
            		printf("当前食物的分数:%2d\n", ps->_food_weight);
            		//检测键是否被按下
            		if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
            		{
            			ps->_dir = UP;
            		}
            		else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
            		{
            			ps->_dir = DOWN;
            		}
            		else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
            		{
            			ps->_dir = LEFT;
            		}
            		else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
            		{
            			ps->_dir = RIGHT;
            		}
            		else if (KEY_PRESS(VK_SPACE))
            		{
            			Pause();//暂停,等待再按下空格继续
            		}
            		else if (KEY_PRESS(VK_ESCAPE))
            		{
            			ps->_status = END_NORMAL;
            		}
            		else if (KEY_PRESS(VK_F3))//F3为加速,休眠时间变少也就是蛇的速度变快,每个食物分数增加2
            		{
            			if(ps->_sleep_time > 80)//速度不能太快
            			{
            				ps->_sleep_time -= 30;
            				ps->_food_weight += 2;
            			}
            		}
            		else if (KEY_PRESS(VK_F4))//F4为减速,休眠时间变多也就是蛇的速度变慢,每个食物分数减少2
            		{
            			if(ps->_food_weight > 2)//食物分数要在2分以上
            			{
            				ps->_sleep_time += 30;
            				ps->_food_weight -= 2;
            			}
            		}
            		SnakeMove(ps);//蛇每走一步要进行的活动
            		Sleep(ps->_sleep_time);//走一步休眠的时间,也就是蛇的速度
            	} while (ps->_status == OK);//当游戏状态为OK时循环继续
            }
            void GameEnd(pSnake ps)
            {
            	SetPos(24, 12);
            	switch (ps->_status)
            	{
            	case END_NORMAL:
            		wprintf(L"主动结束游戏");
            		break;
            	case KILL_BY_SELF:
            		wprintf(L"撞到自己了,游戏结束");
            		break;
            	case KILL_BY_WALL:
            		wprintf(L"撞到墙了,游戏结束");
            		break;
            	}
            	pSnakeNode pur = ps->_pSnake;
            	while (pur)
            	{
            		pSnakeNode del = pur;
            		pur = pur->next;
            		free(del);
            	}
            }
            

            game.h

            #include "snake.h"
            #include 
            void test()
            {
            	int c = 0;
            	do
            	{
            		system("cls");
            		Snake snake = { 0 };
            		GameStart(&snake);
            		GameRun(&snake);
            		GameEnd(&snake);
            		SetPos(20, 15);
            		printf("再来一局吗?(Y/N):");
            		c = getchar();
            		while (getchar() != '\n');
            	} while (c == 'Y');
            	SetPos(0, 27);
            }
            int main()
            {
            	setlocale(LC_ALL, "");//本地化
            	srand((unsigned int)time(NULL));//时间戳随机数
            	test();
            	return 0;
            }
            

            实际运行

            贪吃蛇的实际运行


            今日分享就到这里了~

转载请注明来自码农世界,本文标题:《【C语言项目】贪吃蛇(下)》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,70人围观)参与讨论

还没有评论,来说两句吧...

Top