C语言——贪吃蛇

这篇具有很好参考价值的文章主要介绍了C语言——贪吃蛇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一. 游戏效果


贪吃蛇


贪吃蛇穿墙版


二. 游戏背景

贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。
贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》,后移植到各种平台上。具体如下:
起源。1977年,投币式墙壁游戏生产商Gremlin推出了经典的街机游戏《Blockade》,两名玩家要分别控制角色移动,角色会不停长大,而且走过的地方会变成围栏,谁先碰到围栏或碰到自己的身体就算输。
贪吃蛇最初的版本是像素版本,后来又衍生出3D版本、多人对战版本等2 3。
 

三、游戏开发日志

C语言——贪吃蛇,c语言小游戏,c语言,开发语言,c++,链表,数据结构

四、知识准备 

本次实现贪吃蛇会使⽤到的⼀些Win32 API知识,那么就学习⼀下

4.1 Win32 API

Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外, 它同时也是⼀个很⼤的服务中⼼,调⽤这个服务中⼼的各种服务(每⼀种服务就是⼀个函数),可以帮应⽤程式达到开启 视窗、描绘图形、使⽤周边设备等⽬的,由于这些函数服务的对象是应⽤程序(Application), 所以便 称之为 Application Programming Interface, 简称 API 函数。 WIN32 API也就是Microsoft Windows 32位平台的应⽤程序编程接⼝。

4.2 控制台程序

平常我们运⾏起来的⿊框程序其实就是控制台程序。
我们可以使⽤cmd命令来设置控制台窗⼝的⻓宽,也可以通过命令设置控制台窗⼝的名字:
设置控制台窗⼝的⼤⼩,30⾏,100列,设置控制台窗⼝的名字。
//控制台窗口设置
system("mode con cols=100 lines=35");
system("title 贪吃蛇");

4.3  控制台屏幕上的坐标COORD

COORD 是Windows API中定义的⼀种结构,表⽰⼀个字符在控制台屏幕上的坐标

typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;

4.4  GetStdHandle

GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。
 
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

4.5 GetConsoleCursorInfo

检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息
 
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息

4.5.1  CONSOLE_CURSOR_INFO

这个结构体,包含有关控制台游标的信息
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
(1) dwSize,由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的⽔平线条。
(2)  bVisible,游标的可⻅性。 如果光标可⻅,则此成员为 TRUE。
CursorInfo.bVisible = false; //隐藏控制台光标

5.6  SetConsoleCursorInfo

设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性。

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态

5.7  SetConsoleCursorPosition

设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调 ⽤SetConsoleCursorPosition函数将光标位置设置到指定的位置。
COORD pos = { 10, 5};
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
温馨提示:

这里我们可以将SetPos:封装⼀个设置光标位置的函数

//设置光标的坐标
void SetPos(short x, short y)
{
COORD pos = { x, y };
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
}

5.8 GetAsyncKeyState

获取按键情况,将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果 返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。
如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.
我们这里定义一个宏:
 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

5.9 宽字符打印

在游戏地图上,我们打印墙体使⽤宽字符:□,打印蛇使⽤宽字符●,打印⻝物使⽤宽字符■
普通的字符是占⼀个字节的,这类宽字符是俩个字节。

5.9.1  setlocale函数

char* setlocale (int category, const char* locale);

setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。 setlocale 的第⼀个参数如果是LC_ALL,就会影响所有的类项。

C标准给第⼆个参数仅定义了2种可能取值:"C"和"  "。
在任意程序执⾏开始,都会隐藏式执⾏调⽤:
 setlocale(LC_ALL, "C");

当地区设置为"C"时,库函数按正常⽅式执⾏.

当地区设置为"  "时,这种模式下程序会适应本地环境。⽐如:切换到我们的本地模式后就⽀
持宽字符(汉字)的输出等。
setlocale(LC_ALL, " ");//切换到本地环境

宽字符的打印如下:

#include <stdio.h>
#include<locale.h>
int main() {
setlocale(LC_ALL, "");
wchar_t ch1 = L'●';
wprintf(L"%c\n", ch1);
return 0;
}

五、游戏实现

5.1 游戏逻辑主体

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
#include<locale.h>
#include<stdio.h>
int main()
{
	char ch;
	setlocale(LC_ALL, "");//切换到本地环境,支持宽字符
	srand((unsigned int)time(NULL));
	do
	{
		Snake snake = { 0 };
		GameInit(&snake);
		GameRun(&snake);
		GameOver(&snake);
		printf("小垃圾还要再来吗?是:Y,否:N\n");
	    ch = getchar();
		getchar();

	} while (ch == 'y' || ch == 'Y');
	return 0;
}

5.2  游戏初始化实现

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"

#define  WALL  L'□'
#define  BODY  L'●'
#define  FOOD  L'█'
void SetPos(short x, short y)
{
	COORD pos = { x, y };
	HANDLE hOutput = NULL;
	//获取标准输出的句柄(⽤来标识不同设备的数值)
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置标准输出上光标的位置为pos
	SetConsoleCursorPosition(hOutput, pos);
}
void  WelcomeToGame()
{
	SetPos(40, 13);
	printf("欢迎来到贪吃蛇小游戏");
		SetPos(42, 22);
		system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
		system("cls");
		SetPos(25, 12);
		printf("↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
		SetPos(42, 22);
		system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
		system("cls");
		/*getchar();*/

}
void CreateMap()
{
	SetPos(0,0);
	int i = 0;
	for(i=0;i<58;i=i+2)
	{
		wprintf(L"%c", WALL);
	}
	SetPos(0, 26);
	for (i = 0; i < 58; i = i + 2)
	{
		wprintf(L"%c", WALL);
	}
	for (i = 1; i <26; i++)
	{
		SetPos(0, i);
		wprintf(L"%c", WALL);
	}
	for (i = 1; i < 26; i++)
	{
		SetPos(56, i);
		wprintf(L"%c", WALL);
	}
	/*getchar();*/
}

void InitSnake(Snake* snake)
{
	//初始化蛇身
	
	for (int i = 0; i < 5; i++)
	{
		SnakeNode* node = (SnakeNode*)malloc(sizeof(SnakeNode));
		node->x = 24 + 2 * i;
		node->y = 15;
		node->next = NULL;
		if (snake->pSnake== NULL)
		{
			snake->pSnake= node;
			

		}
		else
		{
			node->next = snake->pSnake;
			snake->pSnake = node;
		}
	}
	SnakeNode* cur = snake->pSnake;
	while (cur)
	{
		int x = cur->x;
		int y = cur->y;
		SetPos(x, y);
		wprintf(L"%c", BODY);
		cur = cur->next;
	}
	snake->status = RUN;
	snake->dir = RIGHT;
	snake->FoodWeight = 10;
	snake->pFood = NULL;
	snake->score = 0;
	snake->SleepTime = 200;
}
void CreateFood(Snake* snake)
{
	int x = 0;
	int y = 0;

again:
	do
	{
		 x = rand() % 53 + 2;
		 y = rand() % 24 + 1;
	} while (x % 2 != 0);
	 SnakeNode* cur = snake->pSnake;
	
	do
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	} while (cur);
	SnakeNode* food = (SnakeNode*)malloc(sizeof(SnakeNode));
	food->x = x;
	food->y = y;
	
	snake->pFood = food;
	
	SetPos(x, y);
	wprintf(L"%c", FOOD);
	/*getchar();*/

}

void  GameInit(Snake* snake)
{
	//控制台窗口设置
	system("mode con cols=100 lines=35");
	system("title 贪吃蛇");
	//隐藏光标
	 HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
     CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
	CursorInfo.bVisible = false; //隐藏控制台光标
	SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
	//打印欢迎界面
	WelcomeToGame();
	//创建地图
	 CreateMap();
	//初始化贪吃蛇
     InitSnake(snake);
	//创建食物
      CreateFood(snake);
}

