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

在这里插入图片描述
个人主页~
源码在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 <locale.h>
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 <stdio.h>
#include <windows.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>

#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 <locale.h>
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;
}

实际运行

贪吃蛇的实际运行


今日分享就到这里了~

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/619454.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

加入全球少儿编程运动:Scratch让每个孩子都能成为创造者(Scratch最新版客户端和初/中/高级学习资料整理分享)

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 演示环境 &#x1f3e1;&#x1f4d2; 文章内容 &#x1f4d2;&#x1f4dd; 安装与使用&#x1f4dd; 社区与资源 &#x1f388; 获取方式 &#x1f388;⚓️ 相关链接 ⚓️ &#x1f4d6; 介绍 &#x1f4d6; 你知道…

没有公网ip,如何实现外网访问内网?

目前拨号上网是最广泛的上网方式&#xff0c;这种方式优点是价格便宜&#xff0c;缺点是没有固定公网ip&#xff0c;每次重新您拨号ip地址都会变。如果有一台服务器&#xff0c;需要实现外网访问&#xff0c;在没有固定公网ip的环境下&#xff0c;该如何实现呢&#xff1f;使用…

2.4 输入和显示

本节必须掌握的知识点&#xff1a; 示例五源代码 代码分析 汇编解析 2.4.1 示例五 ■格式化输入函数scanf scanf函数可以从键盘读取输入的信息。scanf函数同样可以像printf函数那样&#xff0c;通过转换说明“%d”来限制函数只能读取十进制数。scanf函数的参数为可变参数…

外网如何访问内网?快解析

由于公网IP资源短缺&#xff0c;我们的电脑大多处于内网环境&#xff0c;如何在外网访问内网电脑&#xff0c;成为一个令人头疼的问题&#xff0c;下面我给大家推荐一个非常实用的方法。 1&#xff1a;访问快解析下载安装快解析服务器 2&#xff1a;运行软件&#xff0c;点击“…

08.4.grafana自定义图形并直接数据库取值

grafana自定义图形并直接数据库取值 自定义添加油表图形 选择gauge图形&#xff0c;并且配置对应设定值&#xff0c;点击应用 如图所示&#xff0c;可以看到仪表盘上的值是zabbix上取得值 配置grafana直接数据库取值 添加mysql数据源 添加后进行配置&#xff0c;我这…

计算机毕业设计python+spark知识图谱音乐推荐系统 音乐数据分析可视化大屏 音乐爬虫 LSTM情感分析 大数据毕设 深度学习 机器学习

本科毕业设计&#xff08;论文&#xff09;开题报告 课题名称 基于Spark的音乐推荐与数据分析系统 的设计与实现 课题类型 系统设计 学院 大数据与人工智能学院 班级 专业 数据科学与大数据技术 指导教师 职称 学生姓名 学号 重庆工程学院教务处制 1.课…

函数模板底层本质

#include<iostream> using namespace std;template<typename T1> T1 ave(T1 a, T1 b) { return a b; }int main() {ave(100, 200);ave(short(100), short(200));return 0; }反汇编代码 模板本质是编译器帮忙生成了不同的函数 就算非类型参数值不一样编译器也重新…

开发一款相亲交友小程序

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 框架支持:springboot/Ssm/thinkphp/django/flask/express均支持 前端开发:vue.js 可选语言&#xff1a;pythonjavanode.jsphp均支持 运行软件…

STM32F407-驱动SHT41采集温湿度

STM32F407-驱动SHT41采集温湿度 SHT41 SHT41通过I2C方式进行驱动 从机地址&#xff1a; 0x44 获取数据方式 1&#xff09;先发送I2C写&#xff0c;写入特定指令 2&#xff09;延时一段时间&#xff0c;等待SHT41处理 3&#xff09;再进行I2C读&#xff0c;读数据即可 一些…

【谷粒商城】02安装和配置git

