贪吃蛇(C语言Windows控制台)

 

读万卷书,行万里路——木子成

/***********************************************
map数组:二维矩阵值-1为游戏墙
map数组:二维矩阵值1为蛇头
map数组:二维矩阵值2为蛇身
map数组:二维矩阵值3为食物
程序同一运行多次游戏时会暂停3秒
吃到一个食物,蛇移动速度加快,最快速度有阈值
方向键英文小写输入有效
屏幕最大化体验最佳
上:w、下:s、左:a、右:d
暂停:q、退出游戏
*************************************************/

main.c

#include<windows.h>

void pr_map();		//打印墙
void pr_startG();	//打印游戏开始界面
void deal_key();	//处理按键响应
void init_map();	//初始化游戏数据
void wait_start();

char Pause = 0;		//游戏暂停开关
char GameStart = 0;	//撞墙标识



void main()
{
	init_game();	//初始化游戏数据
	while (1)
			if (!GameStart)		//游戏未开始界面
			{
				pr_start();		//打印游戏开始界面
				wait_start();
			}
			else				//游戏开始界面
			{
				deal_key();		//响应按键
				if (!Pause)
				{
					pr_game();	//打印游戏界面
					update_snake();//更新地图
				}
			}
}

init.c

#include<time.h>
#include<stdlib.h>

#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define M 24
#define snake_size 3

int map[M][M];

extern char dir_key;
extern char down_key;
extern int speed;
extern int score;

void update_food();

typedef struct Snakes
{
	int x;
	int y;
	struct Snakes* next;
}snake;
snake* head;



//初始化地图
void init_game()
{
	snake* p = (snake*)malloc(sizeof(snake));
	head = (snake*)malloc(sizeof(snake));
	p = head;
	srand((int)time(NULL));			//女娲在此播下随机种子

	//蛇头位置
	int i, j;
	int x = rand() % (M / 2) + 3;
	int y = rand() % (M / 2) + 3;

	//循环进行游戏初始化
	for (i = 0; i < M; i++)
		for (j = 0; j < M; j++)
			map[i][j] = 0;
	speed = 200;
	score = 0;

	//食物总在蛇头右下方
	update_food();

	//随机贪食蛇位置、方向  
	if (x < y)							//蛇身横向
	{
		for (i = 0; i < snake_size; i++)
			if (i == 0)
			{
				map[x][y] = 1;
				head->x = x;
				head->y = y;
			}
			else
			{
				map[x - i][y] = 2;

				snake* q = (snake*)malloc(sizeof(snake));
				p->next = q;

				q->x = x - i;
				q->y = y;

				p = q;
				p->next = NULL;
			}
		dir_key = right;	//初始化蛇移动方向
	}
	else								//蛇身纵向
	{
		for (i = 0; i < snake_size; i++)
			if (i == 0)
			{
				map[x][y] = 1;
				head->x = x;
				head->y = y;
			}
			else
			{
				map[x][y - i] = 2;

				snake* q = (snake*)malloc(sizeof(snake));
				p->next = q;

				q->x = x;
				q->y = y - i;

				p = q;
				p->next = NULL;
			}
		dir_key = down;
	}

	//标记游戏墙,数组外围一圈
	for (i = 0; i < M; i++)
		for (j = 0; j < M; j++)
			if (i == 0 || i == M - 1 || j == 0 || j == M - 1)
				map[i][j] = -1;
}

function.c

#include<stdlib.h>
#include<conio.h>
#include<windows.h>


#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'q'
#define out 'p'
#define M 24		//游戏地图尺寸

void pr_map();
void init_game();


typedef struct Snakes
{
	int x;
	int y;
	struct Snakes* next;
}snake;

extern int map[M][M];
extern snake* head;
extern char GameStart;
extern char Pause;


char key[4] = { up, down, left, right };	//方便处理蛇移动是否反向,反向不响应,并且游戏正常
char dir_key;
char down_key;
int score = 0;		//游戏得分
int speed = 200;	//蛇移动速度


//移动光标
void gotoxy(int x, int y)
{
	COORD pos;
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(hOutput, pos);
	// 隐藏光标 
	CONSOLE_CURSOR_INFO cursor;
	cursor.bVisible = FALSE;
	cursor.dwSize = sizeof(cursor);
	SetConsoleCursorInfo(hOutput, &cursor);
}


