C++实现贪吃蛇源码(EasyX图形库)

如果你不知道怎么安装EasyX图形库
链接: 点击这里.
这个作者的安装教程很好,当时本人也是看这个一步一步做的
另外如果你想要一个写的思路,可以直接看我的源码,一步一步的推敲,也可以直接看这个作者的文章点击查看.
可能你在写的时候会遇到一部分函数使用错误的问题,主要是这个函数outtextxy(),请这样做:vs2019的情况 :项目属性——》配置属性——》高级——》字符集——》使用多字节字符集.就可以了。

这个贪吃蛇源码实现了以下的功能:
**
(1)需要能在界面指定位置(x,y)直接输出对应内容
(2)需要动态数组储存蛇的身体节点
(3)需要能接收键盘指令对贪吃蛇运动方向进行调整
(4)需要随机生成食物
(5)判断蛇是否撞到墙或者自己的身体
(6)在你的计算机的C盘生成一个C:/snakeTemp/score.txt的路径的一个文本文件,在你不再玩的时候请记得删除这个文件,这个文本是用来记录你的历史最高得分

**

#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<graphics.h>
#include<easyx.h>
#include<conio.h>
#include<windows.h>
#include<time.h>
#include<cstdlib>
#include<fstream>
#include<io.h>
#include <direct.h>
using namespace std;

//项目启动于2021.1.31日
//author:芽孢子
//本次修改时间:2021.2.6日
//实现:按下p暂停,添加了箭头操作,
//本次修改时间:2021.2.5日
//增加了蛇会咬死自己,成功的实现了蛇的加长(不要给我乱删指针),处理好了文件操作,优化了界面显示
//本次修改时间:2021.2.4日
//实现:修整了第三个地图的bug,优化了蛇的死亡的判断,增加了最高分数的的显示功能(使用了文件读取)
//本次修改时间:2021.2.3日
//实现:修改一个蛇身的加长的bug,做了第二张地图,初始界面,死亡动画,做了第三个地图
//本次修改时间:2021.2.2日
//实现:食物生成,分数统计,蛇身加长,控制蛇
//另:
//2021.1.31已经实现默认的传参修改能够修改地图中网格的大小
//2021.2.2减少了代码的冗余,实现了能够操控蛇的移动

//生成食物的函数
void setfood();
//判断蛇的死活
void snakeAlive();
//显示玩家的分数
void getScore();
//显示玩家已经死亡
void dead();
//开始的界面
void be();
//生成新的蛇的方法每次的移动都是蛇的刷新与生成
void createsnake(int direction);
//分数文件的读取
int readScore();
//分数文件的写入
void writeScore(int score);

struct snake {
	int x = 1;
	int y = 1;
	snake* next = NULL;
}*p;

//对于这个数据当前的坐标为横56,宽24,这个数据中边界地部分是不可以使用地
//坐标的范围是会随着方块地长度和间隔地变化而变化的,所以不要给我随便修改
const int JFramx = 1400, JFramy = 600, length = 20, interval = 5, sum = length + interval;
const int snakespeed = 95;//蛇的移动速度
int foodx=8, foody=8;//生成食物的坐标
//int lastx=2, lasty=2;//在尾部添加蛇身而准备的参数//尽量生成的数据不要是没有指向的
int score ;//统计玩家的得分
int level = '1';//地基关卡//实际数据大小应该为(1-9)字符型
bool snakearr[60][30];//判断蛇是否死亡的bool数组
string fileName = "C:/snakeTemp/score.txt";

class Main {
public:
	//默认的蛇的生成//可以写在类的内部//但我怕出现bug就不改了
	//坐标只是影响蛇出现的快慢
	//snake e = { 6,6,NULL };
	//snake d = { 6,7,&e };
	snake c = { 6,8,NULL};
	snake b = { 6,9,&c };
	snake a = { 6,10,&b };
	snake* head = &a;
	snake* p = &a;
	int snakeLength = 3;//蛇的长度

