贪吃蛇小游戏(C语言实现)

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>
#include<stdbool.h>
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'

void welcome(void);				//欢迎界面的打印
void gotoxy(int x, int y);		//光标跳转
void gotoprint(int x, int y);	//光标跳转打印方格
void gotodelete(int x, int y);	//光标跳转打印空格实现删除
void creatgraph(void);			//地图的打印
void creatfood(void);			//随机食物的打印
int clickcontrol(void);			//循环主函数
void changebody(void);			//用于移动变换蛇的位置
int judge(void);				//判断游戏是否结束
void finish(void);				//结束页面的打印
void eatfood(void);				//吃到食物后的处理

typedef struct Snake {			//蛇的节点声明
	int x;	
	int y;
	struct Snake* next;
}snake;		
snake* head;					//蛇头的全局变量

struct FOOD{
	int x;
	int y;
}food;							//食物的结构定义

char name[20];					//用户名
int score = 0;					//得分
char click = '1';				//输入储存

int main(void)					//主函数负责函数调用
{
	system("color 0B");			//system函数,没用过,这一步用来改变控制台字符颜色
	welcome();					//先是欢迎界面
	creatgraph();				//然后打印地图
	creatfood();				//然后创造第一个食物
	if (clickcontrol() == 0)	//主要循环函数——一旦返回0就结束整个主函数
		return 0;
	return 0;
}

void welcome(void)				//这个好说,直接跳转打印就行
{	
	gotoxy(10, 10);
	printf("welcome to my game,注意反向即为自杀");
	gotoxy(10, 12);
	printf("Please enter your name:");
	scanf_s("%s", name,20);
	system("cls");
}

void gotoxy(int x, int y)							//这个函数抄的,毕竟不会用window库
{
	// 更新光标位置 
	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 gotoprint(int x, int y)						//跳转打印方块
{
	gotoxy(x, y);
	printf("■");
}

void gotodelete(int x, int y)						//跳转打印空格
{													//很关键的,空格要打印两个,这是因为方块实际上是一个长宽比为2:1的字符
	gotoxy(x, y);									//因而想要遮盖方块应该打印两个空格,不然就会得到一条弯曲不堪的蛇
	printf("  ");
}

void creatgraph(void)								//地图打印
{
	for (int cnt = 0; cnt <= 56; cnt += 2)			//x轴要留意,cnt每次+2,因为方块长度为2
	{												//地图大小设置好
		gotoprint(cnt, 0);
		gotoprint(cnt, 26);
	}
	for (int cnt = 1; cnt <= 25; cnt++)
	{
		gotoprint(0, cnt);
		gotoprint(56, cnt);
	}
	gotoxy(60, 10);
	printf("score:%d", score);
	gotoxy(60, 9);
	printf("Hello %s", name);
	snake* p, * q;									//创建好原有蛇长
	head = (snake*)malloc(sizeof(snake));			//并且分配好空间
	p = (snake*)malloc(sizeof(snake));
	q = (snake*)malloc(sizeof(snake));
	head->x = 16;
	head->y = 15;
	p->x = 16;
	p->y = 16;
	q->x = 16;
	q->y = 17;
	head->next = p;
	p->next = q;
	q->next = NULL;									//注意这个时候还不用打印蛇,打印蛇交给changebody函数
}

void creatfood(void)
{	
	srand((int)time(NULL));							//设置好随机数种子,用到时间函数
	bool flag = false;	
	while (!flag)									//创建食物的循环——考虑到食物创建失败
	{
		flag = true;
		food.x = rand() % 53 + 2;					//用上%来得到在的地图内的食物
		food.y = rand() % 25 + 1;
		if (food.x % 2 != 0)
		{
			food.x += 1;							//若随机数x落到奇数要加1,因为方块都在偶数位上
		}
		snake* panduan = head;						//遍历蛇身,判断食物没有直接落到蛇身上,若是,则重新创建食物
		while (panduan != NULL)
		{
			if (food.x == panduan->x && food.y == panduan->y)
			{
				flag = false;
				break;
			}
			panduan = panduan->next;
		}
	}
	gotoxy(food.x, food.y);							//循环结束,说明食物创建完成,则进行打印
	printf("⊙");
}

int clickcontrol(void)
{
	while (1)										//循环主函数
	{
		if (judge() == 0) break;					//每轮开始都先判断,若判断到结束,则退出循环,返回0,
		if (_kbhit())								//在主函数就结束了整个函数
		{											//window库里的,也是抄的,作用应该是获取缓冲区的输入
			click = _getch();
		}
		changebody();								//调用函数
		eatfood();
	}
	return 0;
}

void changebody(void)
{
	int x = head->x;								
	int y = head->y;
	snake* pi = head;
	/*snake* new_head;
	new_head = (snake*)malloc(sizeof(snake));*/				//这里注释掉的教训,不能一上来就直接分配空间,
	while (pi->next->next != NULL)							//不然如果出现输入不对,就会一直分配空间知道内存占满
	{
		pi = pi->next;
	}
	gotodelete(pi->next->x, pi->next->y);					//遍历到蛇尾然后打印空格遮盖方块
	//free(pi->next);
	//pi->next = NULL;
	switch (click)											//switch-case函数分开情况
	{
	case up:
		x = head->x;
		y = head->y - 1;
		break;
	case down:
		x = head->x;
		y = head->y + 1;
		break;
	case left:
		x = head->x - 2;
		y = head->y;
		break;
	case right:
		x = head->x + 2;
		y = head->y;
		break;
	default:break;
	}
	if (x != head->x || y != head->y)						//若蛇头坐标该表,则要创建一个新蛇头
	{
		snake* new_head;
		new_head = (snake*)malloc(sizeof(snake));			//分配空间
		new_head->next = head;
		new_head->x = x;
		new_head->y = y;
		head = new_head;									//注意把全局变量head重新定义,因为这个全局变量应该永远是蛇头
		free(pi->next);										//释放掉蛇尾的内存,并把蛇尾设置为NULL
		pi->next = NULL;
	}
	gotoprint(head->x, head->y);							//打印蛇头——注意这个蛇头是无论如何都要打印的,不能放进if块里面
	Sleep(150);												//不然会导致最开始的情况即没有任何输入的情况出错(方块被全部删完了)
}	//这个Sleep函数用来调语句执行速度(延迟)

void eatfood(void)
{
	if (head->x == food.x && head->y == food.y)			//如果吃到了食物
	{
		creatfood();									//创建一个新食物
		snake* pi = head;
		snake* new_tail;
		new_tail = (snake*)malloc(sizeof(snake));		//创建一个新尾巴
		new_tail->next = NULL;
		while (pi->next != NULL)
		{
			pi = pi->next;
		}
		pi->next = new_tail;
		new_tail->x = 60;								//把尾巴的坐标乱设一下,反正在changebody那里都会被删除然后释放的
		new_tail->y = 0;
		score += 10;
		gotoxy(60, 10);
		printf("score:%d", score);
	}

}

int judge(void)
{
	snake* pi = head;
	if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)			//撞墙判断
	{
		finish();
		return 0;
	}
	while (pi->next != NULL)
	{
		pi = pi->next;															//撞自己判断
		if (head->x == pi->x && head->y == pi->y)								//链表遍历
		{
			finish();
			return 0;
		}

	}
	return 1;
}

void finish(void)
{
	system("cls");																//结束页面先清空页面
	gotoxy(25, 13);
	printf("game over");
	snake* pi = head, * temp;
	while (pi != NULL)															//关键,释放整个链表的内存
	{
		temp = pi->next;
		free(pi);
		pi = temp;
	}
	system("pause");															//等待下一步输入
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值