//添加食物
void update_food()
{
	int x, y;

	while (1)
	{
		x = 1 + rand() % (M - 2);
		y = 1 + rand() % (M - 2);
		if (map[x][y] == 0)
		{
			map[x][y] = 3;
			break;
		}
	}
}


//头部前进
void go_key()
{
	snake* new_head = (snake*)malloc(sizeof(snake));	//分配存储空间
	map[head->x][head->y] = 2;				//头部变身体

	switch (dir_key)
	{
	case up:
		new_head->x = head->x;
		new_head->y = head->y - 1;	break;
	case down:
		new_head->x = head->x;
		new_head->y = head->y + 1;	break;
	case left:
		new_head->x = head->x - 1;
		new_head->y = head->y;		break;
	case right:
		new_head->x = head->x + 1;
		new_head->y = head->y;		break;
	}

	if (map[new_head->x][new_head->y] == 3)		//吃掉食物
	{
		update_food();
		score += 10;
		speed = (speed < 100) ? speed + 0 : speed - 50;		//加快速度
	}

	new_head->next = head;
	head = new_head;

	map[head->x][head->y] = 1;		//标记头部

	Sleep(speed);					
}


//消除尾巴
void cat_tail()
{
	snake* tail = (snake*)malloc(sizeof(snake));
	tail = head;

	while (tail->next->next != NULL)		//下一节的下一节身体存在
		tail = tail->next;

	map[tail->next->x][tail->next->y] = 0;	//消除尾巴(头部加一方式前进)

	free(tail->next);						//释放内存
	tail->next = NULL;						//尾部结构指向空,方便寻找
}


//更新蛇的位置
void update_snake()
{
	switch (dir_key)
	{
	case up:
		if (map[head->x][head->y - 1] == 0 || map[head->x][head->y - 1] == 3)
		{
			if (map[head->x][head->y - 1] == 0)		//1----如果没有吃到食物将消除尾巴
				cat_tail();								//1、2顺序勿换,head更新,cat_tail()易失效
			go_key();								//2----头部前进
		}
		else if (map[head->x][head->y - 1] == -1 || map[head->x][head->y - 1] == 2)
		{
			GameStart = 0;
			break;
		}
		break;

	case down:
		if (map[head->x][head->y + 1] == 0 || map[head->x][head->y + 1] == 3)
		{
			if (map[head->x][head->y + 1] == 0)
				cat_tail();
			go_key();
		}
		else if (map[head->x][head->y + 1] == -1 || map[head->x][head->y + 1] == 2)
		{
			GameStart = 0;
			break;
		}
		break;

	case left:
		if (map[head->x - 1][head->y] == 0 || map[head->x - 1][head->y] == 3)
		{
			if (map[head->x - 1][head->y] == 0)
				cat_tail();
			go_key();
		}
		else if (map[head->x - 1][head->y] == -1 || map[head->x - 1][head->y] == 2)
		{
			GameStart = 0;
			break;
		}
		break;

	case right:
		if (map[head->x + 1][head->y] == 0 || map[head->x + 1][head->y] == 3)
		{
			if (map[head->x + 1][head->y] == 0)
				cat_tail();
			go_key();
		}
		else if (map[head->x + 1][head->y] == -1 || map[head->x + 1][head->y] == 2)
		{
			GameStart = 0;
			break;
		}
		break;
	}
}


//处理按键
void deal_key()
{
	if (_kbhit())
	{
		switch (down_key = _getch())		
		{
		case up:
			if (dir_key == key[1])		//反向移动指令不生效
				break;
			dir_key = down_key;			//无论此指令是否意味着撞墙,交由update_snake()函数处理
			break;

		case down:
			if (dir_key == key[0])
				break;
			dir_key = down_key;
			break;

		case left:
			if (dir_key == key[3])
				break;
			dir_key = down_key;
			break;

		case right:
			if (dir_key == key[2])
				break;
			dir_key = down_key;
			break;

		case out:
			exit(0);
		}	
		if (down_key == stop)
		{
			if (Pause == 0)
				Pause = 1;
			else
				Pause = 0;
		}
	}
}