1.下载和安装git 地址&#xff1a;https://git-scm.com/download/win 傻瓜式安装 2.配置git DELLLJL MINGW64 ~/Desktop $ git config --global user.name "yufuabu"DELLLJL MINGW64 ~/Desktop $ git config --global user.email "463999534qq.com"DELL…

智慧管家物业管理系统(小组项目)

目录 前言 一、项目介绍 1、目的和背景 2、项目主要内容 3、技术介绍 二、功能模块 1、重要文件结构 2、功能实现&#xff08;部分个人负责模块功能&#xff09; 2.1 展示房源信息页面 2.2 房屋详情页面 2.3 房源信息管理 三、功能模块页面 1、前台模块 2、后台…

【Mac】Ghost Buster Pro(苹果电脑内存清理专家) v3.2.5安装教程

软件介绍 Ghost Buster pro是一款针对Mac系统的电脑清理和优化工具&#xff0c;可以帮助用户清理系统垃圾、修复注册表错误、卸载不需要的软件、管理启动项等&#xff0c;从而提高系统性能和稳定性。 安装教程 1.打开镜像包&#xff0c;拖动「Ghost Buster Pro」到应用程序中…

UnitTest / pytest 框架

文章目录 一、UnitTest框架1. TestCase使用2. TestSuite 和 TestRunner3. TestLoader4. Fixture装置5. UnitTest断言1. 登录案例 6. 参数化1. parameterized插件 7. unitTest 跳过 二、pytest 框架1. 运行方式3.读取配置文件(常用方式) 2. pytest执行用例的顺序1. 分组执行(冒烟…

华为数据之道第二部分导读

目录 导读 第二部分 第4章 面向“业务交易”的信息架构建设 信息架构的四个组件 数据资产目录 数据标准 数据模型 数据分布 信息架构原则&#xff1a;建立企业层面的共同行为准则 信息架构建设核心要素&#xff1a;基于业务对象进行设计和落地 按业务对象进行架构设…

vue3+ts--实际开发之--table表格打印或者保存

vue3实现指定区域打印&#xff08;导出&#xff09;功能-主要是解决分页内容分割问题 一、 问题页面效果二、 Print.js相关属性 和使用1. 介绍2. 安装引入3. PrintJS参数配置表 三 、解决关于分页文字或者表格被分割问题&#xff0c;解决后如下&#xff1a;1. 设置一个自定义ta…

20240512,函数对象,常用算法:遍历,查找

函数对象 函数对象基本使用 重载 函数调用操作符 的类&#xff0c;其对象被称为函数对象&#xff1b;函数对象使用重载的&#xff08;&#xff09;时&#xff0c;行为类似函数调用&#xff0c;也叫仿函数 函数对象&#xff08;仿函数&#xff09;本质是一个类&#xff0c;不是…

创新案例|为何农夫山泉创新战略升级为一家零售科技公司

农夫山泉上市的消息被公之于众后&#xff0c;几乎所有人都将目光投向了这家国内家喻户晓的饮料公司&#xff0c;谁都想第一时间内窥探它的庐山真面目。 当然&#xff0c;在此之前已经有多路消息通过旁敲侧击&#xff0c;从管窥中获取了一些农夫山泉的真实数据。 去年6月&…

OCR技术在历史文献数字化中的革命性作用

随着数字化技术的不断发展&#xff0c;历史文献的数字化已成为保存和传播文化遗产的重要途径。其中&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术在历史文献数字化中发挥了革命性的作用&#xff0c;为研究者提供了更广阔的研究空间&#xff0c;推动了历史学研究的发…

Golang | Leetcode Golang题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; func partition(head *ListNode, x int) *ListNode {small : &ListNode{}smallHead : smalllarge : &ListNode{}largeHead : largefor head ! nil {if head.Val < x {small.Next headsmall small.Next} else {large.Next hea…

Web安全:SQL注入之布尔盲注原理+步骤+实战操作

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…