5.3 游戏运行实现

void PrintHelpInfo()
{
	SetPos(60, 13);
	printf("1. 不能穿墙不能咬到自己\n");
	SetPos(60, 14);
	printf("2.↑.↓.←.→分别控制蛇的移动\n");
	SetPos(60, 15);
    printf("3. F3为加速,F4为减速\n");
	SetPos(60, 16);
	printf("4. ESC-退出,空格-暂停\n");
}

void Pause()
{
	while (1)
	{
		Sleep(200);
		if (KEY_PRESS(VK_SPACE) == 1)
		{
			break;
		}
	}
	
}
void EatFood(Snake* snake, SnakeNode* snakenext)
{
	snakenext->next = snake->pSnake;
	snake->pSnake = snakenext;
	SnakeNode* cur = snake->pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	free(snake->pFood);
	snake->pFood = NULL;
	CreateFood(snake);

}
void NoEatFood(Snake* snake, SnakeNode* snakenext)
{
	snakenext->next = snake->pSnake;
	snake->pSnake = snakenext;
	SnakeNode* cur = snake->pSnake;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	SetPos(cur->x, cur->y);
	wprintf(L"%lc", BODY);
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

void SnakeMove(Snake* snake)
{
	SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));
	if (snake->dir == UP)
	{
		snakenext->x = snake->pSnake->x;
		snakenext->y = snake->pSnake->y -1;
		snakenext->next = NULL;
	}
	else if (snake->dir == DOWN)
	{
		snakenext->x = snake->pSnake->x;
		snakenext->y = snake->pSnake->y +1;
		snakenext->next = NULL;
	}
	if (snake->dir == LEFT)
	{
		snakenext->x = snake->pSnake->x-2;
		snakenext->y = snake->pSnake->y ;
		snakenext->next = NULL;
	}
	if (snake->dir == RIGHT)
	{
		snakenext->x = snake->pSnake->x + 2;
		snakenext->y = snake->pSnake->y;
		snakenext->next = NULL;
	}
	//判断下一个节点是否为食物
	if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y)
	{
		EatFood(snake,snakenext);//吃食物
		snake->score += snake->FoodWeight;
	}
	else
	{
		NoEatFood(snake,snakenext);//不吃食物
	}
	//碰撞检测
	if (snake->pSnake->x == 0 || snake->pSnake->x == 56 || snake->pSnake->y == 0 || snake->pSnake->y == 26)
	{
		snake->status = KILL_BY_WALL;
	}
	SnakeNode* cur = snake->pSnake->next;
	while (cur)
	{
		if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y)
		{
			snake->status = KILL_BY_SELF;
		}
		cur = cur->next;
	}
}

void GameRun(Snake* snake)
{
	//打印帮助信息
	PrintHelpInfo();
	do
	{
		SetPos(60, 8);
		printf("游戏总得分:%5d ", snake->score);
		SetPos(60, 9);
		printf("每个食物的分数:%2d ", snake->FoodWeight);
		if (KEY_PRESS(VK_UP) == 1&&snake->dir!=DOWN)
		{
			snake->dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) == 1 && snake->dir != UP)
		{
			snake->dir = DOWN;
		}
		else if (KEY_PRESS(VK_RIGHT) == 1 && snake->dir != LEFT)
		{
			snake->dir = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) == 1 && snake->dir != RIGHT)
		{
			snake->dir =LEFT;
		}
		else if (KEY_PRESS(VK_F3) == 1)
		{
			if (snake->SleepTime>=80)
			{
				snake->SleepTime -= 30;
				snake->FoodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_F4) == 1)
		{
			if (snake->SleepTime<=320)
			{
				snake->SleepTime += 30;
				snake->FoodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_ESCAPE) == 1)
		{
			snake->status = OVER;
			break;
		}
		else if (KEY_PRESS(VK_SPACE) == 1)
		{
			Pause();
		}
		
		SnakeMove(snake);
		Sleep(snake->SleepTime);//每一帧停0.2s
	} while (snake->status==RUN);
}