//等待用户按任意键开始游戏
void wait_start()
{
	while (1)		//等待用户按任意键开始游戏
		if (_kbhit())
		{
			GameStart = 1;	//游戏开始开关打开
			break;
		}
	pr_map();		//打印地图
	init_game();	//同一运行程序,游戏多次进行时初始化游戏数据
}

print.c

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<windows.h>

#define M 24

extern map[M][M];
extern GameStart;
extern score;

void gotoxy(int x, int y);

//打印得分
void pr_score()
{
	if(score / 100000000 >= 1)		//多判断结构意在保证得分显示居中显示框
	{
		gotoxy(45 + 21, 4);
		printf("%d", score);
	}
	else if (score/1000000>=1)
	{
		gotoxy(45 + 22, 4);
		printf("%d", score);
	}
	else if (score / 10000 >= 1)
	{
		gotoxy(45 + 23, 4);
		printf("%d", score);
	}
	else if (score / 100 >= 1)
	{
		gotoxy(45 + 23, 4);
		printf("%d", score);
	}
	else
	{
		gotoxy(45 + 24, 4);
		printf("\033[40;36m%d\033[0m", score);
	}
	system("color 0E");		//这里其实是一个bug,但是无意间发现此法可让蛇身、食物、得分显示闪烁
}

//打印地图
void pr_map()
{
	system("cls");		//清除此时屏幕上显示的游戏提示
	system("color 0E");	//设置屏幕颜色
	for (int i = 0; i < M; i++)
		for (int j = 0; j < M; j++)
		{
			if (map[i][j] == -1)
			{
				gotoxy(i * 2 + 45, j + 5);
				printf("■");
			}
		}
	gotoxy(45 + 16, 4);
	printf("■"); 

	gotoxy(45 + 32, 4);
	printf("■");

	gotoxy(45 + 16, 3);
	printf("■■■■■■■■■");
}



//打印游戏界面
void pr_game()
{
	for (int i = 0; i < M; i++)
		for (int j = 0; j < M; j++)
		{
			if (map[i][j] == 0)
			{
				gotoxy(i * 2 + 45, j + 5);
				printf("  ");
			}
			else if (map[i][j] == 1)
			{
				gotoxy(i * 2 + 45, j + 5);
				printf("\033[40;33m●\033[0m");
			}
			else if (map[i][j] == 2)
			{
				gotoxy(i * 2 + 45, j + 5);
				printf("○");
			}
			else if (map[i][j] == 3)
			{
				gotoxy(i * 2 + 45, j + 5);
				printf("\033[40;31m⊙\033[0m");
			}
		}
	pr_score();
}


//打印游戏未开始界面
void pr_start()
{
	pr_map();
	if(score!=0)
		pr_score();

	gotoxy(61, 11);
	printf("▁▁▁▁▁▁▁▁");
	gotoxy(61, 12);
	printf("▏请切换最大屏  ▏");
	gotoxy(61, 13);
	printf("▔▔▔▔▔▔▔▔");


	gotoxy(57, 14);
	printf("▁▁▁▁▁▁▁▁▁▁▁▁");
	gotoxy(57, 15);
	printf("▏请切换英文小写输入法  ▏");
	gotoxy(57, 16);
	printf("▔▔▔▔▔▔▔▔▔▔▔▔");


	gotoxy(53, 17);
	printf("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁");
	gotoxy(53, 18);
	printf("▏上: w ▏下: s ▏左: a ▏右: d ▏");
	gotoxy(53, 19);
	printf("▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔");

	gotoxy(53, 20);
	printf("▏暂停:q▏              ▏退出:p▏");
	gotoxy(53, 21);
	printf("▔▔▔▔                ▔▔▔▔");


	gotoxy(58, 25);
	printf("▁▁▁▁▁▁▁▁▁▁▁");
	gotoxy(58, 26);
	printf("▏请按任意键开始游戏  ▏");
	gotoxy(58, 27);
	printf("▔▔▔▔▔▔▔▔▔▔▔");


	Sleep(3000);		//防止蛇撞墙后,用户按任意键立马继续游戏
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值