欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言贪吃蛇—基于EasyX图形库

程序员文章站 2024-03-18 10:04:04
...

一、编译环境

1、VS2017(VC++6.0也可以)
2、EasyX库(C/C++的图形库)

 EasyX Library for C++ (Ver:2018春分版)
 http://www.easyx.cn
 graphics.h

C语言贪吃蛇—基于EasyX图形库

二、代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>

typedef struct body {
	int x, y;   //每节蛇身坐标
	struct body *pre, *next;  //双向链表
}SnakeBody;

typedef struct snake {        //用线性表存储蛇的资料

	SnakeBody  *head, *tail;   //链式线性表
	char headDirection; // sedf  四个键表示左上下右四个方向
	char tailDirection;
	int len;       //表长
} Snake;

Snake * createsanke()   //生成空的蛇
{
	Snake  * s;
	s = (Snake *)malloc(sizeof(Snake));
	s->head = NULL;
	s->tail = NULL;
	s->len = 0;
	return s;
}

void initbeginmap(int width, int height)   //绘制背景
{
	int i = 0, j = 0;
	setlinestyle(PS_SOLID, 1);
	setcolor(BLUE);
	for (i = 0; i <= height; i++)
		line(0, i * 10, 640, i * 10);
	for (i = 0; i <= width; i++)
		line(i * 10, 0, i * 10, 480);
	setcolor(BLACK);
	setfillcolor(BLACK);
	solidrectangle(140,130,150,300);
	solidrectangle(200,80,350,90);
	solidrectangle(400,300,410,130);
	solidrectangle(200,340,350,350);
}


void initSnake(Snake *s, int x, int y, int len)  //生成长度为3,x,y为起点的蛇
{
	int i;
	SnakeBody *newbody;
	s->len = len;
	s->headDirection = 'e';
	//s->tailDirection='e';
	setlinestyle(PS_SOLID, 1);
	setcolor(YELLOW);
	setfillcolor(GREEN);

	for (i = 0; i < len; i++)
	{
		//尾插法创建双向链表(蛇身的数据:坐标)
		newbody = (SnakeBody *)malloc(sizeof(SnakeBody));
		newbody->next = NULL;
		newbody->pre = NULL;
		newbody->x = x;
		newbody->y = y + i;
		if (i == 0)
		{           //第一个节点创建
			s->head = s->tail = newbody;
		}
		else
		{         //其他节点创建
			newbody->pre = s->tail;
			s->tail->next = newbody;
			s->tail = newbody;
		}
		//根据蛇身坐标绘图
		fillrectangle(x * 10 + 1, (y + i) * 10 + 1, x * 10 + 10 - 1, (y + i) * 10 + 10 - 1);

	}

}

void putApple(int x, int y)  //在指定x,y位置放一个苹果
{
	setcolor(BLUE);
	setfillcolor(RED);
	int p = x * 10 + 5,q=y*10+5;
	fillcircle(x * 10 + 5, y * 10 + 5, 5);
}

int eatTest(Snake *s, int m, int n)   //判断前进路上是否碰到苹果
{
	switch (s->headDirection)  //探测下个位置是否是苹果
	{
	case 's':         //蛇向左运动,则前一个位置如果是苹果,则可以吃到,返回1
		if (s->head->x - 1 == m && s->head->y == n)
			return 1;
		break;
	case 'e':
		if (s->head->x == m && s->head->y - 1 == n)
			return 1;
		break;
	case 'd':
		if (s->head->x == m && s->head->y + 1 == n)
			return 1;
		break;
	case 'f':
		if (s->head->x + 1 == m && s->head->y == n)
			return 1;
		break;
	}
	return 0;
}

int moveSnake(Snake *s, int m, int n) {
	//按照蛇的运行方向移动一个位置
	SnakeBody * p;
	int flag = 0;
	if (eatTest(s, m, n) == 1)
	{               //创建新的蛇头节点
		p = (SnakeBody *)malloc(sizeof(SnakeBody));
		p->x = m;
		p->y = n;
		flag = 1;
	}
	else
	{
		p = s->tail;         //删除尾节点
		s->tail = p->pre;
		s->tail->next = NULL;
		setcolor(YELLOW);
		setfillcolor(GREEN);
		fillrectangle(p->x * 10 + 1, (p->y) * 10 + 1, p->x * 10 + 10 - 1, (p->y) * 10 + 10 - 1);
	}
	s->head->pre = p;
	p->pre = NULL;
	p->next = s->head;
	s->head = p;

	//	p->derect=s->headDirection; 
		//根据蛇的运动方向,设置蛇头(p指向的节点)坐标
	if (s->headDirection == 's')
	{
		p->x = p->next->x - 1;
		p->y = p->next->y;
	}
	else if (s->headDirection == 'e')
	{
		p->x = p->next->x;
		p->y = p->next->y - 1;
	}
	else if (s->headDirection == 'd')
	{
		p->x = p->next->x;
		p->y = p->next->y + 1;
	}
	else if (s->headDirection == 'f')
	{
		p->x = p->next->x + 1;
		p->y = p->next->y;
	}
	//画蛇头
	setcolor(YELLOW);
	setfillcolor(GREEN);
	fillrectangle(p->x * 10 + 1, (p->y) * 10 + 1, p->x * 10 + 10 - 1, (p->y) * 10 + 10 - 1);

	return flag;
}