5.4 游戏结束实现

void GameOver(Snake* snake)
{
	switch (snake->status)
	{
	case KILL_BY_WALL:
		SetPos(20, 15);
		printf("你已经撞墙了,小垃圾!\n");
			break;
	case KILL_BY_SELF:
		SetPos(20, 15);
		printf("你已经自杀了,小垃圾!\n");
             break;
	case  OVER:
		SetPos(20, 15);
		printf("你退出游戏了,小垃圾!\n");
              break;
	}
	SetPos(0, 29);

}

六、 完整代码

6.1 snake.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdbool.h>
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
enum direction{UP = 1,  DOWN, LEFT, RIGHT};//蛇的方向
enum game_status{RUN,KILL_BY_WALL,KILL_BY_SELF,OVER};

typedef struct  SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode;


typedef struct Snake
{
	SnakeNode* pSnake;//指向贪吃蛇头节点
	SnakeNode* pFood;//指向食物的节点
	int  score;
	int FoodWeight;
	int SleepTime;
	enum direction dir;//蛇的方向
	enum  game_status status;//游戏状态
}Snake;
void  GameInit(Snake*snake);
void  WelcomeToGame();
void CreateMap();
void InitSnake(Snake* snake);
void CreateFood(Snake* snake);
void GameRun(Snake* snake);
void PrintHelpInfo();
void Pause();
void SnakeMove(Snake* snake);

void EatFood(Snake* snake,SnakeNode*snakenext);
void NoEatFood(Snake* snake, SnakeNode* snakenext);
void GameOver(Snake* snake);

6.2 snake.c

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"

#define  WALL  L'□'
#define  BODY  L'●'
#define  FOOD  L'█'
void SetPos(short x, short y)
{
	COORD pos = { x, y };
	HANDLE hOutput = NULL;
	//获取标准输出的句柄(⽤来标识不同设备的数值)
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置标准输出上光标的位置为pos
	SetConsoleCursorPosition(hOutput, pos);
}
void  WelcomeToGame()
{
	SetPos(40, 13);
	printf("欢迎来到贪吃蛇小游戏");
		SetPos(42, 22);
		system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
		system("cls");
		SetPos(25, 12);
		printf("↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
		SetPos(42, 22);
		system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
		system("cls");
		/*getchar();*/

}
void CreateMap()
{
	SetPos(0,0);
	int i = 0;
	for(i=0;i<58;i=i+2)
	{
		wprintf(L"%c", WALL);
	}
	SetPos(0, 26);
	for (i = 0; i < 58; i = i + 2)
	{
		wprintf(L"%c", WALL);
	}
	for (i = 1; i <26; i++)
	{
		SetPos(0, i);
		wprintf(L"%c", WALL);
	}
	for (i = 1; i < 26; i++)
	{
		SetPos(56, i);
		wprintf(L"%c", WALL);
	}
	/*getchar();*/
}

void InitSnake(Snake* snake)
{
	//初始化蛇身
	
	for (int i = 0; i < 5; i++)
	{
		SnakeNode* node = (SnakeNode*)malloc(sizeof(SnakeNode));
		node->x = 24 + 2 * i;
		node->y = 15;
		node->next = NULL;
		if (snake->pSnake== NULL)
		{
			snake->pSnake= node;
			

		}
		else
		{
			node->next = snake->pSnake;
			snake->pSnake = node;
		}
	}
	SnakeNode* cur = snake->pSnake;
	while (cur)
	{
		int x = cur->x;
		int y = cur->y;
		SetPos(x, y);
		wprintf(L"%c", BODY);
		cur = cur->next;
	}
	snake->status = RUN;
	snake->dir = RIGHT;
	snake->FoodWeight = 10;
	snake->pFood = NULL;
	snake->score = 0;
	snake->SleepTime = 200;
}
void CreateFood(Snake* snake)
{
	int x = 0;
	int y = 0;

again:
	do
	{
		 x = rand() % 53 + 2;
		 y = rand() % 24 + 1;
	} while (x % 2 != 0);
	 SnakeNode* cur = snake->pSnake;
	
	do
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	} while (cur);
	SnakeNode* food = (SnakeNode*)malloc(sizeof(SnakeNode));
	food->x = x;
	food->y = y;
	
	snake->pFood = food;
	
	SetPos(x, y);
	wprintf(L"%c", FOOD);
	/*getchar();*/

}