	//生成地图的构造参数(默认地图的构造函数)
	//2021.2.1添加构造已无需在修改调用游戏的启动时直接俄new这个构造就行
	//2021.2.4日这个构造不在修改,功能完善了
	Main(int levelNumber) {
		score = 0;
		//先生成上部的方块
		for (int i = 0; i < JFramx / (length + interval); i++) {
			//首先声明颜色,否则第一个格子怪怪的
			setfillcolor(BLUE);
			setcolor(BLUE);
			fillrectangle(i * (length + interval), 0, i * (length + interval) + length, length);
			snakearr[i][0]=1;
			Sleep(30);
		}
		//对中间的方块·的操作决定了关卡的不同的说
				if (levelNumber=='2') {
					for (int i = 1; i <= JFramy / (length + interval)-2; i++) {
						fillrectangle(0, i * (length + interval), length, i * (length + interval) + length);
						snakearr[0][i]=1;
						if (i!=11&&i!=10&&i!=12) {
							fillrectangle(37*sum,i*sum,37*sum+length,i*sum+length);
							snakearr[37][i] = 1;
						}
						if (i!=7&&i!=8&&i!=14&&i!=15) {
							fillrectangle(17 * sum, i * sum, 17 * sum + length, i * sum + length);
							snakearr[17][i] = 1;
						}
						fillrectangle((JFramx / (length + interval) - 1) *sum, i * (length + interval), (JFramx / (length + interval) - 1) * (length + interval) + length, i * (length + interval) + length);
						snakearr[JFramx / (length + interval) - 1][i] = 1;
						Sleep(30);
					}
				}
				else if (levelNumber=='3') {
					for (int i = 1; i <= JFramy / sum - 2;i++) {
						fillrectangle(0,i*sum,length,i*sum+length);
						snakearr[0][i]=1;
						for (int i2 = 5; i2 < 9;i2++) {
							for (int i1 = 12; i1 < 16;i1++) {
								snakearr[i1][i2] = 1;
							}
							for (int i1 = 37; i1 < 41;i1++) {
								snakearr[i1][i2] = 1;
							}
						}
						for (int i2 = 7; i2 < 10;i2++) {
							for (int i1 = 24; i1 < 27;i1++) {
								snakearr[i1][i2] = 1;
							}
						}
						for (int i2 = 13; i2 < 16;i2++) {
							for (int i1 = 24; i1 < 27;i1++) {
								snakearr[i1][i2] = 1;
							}
						}
						for (int i2 = 17; i2 < 21; i2++) {
							for (int i1 = 12; i1 < 16; i1++) {
								snakearr[i1][i2] = 1;
							}
							for (int i1 = 37; i1 < 41; i1++) {
								snakearr[i1][i2] = 1;
							}
						}
						if (i==5||i==6) {
							for (int i1 = 12; i1 < 16;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
							for (int i1 = 37; i1 < 41;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
						}
						else if (i==8||i==7) {
							for (int i1 = 12; i1 < 16;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
							for (int i1 = 37; i1 < 41;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
							for (int i1 = 24; i1 < 27;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
						}
						else if (i==9||i==13||i==14||i==15) {
							for (int i1 = 24; i1 < 27;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
						}
						else if (i == 17 || i == 18 || i == 19||i==20) {
							for (int i1 = 12; i1 < 16;i1++) {
								fillrectangle(i1*sum,i*sum,i1*sum+length,i*sum+length);
								Sleep(30);
							}
							for (int i1 = 37; i1 < 41; i1++) {
								fillrectangle(i1 * sum, i * sum, i1 * sum + length, i * sum + length);
								Sleep(30);
							}
						}
						fillrectangle((JFramx / (length + interval) - 1) * (length + interval), i * (length + interval), (JFramx / (length + interval) - 1) * (length + interval) + length, i * (length + interval) + length);
						snakearr[JFramx / (length + interval) - 1][i]=1;
						Sleep(30);
					}
				}
				else {
					//玩家不存在选关的操作时
					level = '1';//令关卡的变量为零
					for (int i = 1; i <= JFramy / (length + interval)-2; i++) {
						fillrectangle(0, i * (length + interval), length, i * (length + interval) + length);
						snakearr[0][i]=1;
						fillrectangle((JFramx / (length + interval) - 1) * (length + interval), i * (length + interval), (JFramx / (length + interval) - 1) * (length + interval) + length, i * (length + interval) + length);
						snakearr[JFramx / (length + interval) - 1][i]=1;
						Sleep(30);
					}
				}
		//底部的生成
		for (int i = 0; i < JFramx / (length + interval); i++) {
			fillrectangle(i * (length + interval), (JFramy / (length + interval) - 1) * (length + interval), i * (length + interval) + length, JFramy - interval);
			snakearr[i][JFramy / (length + interval) - 1]=1;
			Sleep(30);
		}
		Main('s');
	}

	//这个构造完善了,不能在修改,时间2021.2.3
	//蛇的加入构造,其中还有蛇的移动方法
	Main(char numebr) {
		int temp_key = 's';//接受键盘输入的事件的暂时量,为了使蛇的身体不会实现倒退的情况
		while (1) {//接受键盘的事件
			int ch;//接受键盘上的事件的得到的数据
			Sleep(5);
			if (_kbhit()) {
				ch = _getch();
				if (ch == 27) { closegraph();  break; }
				else if ((ch == 'd'||ch==77) && temp_key != 'a') {//向右移动//新加入了判断蛇回退的判断
					temp_key = 'd';
				}else if ((ch == 'w'||ch==72)&&temp_key!='s') {    //向上移动//判断已添加
					temp_key = 'w';
				}else if ((ch == 's'||ch==80)&&temp_key!='w') {   //向上移动//判断已添加
					temp_key = 's';
				}else if ((ch == 'a'||ch==75)&&temp_key!='d') {   //向上移动//判断已添加
					temp_key = 'a';
				}else if (ch=='p') {
					pauseGame();
				}
			}
			//这里是蛇身移动的方法,在没有输入的时候的情况//已经减少了代码的冗余
			if (temp_key=='d') {
				createsnake(1);
			}if (temp_key=='w') {
				createsnake(2);
			}if (temp_key=='s') {
				createsnake(4);
			}if (temp_key=='a') {
				createsnake(3);
			}
		}
	}

	//生成新的蛇的方法每次的移动都是蛇的刷新与生成
	void createsnake(int direction) {
		//直接在生成蛇的时候就直接判断蛇的死亡
		getScore();
		setfood();
		if (head->x==foodx&&head->y==foody) {
			snake* endsnake=new snake;
			endsnake->x = head->x;
			endsnake->y = head->y;
			endsnake->next = head;
			snake* s = new snake;
			 head=endsnake;
		}
		for (p = head; p; p = p->next) {
			clearrectangle(p->x * sum, p->y * sum, p->x * sum + length, p->y * sum + length);
		}
		int tempy = head->y;
		int tempx = head->x;
		int tempx02;
		int tempy02;
		if (direction == 1) { head->x++; }
		else if (direction == 2) { head->y--; }
		else if (direction == 3) { head->x--; }
		else if (direction == 4) { head->y++; }
		for (p = head; p; p = p->next) {
			if (p == head) {
				setcolor(RED);
				setfillcolor(LIGHTRED);
			}
			else {
				setcolor(GREEN);
				setfillcolor(GREEN);
			}
			if (p == head) {
				fillrectangle(p->x * sum, p->y * sum, p->x * sum + length, p->y * sum + length);
			}
			else {
				tempx02 = p->x;
				tempy02 = p->y;
				p->x = tempx;
				p->y = tempy;
				fillrectangle(p->x * sum, p->y * sum, p->x * sum + length, p->y * sum + length);
				tempx = tempx02;
				tempy = tempy02;
			}
		}
		Sleep(snakespeed);
		snakeAlive(level);
	}

	//生成食物的函数
	void setfood() {
		if (head->x == foodx&&head->y==foody) {
			score++;//分数的增加
			addSnake();
			unsigned seed=(time(0));
			srand(seed);
			foody = rand() % 22 + 1;
			if (level=='1') {
				foodx = rand() % 54 + 1;
			}
			else if (level=='2') {
				if (head->x<17) {
					foodx = rand()%17+20;
				}
				else if (head->x<37) {
				foodx = rand()%17+38;
				}
				else if (head->x<55) {
					foodx = rand() % 16 + 1;
				}
			}
			else if (level=='3') {
				if (head->x<12) {
					foodx = rand()%7+16;
				}
				else if (head->x<24) {
					foodx = rand() % 10+27;
				}
				else if (head->x<37) {
					foodx = rand() % 14 + 41;
				}
				else if (head->x<54) {
					foodx = rand() % 12 + 1;
				}
			}
			setfillcolor(LIGHTMAGENTA);
			fillrectangle(foodx*sum,foody*sum,foodx*sum+length,foody*sum+length);
		}
		else {
		setcolor(LIGHTMAGENTA);
		setfillcolor(LIGHTMAGENTA);
		fillrectangle(foodx * sum, foody * sum, foodx * sum + length, foody * sum + length);
		}
	}

	//判断蛇是否死亡
	//本次修改时间:2021.2.4
	//已经优化了特别多了,不要再修改了
	//被调用的上级createSnake();
	void snakeAlive(int level) {
		for (p = head; p;p=p->next) {
			if (head->x==p->x&&head->y==p->y&&p!=head) {
				dead();
				closegraph();
			}
		}
		if (snakearr[head->x][head->y]==1) {
			dead();
			closegraph();
		}
	}

	//使地图显示分数
	void getScore() {
		RECT r = { sum,sum,1200, 550 };
		string s = "你的分数";
		string stemp = to_string(score);
		s += stemp;
		settextcolor(GREEN);
		drawtext(_T(s.c_str()),&r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	}

	//届几个在类外实现了
	void addSnake();
	void dead();
	static void createTempFile();
	static void createTempDirectory();
	void pauseGame();//游戏的暂停方法
};


void Main::pauseGame() {
	bool temp = 1;
	while (temp) {
		if (_kbhit()) {
			temp = 0;
		}
	}
}

void Main::createTempDirectory() {
	const char* temp_directory = "C:/snakeTemp";
	if (_access(temp_directory,0)!=0) {
		_mkdir(temp_directory);
	}
}


//生成文件
 void Main::createTempFile() {
	//下面这个判断在文件存在时返回的为0,于是在不为0时文件就不存在了
	 createTempDirectory();
	if (_access(fileName.c_str(),0)!=0) {
		ofstream temp_os(fileName, ios::app);
		temp_os << '0';
		temp_os.close();
	}
}


void Main::addSnake() {
	snake* endsnake=head,*q=new snake;
	while (endsnake ->next!=NULL) {
		endsnake = endsnake -> next;
	}
	q->x = endsnake->x;
	q->y = endsnake->y;
	endsnake->next = q;
}

    //死亡的动画
	//时间2021.2.4:方法差不多完善了,之后可以在加一个io流的方法
void Main::dead() {
	for (int i = 0; i < 5;i++) {
		for (p = head; p;p=p->next) {
			clearrectangle(p->x*sum,p->y*sum,p->x*sum+length,p->y*sum+length);
		}
		Sleep(200);
		for (p = head; p;p=p->next) {
			if (p->x==head->x&&p->y==head->y) {
				setfillcolor(RED);
				fillrectangle(p->x * sum, p->y * sum, p->x * sum + length, p->y * sum + length);
			}
			else {
				setfillcolor(GREEN);
				fillrectangle(p->x*sum,p->y*sum,p->x*sum+length,p->y*sum+length);
			}	
		}
		Sleep(30);
	}
	if (score>readScore()) {//如果本次得分比上一次的高就保存在本地文件
		writeScore(score);
	}
	clearcliprgn();
	char string[] = "时间停止了,你..死了!";
	char string01[] = "                      ";
	settextcolor(RED);
	settextstyle(100, 0, _T("宋体"));
	for (int i = 0; i < 3; i++) {
		outtextxy(250, 300, string);
		Sleep(500);
		outtextxy(250, 300, string01);
		Sleep(1000);
	}
	settextcolor(GREEN);
	char string02[] = "马上就会回到初始界面";
	settextstyle(100, 0, _T("宋体"));
	outtextxy(250, 300, string02);
	Sleep(1000);
	clearcliprgn();
	be();
}


int readScore() {
	fstream scorefile(fileName, ios::in);
	string s;
	getline(scorefile,s);
	scorefile.close();
	return stoi(s);
}

void writeScore(int score) {
	fstream scorefile(fileName, ios::trunc | ios::out);
	scorefile << score;
	scorefile.close();
}

void be() {
	Main::createTempFile();
	memset(snakearr, 0, sizeof(snakearr));//bool数组的赋值
	initgraph(JFramx, JFramy);
	char str_0[] = "》贪吃蛇《";
	char tips[] = "提示:";
	char str_1[] = "欢迎你的游玩,本游戏由芽孢子独立完成,特别鸣谢张百害";
	char str_2[] = "·使用WASD控制蛇的移动,箭头也行";
	char str_3[] = "·撞墙而死.按p暂停";
	char str_4[] = "·游戏界面可以显示你的分数";
	char str_5[] = "   点击任意键继续";
	char str_6[] = "·键盘输入数字可以选关(1-3)";
	char deletestr[] = "                                                  ";
	settextstyle(50, 0, _T("宋体"));
	outtextxy(620, 50, str_0);
	settextstyle(20, 0, _T("宋体"));
	outtextxy(500, 130, str_1);
	outtextxy(500, 180, tips );
	outtextxy(500, 230, str_2);
	outtextxy(500, 280, str_3);
	outtextxy(500, 330, str_4);
	outtextxy(500, 380, str_6);
	settextstyle(50, 0, _T("宋体"));

	int scoreFileNumber = readScore();
	string scoreFile = "   你的最高分数:";
	scoreFile += to_string(scoreFileNumber);
	char Outscore[1024];
	strcpy_s(Outscore,sizeof(Outscore),scoreFile.c_str());//c_str()方法能加字符串转化为字符数组

	while (1) {
		if (_kbhit()) {
			level =_getch();//再键盘上得到的字符类型,从零开始计数的话,0的ASCll的值为48
			if (level==27) {//在初始的界面中所加上的一个退出的的选项
				closegraph();
			}
			break;
		}
		outtextxy(450, 500, str_5);
		Sleep(500);
		outtextxy(450, 500, deletestr);
		Sleep(500);
		outtextxy(450,500,Outscore);
		Sleep(700);
		outtextxy(450, 500, deletestr);
		Sleep(500);
	}
	clearcliprgn();
	new Main(level);//这里传值
}

int main() {
	be();
	getchar();
	return 0;
}

你可能感兴趣的:(C++,贪吃蛇,游戏,c++)