#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#include<mmsystem.h>
#include<conio.h>
#include<stdbool.h>
#include\"背景和画蛇.h\"//把占空间大的放在头文件中
#include\"resource.h\"
#pragma comment(lib,\"winmm.lib\")//手动添加库
void firstpage(void);//首页
void firstpage_music(void);//首页音乐
void empty_cmd(void);//清空首页
void stopmusic(void);//停止音乐
void startgame(void);//开始游戏(按钮)
void ground(void);//游戏边框
void snake_pos(void);//蛇的随机产生
void draw_snake(void);//画蛇
void empty_snake(void);//去除旧蛇残留
void change_dir(void);//改变方向
bool snake_die(void);//死亡判断
void snake_food(void);//画食物
void snake_up(void);//蛇变长

//首页
void firstpage(void)
{

	printf(\"\\n\"); printf(\"\\n\"); printf(\"\\n\");
	printf(\"				************************************************\\n\");
	printf(\"\\n\"); printf(\"\\n\"); printf(\"\\n\");
	printf(\"				*           <来和程序张一起van♂游戏>          *\\n\");
	printf(\"				*          van♂心提示:			       *\\n\");
	printf(\"				*          1. W A S D 控制老蛇的方向           *\\n\");
	printf(\"				*          2. 按 开始游戏                      *\\n\");
	printf(\"\\n\"); printf(\"\\n\"); printf(\"\\n\");
	printf(\"				************************************************\\n\");
	printf(\"\\n\"); printf(\"\\n\"); printf(\"\\n\");
	
}

//播放音乐(必须是wav格式的)
void firstpage_music(void)
{
	//绝对路径:文件的完整路径
	//相对路径:和要执行的文件所在的位置一样
	PlaySound(MAKEINTRESOURCE(IDR_WAVE1), NULL, SND_RESOURCE | SND_ASYNC);//加载资源在内部需要加头文件
}

void game_music(void)
{
	PlaySound(L\"3.wav\", NULL, SND_FILENAME | SND_ASYNC);
}

void startgame(void)
{
	//按空格开始游戏
	char start;
	while (1)//无限循环
	{
		start = _getch();
		if (\' \' == start)//输入空格时跳出循环开始游戏
		{
			break;
		}
	}
}

//音乐停止(或者更换播放音乐)
void stopmusic(void)
{
	
	PlaySound(NULL, 0, 0);
}

void empty_cmd(void)
{
	//清空控制台界面,准备进入游戏界面
	system(\"cls\");
}

//专心画背景emmmmm
void background(void)
{
	int i = 0;
	for (i = 0; i < 29; i++)
	{
			printf(black_ground[i]);
	}
}

void snake_pos(void)
{
	//定义横纵坐标
	/*int x=-1;
	int y=-1;*/
	//产生随机数
	srand((unsigned int)time(NULL));//种种子
	//随机数的范围
	int x =( rand() % 19 )+ 1;//1~19
	int y =( rand() % 27 )+ 1;//1~27

	//初始化蛇的三个节点(身体)
	//头
	arr_snake[0][0] = y;//行
	arr_snake[0][1] = 2 * x;//列
	arr_snake[0][2] = to_east;//方向
	//身
	arr_snake[1][0] = y;//行
	arr_snake[1][1] = 2 * x + 2;//列
	arr_snake[0][2] = to_east;//方向
	//尾
	arr_snake[2][0] = y;//行
	arr_snake[2][1] = 2 * x + 4;//列
	arr_snake[2][2] = to_east;//方向

	
	draw_snake();
}

void draw_snake(void)
{
	int i = 0;
	for (i = 0; arr_snake[i][0] != 0 ; i++)//打印3个节点
	{
		//字符串自带\\0,所以\"●\"带了三个字符,当我们直接赋值给数组时会吧\\0复制过去,会停止,所以要规定只复制两个字符过去
		//把放在蛇数组里的三个节点拿到界面中
		strncpy(&black_ground[arr_snake[i][0]][arr_snake[i][1]], \"◆\", 2);
	}
}
//让蛇动
void snake_move(void)
{
	int i= snake_max_long-1;//100个元素,但是下标只有99

	
	for (i ; i > 0; i--)//循环遍历蛇数组
	{
		//因为我们初始化的蛇数组都为0,所以遍历时若为0说明不是蛇身体上的任一部分,可以过滤掉0的部分
		if (0 == arr_snake[i][1])
		{
			continue;
		}
			//把前一个节点的x坐标给后一个节点,新的蛇的位置装在了数组中
			arr_snake[i][0] = arr_snake[i - 1][0];//就是x的坐标
			arr_snake[i][1] = arr_snake[i - 1][1];
			arr_snake[i][2] = arr_snake[i - 1][2];
	}
	//蛇头
	 arr_snake[0][2] = snake_dir;//将上下左右的移动赋值给它以进行下一步的判断(南北时1和-1,东西时2和-2)
	if (to_east == arr_snake[0][2] || to_west == arr_snake[0][2])//当输入的键是左右时执行if,上下执行else
	{
		arr_snake[0][1] += arr_snake[0][2];//左右移动列动,当输入的是左右时就朝当前位置加输入方向大小 (-2和2)位移
	}
	else
	{
		arr_snake[0][0] += arr_snake[0][2];//上下移动行动,当输入的是上下时就朝当前位置加输入方向大小(-1和1)位移
	}
	draw_snake();
}
//去除旧蛇残留
void empty_snake(void)
{
	int i = 0;
	for (i = 0; arr_snake[i][0] != 0; i++)
	{
		strncpy(&black_ground[arr_snake[i][0]][arr_snake[i][1]], \"  \", 2);
	}
}
//改变方向
void change_dir(void)
{
	if (GetAsyncKeyState(\'W\'))
	{
		if(arr_snake[0][2]!=to_south)
			{
				snake_dir = to_north;
			}
	}
	else if (GetAsyncKeyState(\'S\'))
	{
		if (arr_snake[0][2] != to_north)
		{
			snake_dir = to_south;
		}
	}
	else if (GetAsyncKeyState(\'A\'))
	{
		if (arr_snake[0][2] != to_east)
		{
			snake_dir = to_west;
		}
	}
	else if (GetAsyncKeyState(\'D\'))
	{
		if (arr_snake[0][2] != to_west)
		{
			snake_dir = to_east;
		}
	}
}

//蛇死亡判断
bool snake_die(void)
{
	if (to_west == arr_snake[0][2] || to_east == arr_snake[0][2])
	{
		//老蛇左右移动的时候行不动列动,arr_snake[0][0](行),arr_snake[0][1] + arr_snake[0][2](列)
		//这里代表的是列坐标+输入的键位大小,即是下一个坐标,并对下一个坐标进行判断
		//strncmp若返回0则代表两个比较的字符串相等(需要的参数是字符串的首地址)
		if (0 == (strncmp(&black_ground [arr_snake[0][0]]  [arr_snake[0][1]+arr_snake[0][2]], \"◆\", 2) /*||  0 == (strncmp(&black_ground[arr_snake[0][0]][arr_snake[0][1] + arr_snake[0][2]], \"●\", 2))*/))//背景上蛇头的下一个点
		{
			return false;
		} 
	}
	else
	{
		//列不动行动
		if (0 == (strncmp(&black_ground [arr_snake[0][0] +arr_snake[0][2]]  [arr_snake[0][1]], \"◆\", 2) /*|| 0 == (strncmp(&black_ground[arr_snake[0][0] + arr_snake[0][2]][arr_snake[0][1]], \"●\", 2))*/))
		{
			return false;
		}
	}
	return true;
}

//产生食物
void snake_food(void)
{
	//产生随机坐标
	
	//判断是否需要产生新的食物
	if (crea_food == 0)//不需要产生食物
	{
		return ;
	}

	srand((unsigned int)time(NULL));
	while (1)
	{
		int mark = 1;
		food_x = (rand() % 18) + 2;//实际范围应该是1~21,随机范围低于21都行,(0~20)+1==1~21
		food_y = (rand() % 25) + 2;
		int i;//遍历蛇身

		for (i = 0; arr_snake[i][0] != 0; i++)
		{
			if (food_x == arr_snake[i][1] && food_y == arr_snake[i][0])//食物的横纵坐标和蛇的横纵坐标做对比,若重合,则重新产生一个随机数
			{
				 mark = 0;//标记当前的不满足不重合的条件,不能跳出while循环
				 break;//一有重合部分就跳出for循环,不用每个节点都判断是否重合,提高效率
			}
		}
		if (mark != 0)
		{
			break;//满足条件后跳出while循环
		}
		
	}
	
	//画食物
	strncpy(&black_ground[food_y][food_x*2], \"※\", 2);//横坐标乘2,两字节,背景数组为[y][x]
	crea_food = 0;//产生食物后赋值一个0,防止又有食物产生
}

//蛇变长
void snake_up(void)
{
	//蛇头坐标跟食物坐标重合时尾巴增长1
	if (arr_snake[0][0]==food_y && arr_snake[0][1]==food_x*2 )
	{
		//增长
		if (arr_snake[0][2] == to_east )
		{									
			arr_snake[snake_long + 1][0] = arr_snake[snake_long][0];//向东西移动时纵坐标不变
			arr_snake[snake_long + 1][1] = arr_snake[snake_long][1] + to_west ;//向东移动时蛇尾坐标往西加一格
			arr_snake[snake_long + 1][2] = arr_snake[snake_long][2];//方向不变
		}
		else if (arr_snake[0][2] == to_west)
		{
			arr_snake[snake_long + 1][0] = arr_snake[snake_long][0];//向东西移动时纵坐标不变
			arr_snake[snake_long + 1][1] = arr_snake[snake_long][1] + to_east;
			arr_snake[snake_long + 1][2] = arr_snake[snake_long][2];//方向不变
		}
		else if (arr_snake[0][2] == to_north)
		{
			arr_snake[snake_long + 1][0] = arr_snake[snake_long][0] + to_south;
			arr_snake[snake_long + 1][1] = arr_snake[snake_long][1] ;//向上下移动时横坐标不变
			arr_snake[snake_long + 1][2] = arr_snake[snake_long][2];//方向不变
		}
		else if ( arr_snake[0][2] == to_south)
		{
			arr_snake[snake_long + 1][0] = arr_snake[snake_long][0] + to_north;
			arr_snake[snake_long + 1][1] = arr_snake[snake_long][1];//向东西移动时纵坐标不变
			arr_snake[snake_long + 1][2] = arr_snake[snake_long][2];//方向不变
		}

		snake_long++;
		crea_food = 1;//重置食物标记为true
		g_score += 10;//吃一次食物加10分

	}
}

//记分
void score(void)
{
	COORD rd;
	rd.X = 55;
	rd.Y = 15;
	//设置光标位置在游戏界面右侧
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), rd); 
	printf(\"分数:%d\", g_score);
	COORD sd;
	sd.X = 55;
	sd.Y = 16;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), sd);
	if (to_east == arr_snake[0][2])
	{
		printf(\"对对对,向左\");
	}
	if (to_west == arr_snake[0][2])
	{
		printf(\"对对对,向右\");
	}
	if (to_north == arr_snake[0][2])
	{
		printf(\"对对对,向下\");
	}
	if (to_south == arr_snake[0][2])
	{
		printf(\"对对对,向上\");
	}
	
}

int main(void)
{
	//显示首页
	firstpage();
	//首页音乐
	firstpage_music();

	//空格进入游戏界面
	startgame();

	//音乐停止
	stopmusic();
	game_music();

	//清空控制台界面以显示背景
	empty_cmd();

	//随机位置显示蛇,因为只需要显示一开始的一次,因此需要放在游戏外
	snake_pos();
	
	//背景,重复调用函数内容以画背景
	while (1)
	{
			empty_cmd();
			snake_food();//产生食物
			
			change_dir();//改变方向
			snake_up();//蛇变长
			empty_snake();//去除旧蛇残留
			
			if (false == snake_die())
			{
				printf(\"恭喜你,你死了\\n\");
				printf(\"辣鸡,分数才: %d\\n\", g_score);
				break;
			}
			snake_move();//蛇动
			background();//背景
			score();//分数
			Sleep(100); 
		
	}
	system(\"pause\");
	return 0;
}

头文件

#define	snake_max_long 30
#define	M 3//3代表每个数组里面要装三个元素,y,x,方向
//实际上横坐标只有x=48/2=24
//有23个两字节的符号,所以下标范围是0~22,除开边框就是1~21,减去蛇初始长度就是横坐标随机数的产生范围

//实际纵坐标有y=29,所以下标范围0~28
char black_ground[29][48] = { \"◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
	                 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
	                 \"◆                                          ◆\\n\",
					 \"◆                                          ◆\\n\",
					 \"◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆\\n\" };
//枚举方向
enum { to_east = 2, to_west = -2, to_north = -1, to_south = 1 };//东西北南

//蛇数组
//行的位置写多少,蛇就最长是多少
int arr_snake[snake_max_long][3] = { 0 };

//蛇的方向
int snake_dir = to_east;

int crea_food = 1;//初始化为1,代表需要产生食物
//定义食物坐标为全局变量方便在蛇变长函数中使用
int food_x;
int food_y;

//记录蛇长
int snake_long = 2;//3个,下标0~2,所以长度为2

//分数
int g_score = 0;

这个运行出来的贪吃蛇撞自己不会死,希望有大佬看见的话能否在留言告诉我蛇死亡判断那里是否有错误或者其他地方有错误,感激不尽。

详细的各个函数模块的解析将会在最大的bug解决后贴出。

收藏 打印