void  GameInit(Snake* snake)
{
	//控制台窗口设置
	system("mode con cols=100 lines=35");
	system("title 贪吃蛇");
	//隐藏光标
	 HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
     CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
	CursorInfo.bVisible = false; //隐藏控制台光标
	SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
	//打印欢迎界面
	WelcomeToGame();
	//创建地图
	 CreateMap();
	//初始化贪吃蛇
     InitSnake(snake);
	//创建食物
      CreateFood(snake);
}

void PrintHelpInfo()
{
	SetPos(60, 13);
	printf("1. 不能穿墙不能咬到自己\n");
	SetPos(60, 14);
	printf("2.↑.↓.←.→分别控制蛇的移动\n");
	SetPos(60, 15);
    printf("3. F3为加速,F4为减速\n");
	SetPos(60, 16);
	printf("4. ESC-退出,空格-暂停\n");
}

void Pause()
{
	while (1)
	{
		Sleep(200);
		if (KEY_PRESS(VK_SPACE) == 1)
		{
			break;
		}
	}
	
}
void EatFood(Snake* snake, SnakeNode* snakenext)
{
	snakenext->next = snake->pSnake;
	snake->pSnake = snakenext;
	SnakeNode* cur = snake->pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	free(snake->pFood);
	snake->pFood = NULL;
	CreateFood(snake);

}
void NoEatFood(Snake* snake, SnakeNode* snakenext)
{
	snakenext->next = snake->pSnake;
	snake->pSnake = snakenext;
	SnakeNode* cur = snake->pSnake;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	SetPos(cur->x, cur->y);
	wprintf(L"%lc", BODY);
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

void SnakeMove(Snake* snake)
{
	SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));
	if (snake->dir == UP)
	{
		snakenext->x = snake->pSnake->x;
		snakenext->y = snake->pSnake->y -1;
		snakenext->next = NULL;
	}
	else if (snake->dir == DOWN)
	{
		snakenext->x = snake->pSnake->x;
		snakenext->y = snake->pSnake->y +1;
		snakenext->next = NULL;
	}
	if (snake->dir == LEFT)
	{
		snakenext->x = snake->pSnake->x-2;
		snakenext->y = snake->pSnake->y ;
		snakenext->next = NULL;
	}
	if (snake->dir == RIGHT)
	{
		snakenext->x = snake->pSnake->x + 2;
		snakenext->y = snake->pSnake->y;
		snakenext->next = NULL;
	}
	//判断下一个节点是否为食物
	if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y)
	{
		EatFood(snake,snakenext);//吃食物
		snake->score += snake->FoodWeight;
	}
	else
	{
		NoEatFood(snake,snakenext);//不吃食物
	}
	//碰撞检测
	if (snake->pSnake->x == 0 || snake->pSnake->x == 56 || snake->pSnake->y == 0 || snake->pSnake->y == 26)
	{
		snake->status = KILL_BY_WALL;
	}
	SnakeNode* cur = snake->pSnake->next;
	while (cur)
	{
		if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y)
		{
			snake->status = KILL_BY_SELF;
		}
		cur = cur->next;
	}
}