int issnakedead(Snake *s)
{
	int x = s->len;
	SnakeBody * p;
	p = s->head->next;
	if (s->head->x >= 64 || s->head->x < 0 || s->head->y >= 48 || s->head->y < 0		 //判断是否碰到了边框
		|| (s->head->x >= 14 && s->head->x < 15 && s->head->y >= 13 && s->head->y < 30)  //是否碰到了障碍物(下面四个都是)
		|| (s->head->x >= 40 && s->head->x < 41 && s->head->y >= 13 && s->head->y < 30) 
		|| (s->head->x >= 20 && s->head->x < 35 && s->head->y >= 8 && s->head->y < 9)
		|| (s->head->x >= 20 && s->head->x < 35 && s->head->y >= 34 && s->head->y < 35)) 
		return 1;
	else if(x!=0){
		while (p)
		{
			if (s->head->x == p->x&&s->head->y ==p-> y)		//判断是否头尾相撞
				return 1;
			p = p->next;
			x--;
		}
	}
	else return 0;
}
int main()
{
	Snake *snake = NULL;
	int score = 0;
	int k = 0;
	int m, n, flag = 0;
	char fenshu[50];
	initgraph(640, 600);
	srand((int)time(0));
	setbkcolor(YELLOW);
	cleardevice();
	initbeginmap(64, 48);     //设置背景
	setwritemode(R2_XORPEN); // 设置 XOR 绘图模式
	m = rand() % 32 + 1;
	n = rand() % 20 + 1;
	snake = createsanke();  //创建空蛇
	initSnake(snake, 32, 24, 3);  // 初始化长度为3的蛇	
	putApple(m, n);     //设定一个固定的苹果 
	char c = ' ';
	int speed = 250;
	outtextxy(0, 550, "当前速度:");
	outtextxy(300, 550, "s:向左");
	outtextxy(380, 550, "f:向右");
	outtextxy(460, 550, "e:向上");
	outtextxy(540, 550, "d:向下");
	outtextxy(300, 520, "1-7:变速");
	outtextxy(380, 520, "空格:暂停");
	outtextxy(480, 520, "ESC:结束游戏");
	settextcolor(RED);
	outtextxy(80, 550, '3');
	int pause = 0;
	while (1)    //27为ESC键
	{
		// 获取按键
		if (_kbhit())
		{
			c = _getch();

			if (c == 27) break;

			// 根据按键设置蛇的运动方向
			switch (c)
			{
			case 's':   //向左,原方向为上下才可以变
				if (snake->headDirection == 'e' || snake->headDirection == 'd')	snake->headDirection = c; break;
			case 'f':   //向右,原方向为上下才可以变
				if (snake->headDirection == 'e' || snake->headDirection == 'd')	snake->headDirection = c; break;
			case 'e':   //向上,原来为左右才变化
				if (snake->headDirection == 's' || snake->headDirection == 'f')	snake->headDirection = c; break;
			case 'd':   //向下,原来为左右才变化
				if (snake->headDirection == 's' || snake->headDirection == 'f')	snake->headDirection = c; break;
			case ' ':   //向下,原来为左右才变化
					outtextxy(200, 500, "已暂停,按任意键继续...");
					system("pause");
					outtextxy(200, 500, "                                                    ");
					break;
					//改变蛇的移动速度(1-7)
			case '1': speed = 350; outtextxy(80, 550, '1'); break;
			case '2': speed = 300; outtextxy(80, 550, '2'); break;
			case '3': speed = 250; outtextxy(80, 550, '3'); break;
			case '4': speed = 200; outtextxy(80, 550, '4'); break;
			case '5': speed = 150; outtextxy(80, 550, '5'); break;
			case '6': speed = 100; outtextxy(80, 550, '6'); break;
			case '7': speed = 50;  outtextxy(80, 550, '7'); break;
			}
		}
		flag = moveSnake(snake, m, n);   //按照蛇的运动方向移动
		settextcolor(BLUE);
		outtextxy(0, 520, "得分:");
		sprintf(fenshu, "%d", k);
		settextcolor(RED);
		outtextxy(80, 520, fenshu);
		if (flag == 1)
		{
			setcolor(BLUE);
			setfillcolor(RED);
			fillcircle(m * 10 + 5, n * 10 + 5, 5);
			m = rand() % 62;
			n = rand() % 30;
			if ((m == 14 && n >= 13 && n <= 30)
			|| (m == 40 && n >= 13 && n <= 30)
			|| (n == 8 && m >= 20 && m <= 35)
			|| (n == 34 && m >= 20 && m <= 35))
			{
				m = m + 1;
				n = n + 1;
			}
			putApple(m, n);
			flag = 0;
			k++;
			sprintf(fenshu, "%d", k--);
			settextcolor(YELLOW);
			outtextxy(80, 520, fenshu);
			sprintf(fenshu, "%d", k++);
			settextcolor(RED);
			outtextxy(80, 520, fenshu);
		}

		// 延时
		Sleep(speed - k * 10);
		if (issnakedead(snake) == 1)
		{

			outtextxy(200, 500, "Game Over!");
			outtextxy(200, 550, "按任意键退出");
			_getch();
			break;
			if (_kbhit())
				exit(0);
		}
	}

	closegraph();
	return 0;
}