void GameRun(Snake* snake)
{
	//打印帮助信息
	PrintHelpInfo();
	do
	{
		SetPos(60, 8);
		printf("游戏总得分:%5d ", snake->score);
		SetPos(60, 9);
		printf("每个食物的分数:%2d ", snake->FoodWeight);
		if (KEY_PRESS(VK_UP) == 1&&snake->dir!=DOWN)
		{
			snake->dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) == 1 && snake->dir != UP)
		{
			snake->dir = DOWN;
		}
		else if (KEY_PRESS(VK_RIGHT) == 1 && snake->dir != LEFT)
		{
			snake->dir = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) == 1 && snake->dir != RIGHT)
		{
			snake->dir =LEFT;
		}
		else if (KEY_PRESS(VK_F3) == 1)
		{
			if (snake->SleepTime>=80)
			{
				snake->SleepTime -= 30;
				snake->FoodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_F4) == 1)
		{
			if (snake->SleepTime<=320)
			{
				snake->SleepTime += 30;
				snake->FoodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_ESCAPE) == 1)
		{
			snake->status = OVER;
			break;
		}
		else if (KEY_PRESS(VK_SPACE) == 1)
		{
			Pause();
		}
		
		SnakeMove(snake);
		Sleep(snake->SleepTime);//每一帧停0.2s
	} while (snake->status==RUN);
}

void GameOver(Snake* snake)
{
	switch (snake->status)
	{
	case KILL_BY_WALL:
		SetPos(20, 15);
		printf("你已经撞墙了,小垃圾!\n");
			break;
	case KILL_BY_SELF:
		SetPos(20, 15);
		printf("你已经自杀了,小垃圾!\n");
             break;
	case  OVER:
		SetPos(20, 15);
		printf("你退出游戏了,小垃圾!\n");
              break;
	}
	SetPos(0, 29);

}

6.3 text.c

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
#include<locale.h>
#include<stdio.h>
int main()
{
	char ch;
	setlocale(LC_ALL, "");//切换到本地环境,支持宽字符
	srand((unsigned int)time(NULL));
	do
	{
		Snake snake = { 0 };
		GameInit(&snake);
		GameRun(&snake);
		GameOver(&snake);
		printf("小垃圾还要再来吗?是:Y,否:N\n");
	    ch = getchar();
		getchar();

	} while (ch == 'y' || ch == 'Y');
	return 0;
}

七、穿墙版(进阶版)

穿墙也非常简单,只是将撞墙检测去除,改为

1)判断snakenext->y ==0,则snakenext->y =25

2)判断snakenext->y ==26,则snakenext->y =1

3)判断snakenext->x==0,则snakenext->x =54

4)   判断snakenext->x==56,则snakenext->x =2

其余状态为正常吃食物状态

只在snake.c中的void SnakeMove(Snake* snake)中略有改动,其余不变文章来源地址https://www.toymoban.com/news/detail-751378.html

void SnakeMove(Snake* snake)
{
	SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));
	if (snake->dir == UP)
	{
		
		snakenext->x = snake->pSnake->x;
		snakenext->y = snake->pSnake->y -1;
		snakenext->next = NULL;
	}
	else if (snake->dir == DOWN)
	{
		snakenext->x = snake->pSnake->x;
		snakenext->y = snake->pSnake->y +1;
		snakenext->next = NULL;
	}
	if (snake->dir == LEFT)
	{
		snakenext->x = snake->pSnake->x-2;
		snakenext->y = snake->pSnake->y ;
		snakenext->next = NULL;
	}
	if (snake->dir == RIGHT)
	{
		snakenext->x = snake->pSnake->x + 2;
		snakenext->y = snake->pSnake->y;
		snakenext->next = NULL;
	}
	//判断下一个节点是否为食物
	if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y)
	{
		EatFood(snake,snakenext);//吃食物
		snake->score += snake->FoodWeight;
	}
	else
	{ 
		
		if (snakenext->y == 0)
		{
			snakenext->y = 25;
			snakenext->next = snake->pSnake;
			snake->pSnake = snakenext;
			SnakeNode* cur = snake->pSnake;
			while (cur->next->next)
			{
				SetPos(cur->x, cur->y);
				wprintf(L"%lc", BODY);
				cur = cur->next;
			}
			SetPos(cur->x, cur->y);
			wprintf(L"%lc", BODY);
			SetPos(cur->next->x, cur->next->y);
			printf("  ");
			free(cur->next);
			cur->next = NULL;
		}
		else if (snakenext->y == 26)
		{
			snakenext->y =1;
			snakenext->next = snake->pSnake;
			snake->pSnake = snakenext;
			SnakeNode* cur = snake->pSnake;
			while (cur->next->next)
			{
				SetPos(cur->x, cur->y);
				wprintf(L"%lc", BODY);
				cur = cur->next;
			}
			SetPos(cur->x, cur->y);
			wprintf(L"%lc", BODY);
			SetPos(cur->next->x, cur->next->y);
			printf("  ");
			free(cur->next);
			cur->next = NULL;
		}
		else if (snakenext->x == 0)
		{
			snakenext->x = 54;
			snakenext->next = snake->pSnake;
			snake->pSnake = snakenext;
			SnakeNode* cur = snake->pSnake;
			while (cur->next->next)
			{
				SetPos(cur->x, cur->y);
				wprintf(L"%lc", BODY);
				cur = cur->next;
			}
			SetPos(cur->x, cur->y);
			wprintf(L"%lc", BODY);
			SetPos(cur->next->x, cur->next->y);
			printf("  ");
			free(cur->next);
			cur->next = NULL;
		}
		else if (snakenext->x == 56)
		{
			snakenext->x =2;
			snakenext->next = snake->pSnake;
			snake->pSnake = snakenext;
			SnakeNode* cur = snake->pSnake;
			while (cur->next->next)
			{
				SetPos(cur->x, cur->y);
				wprintf(L"%lc", BODY);
				cur = cur->next;
			}
			SetPos(cur->x, cur->y);
			wprintf(L"%lc", BODY);
			SetPos(cur->next->x, cur->next->y);
			printf("  ");
			free(cur->next);
			cur->next = NULL;
		}
		else
		{
			NoEatFood(snake, snakenext);//不吃食物
		}
	}
	//穿墙检测
	
	SnakeNode* cur = snake->pSnake->next;
	while (cur)
	{
		if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y)
		{
			snake->status = KILL_BY_SELF;
		}
		cur = cur->next;
	}
}

到了这里,关于C语言——贪吃蛇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言实战项目-贪吃蛇小游戏

    1.定义蛇对象、食物对象 2.初始化蛇、初始化食物 3.控制流程: ( 1)蛇头和墙壁的碰撞 (2)蛇头和蛇身体碰撞 (3)蛇头和食物碰撞 (4)移动速度增大 4.游戏效果: ( 1)蛇身增长 (2)食物消失 -- 新食物产生 (3)分数累加 (4)移动速度增大 (5)蛇的移动 (6)显示分

    2024年02月19日
    浏览(38)
  • C语言之实现贪吃蛇小游戏篇(2)

    目录 🎇测试游戏test.c 🎇游戏头文件包含函数声明snake.h 🎇游戏实现snake.c 屏幕录制 2023-12-02 204515   ✔✔✔✔✔最后感谢大家的阅读,若有错误和不足,欢迎指正!乖乖敲代码哦!  代码---------→【唐棣棣 (TSQXG) - Gitee.com】 联系---------→【邮箱:2784139418@qq.com】

    2024年02月05日
    浏览(56)
  • C语言从零实现贪吃蛇小游戏

    制作不易,点赞关注一下呗!!! 文章目录 前言 一.  技术要点 二、 WIN32API介绍 三、 贪吃蛇游戏设计与分析         1.游戏开始前的初始化         2.游戏运行的逻辑  总结 当我们掌握链表这样的数据结构之后,我们就可以用它来做一些小项目,比如童年小游戏贪吃蛇

    2024年02月20日
    浏览(37)
  • C语言小项目——小游戏贪吃蛇的实现

    我们可以使用 mode命令来设置控制台的大小,使用title命令来设置控制台标题。 在C语言中调用库函数 system来使用这些作用于控制台的命令 。使用代码如下: 采用该命令后控制台界面大概如下:   控制台坐标系以控制台左上角为原点从上往下y轴坐标增大,从左往右x轴坐标增

    2024年04月27日
    浏览(34)
  • 小游戏贪吃蛇的实现之C语言版

    找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:C语言 目录 游戏前期准备: 设置控制台相关的信息  GetStdHandle GetConsoleCursorInfo  SetConsoleCursorInfo SetConsoleCursorPosition GetAsyncKeyState 贪吃蛇游戏设计与分析  本地化 地图,食物

    2024年04月23日
    浏览(36)
  • 游戏开发丨基于Pygame的AI版贪吃蛇小游戏

    本期内容 基于pygame的AI版贪吃蛇小游戏 所需环境 python pycharm或anaconda pygame 下载地址 https://download.csdn.net/download/m0_68111267/88789665 本游戏使用Pygame模块开发,不需要玩家操纵贪吃蛇,贪吃蛇会自动吃掉屏幕上随机出现的食物,每吃一个食物贪吃蛇长度增加一节。如果贪吃蛇撞到

    2024年02月20日
    浏览(57)
  • C语言结课实战项目_贪吃蛇小游戏

    ✨✨所属专栏:C语言✨✨ ✨✨作者主页:嶔某✨✨ 游戏源代码链接: function/贪吃蛇 · 钦某/c-language-learning - 码云 - 开源中国 (gitee.com) • 贪吃蛇地图绘制 • 蛇吃⻝物的功能(上、下、左、右⽅向键控制蛇的动作) • 蛇撞墙死亡 • 蛇撞⾃⾝死亡 • 计算得分 • 蛇⾝加速、

    2024年04月26日
    浏览(37)
  • 【C语言】做一个贪吃蛇小游戏,完整代码&附带视频演示

    视频演示: https://www.bilibili.com/video/BV1pt421a7Nu/?spm_id_from=333.999.0.0vd_source=82b65865be0947de29bd55efc8cdb40a 编译环境:linux(Vmware16.2.4 + Ubantu20.04.3); 小蛇🐍只能在固定的范围内活动; 可以利用键盘方向键控制小蛇🐍的前进方向; 活动范围内会随机生成食物; 小蛇🐍吃到食物,身

    2024年02月21日
    浏览(38)
  • 一篇文章教会你写一个贪吃蛇小游戏(纯C语言)

    实现基本的功能 : • 贪吃蛇地图绘制 • 蛇吃⻝物的功能(上、下、左、右⽅向键控制蛇的动作) • 蛇撞墙死亡 • 蛇撞⾃⾝死亡 • 计算得分 • 蛇⾝加速、减速 • 暂停游戏 Win32 API是一套由Microsoft提供的应用程序编程接口,用于开发Windows平台上的应用程序。它包括了丰

    2024年01月22日
    浏览(43)
  • 【贪吃蛇小游戏】宝塔面板快速搭建贪吃蛇小游戏Web网站 - 无需云服务器

    转载自远程内网穿透的文章:Linux使用宝塔面板搭建网站,并内网穿透实现公网访问 宝塔面板作为简单好用的服务器运维管理面板,它支持Linux/Windows系统,我们可用它来一键配置LAMP/LNMP环境、网站、数据库、FTP等,通过Web端轻松管理服务器。 以下教程,我们将演示使用宝塔

    2024年02月05日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包