Easyx图形库+C++做一个贪吃蛇小游戏 数据结构课程设计

Easyx图形库+C++做一个贪吃蛇小游戏 数据结构课程设计

  1. 程序界面

① 游戏开始界面(如下图):
显示游戏标题,提供“开始游戏”、“游戏模式”和“游戏关于”(用以查看游戏的相关信息)选项
图 1游戏开始界面
② 游戏界面(如下图):
显示“蛇”和“食物”的位置及“等级框”、“分数框”、“提示框”等。
并在蛇移动时,更新游戏信息
图 2 游戏界面
③ 游戏结束界面(如下图):
图 3 游戏结束界面
显示游戏结束的提示,并提供“restart”和“quit”按钮

附上代码

#include<iostream>
#include<graphics.h>
#include<time.h>
#include<conio.h>
#include<Mmsystem.h>
#pragma comment(lib,"winmm.lib")
#include"resource.h"
using namespace std;

#define initSize 4    //蛇的初始
#define		 bgc     BLACK          //背景色
#define      gbgc    RGB(43,215,225)			//游戏界面的背景色
#define		shc1	 YELLOW  //RGB(138,232,23)			//蛇头边框色
#define      shc2		RED			//蛇头色
#define      sbc1	BLUE			//蛇身边框色
#define      sbc2	RGB(138,232,23)	//蛇身色
#define      fc1    RGB(255,128,64)
#define      fc2   YELLOW
#define      boxc  RGB(70,226,205)





//定义结构体点   这个点为游戏地图上的点,并非像素点
typedef struct point {
	int x;  //点的横坐标
	int y; //点的纵坐标
	point() {};
	point(int _x, int _y) {
		x = _x;
		y = _y;
	}
}point;

//蛇身
typedef struct sBody{
	point _point; //位置
	sBody *next; //下一个
	sBody *pre;//上一个
}sBody;

//方向
enum direction {up,down,left,right };

typedef struct snake {
	sBody *head;//蛇头
	sBody *body;//蛇身
	sBody *tail;//蛇尾
	direction drc;
	snake() {
		head = new sBody;
		body = new sBody;
		tail = new sBody;
	}
}snake;

typedef struct food {
	point _point;
	bool flash;														//闪烁的标志
}food;


snake *S = new snake;											//主角
food *Food = new food;
int score;														//分数
int level;														//级别
int goal;
int mode;														//模式选择
int pointWidth;
int _end;														//是否结束游戏的标志

//---------------------------------------------------------------point部分
void drawPoint(point p,int color=GREEN) {
	setfillcolor(color);
	int sx, sy, ex, ey;
	sx = 100 + pointWidth * p.x+1;
	sy = 100 + pointWidth * p.y+1;
	ex = sx + pointWidth-1;
	ey = sy + pointWidth-1;
	fillrectangle(sx,sy,ex,ey);
}

//高级版画点
void drawPointPlus(point p,int color1 ,int color2){
	
	
	int x1 = 100 + pointWidth * p.x+1;
	int y1 = 100 + pointWidth * p.y+1;
	int x2 = x1 + pointWidth-1;
	int y2 = y1 + pointWidth-1;
	setfillcolor(color2);
	fillrectangle(x1, y1, x2, y2);
	setlinecolor(color1);
	rectangle(x1, y1, x2, y2);
}

void clearPoint(point p) {
	setlinecolor(gbgc);
	drawPoint(p,gbgc);
}

//---------------------------------------------------------------snake
void initSnake(snake *S) {
	S->drc = up;
	S->head->_point.x = 10;											//蛇头的初始位置
	S->head->_point.y = 10;
	S->body->_point.x = S->head->_point.x;
	S->body->_point.y = S->head->_point.y + 1;

	S->head->next = S->body; //指针域
	S->body->pre = S->head;
	sBody *q = S->head->next;
	for (int i = 1; i < initSize; i++) {
		sBody *p = new sBody;
		p->_point.x = q->_point.x;
		p->_point.y = q->_point.y + 1;
		                                    //指针域
		q->next = p;
		p->pre = q;
		S->tail = p;
		q = p;
	}
	q->next = NULL;
}

//画蛇头
void drawHead(snake *S) {
	setfillcolor(fc1);
	fillrectangle((S->head->_point.x)*pointWidth +100+1, (S->head->_point.y)*pointWidth +100+1, (S->head->_point.x)*pointWidth +100 + pointWidth-1, (S->head->_point.y)*pointWidth +100-1 + pointWidth);
	drawPointPlus(S->head->_point, shc1,shc2);
}


//画蛇身体
void drawBody(sBody * a) {
	setfillcolor(sbc2);
	setlinecolor(YELLOW);
	fillrectangle((a->_point.x)*pointWidth +100+1, (a->_point.y)*pointWidth +100+1, (a->_point.x)*pointWidth +100-1 + pointWidth, (a->_point.y)*pointWidth +100-1 + pointWidth);
	
	drawPointPlus(a->_point, sbc1,sbc2);
}

//画蛇
void drawSnake(snake *S) {
	drawHead(S);
	sBody *p = S->head->next;
	while (p!=S->tail->next) {
		drawBody(p);
		p = p->next;
	}

}

判断蛇是否撞到自己
bool hitItself(snake *S) {
	int X, Y;
	X = S->head->_point.x;
	Y = S->head->_point.y;
	sBody *p = S->head->next;
	while (p!=S->tail->next) {
		if (p->_point.x == X && p->_point.y == Y) return true;
		p = p->next;
	}
	return false;
}

//判断蛇是否撞到边框
bool hitEdge(snake *S) {
	int X = S->head->_point.x;
	int Y = S->head->_point.y;
	if (X < 0 || X>(480/ pointWidth-1) || Y < 0 || Y>(600/ pointWidth-1))
		return true;
	return false;
}

//判断蛇是否吃到食物
bool getFood(snake *S, food *Food) {
	int X = S->head->_point.x;
	int Y = S->head->_point.y;
	int fx = Food->_point.x;
	int fy = Food->_point.y;
	if (X == fx && Y == fy) { 
		return true; }
	return false;
}


//普通的移动
void move(snake *S) {
	sBody *temp = new sBody;
	switch (S->drc)
	{
	case direction::up:
		temp->_point.x = S->head->_point.x;
		temp->_point.y = S->head->_point.y - 1;
		break;
	case direction::down:
		temp->_point.x = S->head->_point.x;
		temp->_point.y = S->head->_point.y + 1;
		break;
	case direction::left:
		temp->_point.x = S->head->_point.x-1;
		temp->_point.y = S->head->_point.y;
		break;
	case direction::right:
		temp->_point.x = S->head->_point.x+1;
		temp->_point.y = S->head->_point.y;
		break;
	default:
		break;
	}
	temp->next =S->head;
	S->head->pre = temp;
	S->head = temp;
	drawHead(S);                //重画蛇头
	drawBody(S->head->next);
	clearPoint(S->tail->_point);
	sBody *t = S->tail;
	S->tail = S->tail->pre;
	t = NULL;
}

//吃到食物的移动
void growAndMove(snake * S) {
	sBody *temp = new sBody;
	switch (S->drc)
	{
	case direction::up:
		temp->_point.x = S->head->_point.x;
		temp->_point.y = S->head->_point.y - 1;
		break;
	case direction::down:
		temp->_point.x = S->head->_point.x;
		temp->_point.y = S->head->_point.y + 1;
		break;
	case direction::left:
		temp->_point.x = S->head->_point.x - 1;
		temp->_point.y = S->head->_point.y;
		break;
	case direction::right:
		temp->_point.x = S->head->_point.x + 1;
		temp->_point.y = S->head->_point.y;
		break;
	default:
		break;
		

	}
	temp->next = S->head;
	S->head->pre = temp;
	S->head = temp;
	drawHead(S);
    clearPoint(S->head->next->_point);
	drawBody(S->head->next);

}
//---------------------------------------------------------------------food

//判断该位置是否被蛇的身体占据
bool isOccupied(snake *S, int fx, int fy) {
	sBody *p = S->head;
	while (p != S->tail->next) {
		if (p->_point.x == fx && p->_point.y == fy) {
			return true;
		}
		p = p->next;
	}
	return false;
}


//画一个新的食物
void drawANewFood(food *Food) {
	int MAX_X = 480 / pointWidth;
	int MAX_Y = 600 / pointWidth;
	int fx = rand() % MAX_X;
	int fy = rand() % MAX_Y;
	while (isOccupied(S, fx, fy)) {
		fx = rand() % MAX_X;
		fy = rand() % MAX_Y;
	}
	Food->_point.x = fx;
	Food->_point.y = fy;
	Food->flash = 0;
	drawPointPlus(Food->_point, fc1, fc2);
}

//控制食物闪烁
void flashFood(food *Food) {
	if (Food->flash) { 
		clearPoint(Food->_point);
		Food->flash = 0;
	}
	else {
		drawPointPlus(Food->_point, fc1, fc2);
		Food->flash = 1;
	}
}
//---------------------------------------------------------------------game
void initGame(int mode) {			//初始化蛇,画出蛇,画第一个食物,初始化级别和分数
	if (mode == 0) pointWidth = 20;
	else pointWidth = 10;
	initSnake(S);
	drawSnake(S);
	srand(unsigned(time(NULL))); //食物随机位置的种子
	
								
	level = 1;
	goal = level * 100;
	score = 0;
	_end = 0;
}
//画出模式切换箭头

void drawLeftArrow(int x, int y) {
	POINT pts[] = { {x,(y + 10)}, {x + 20, y + 20}, {x + 20, y} };
	fillpolygon(pts, 3);

}
//画出模式切换箭头
void drawRightArrow(int x, int y) {
	POINT pts[] = { {x + 20,(y + 10)}, {x, y}, {x , y + 20} };
	fillpolygon(pts, 3);

}

//绘制成绩框
void drawScoreBox() {
setlinecolor(BLACK);
	setfillcolor(boxc);
	fillroundrect(630,320,950,420,20,20);

	fillroundrect(630, 550, 950, 650, 20, 20);

}

//更新成绩显示
void updateScore() {
	drawScoreBox();
	_TCHAR a[12],b[12];
	_stprintf_s(a,L"%d",score);
	settextcolor(BLACK);
	settextstyle(60,0,_T("Rosewood Std Regular"));
	outtextxy(760,345,a);
	_stprintf_s(b, L"%d", goal);
	outtextxy(760, 575, b);
}

//绘制等级框
void drawRinkBox() {
	setlinecolor(BLACK);
	setfillcolor(boxc);
	fillroundrect(820, 100, 950, 200, 20, 20);
}

//更新等级显示
void updateRank() {
	settextcolor(BLACK);
	drawRinkBox();
	_TCHAR a[4];
	_stprintf_s(a, L"%d", level);
	settextstyle(60, 0, _T("Rosewood Std Regular"));
	outtextxy(860, 125, a);

}


//游戏开始界面,开始播放背景音乐
void startInterface(int &cmd,int &mode) {
	mciSendString(L"open  C:\\Users\\TTODS\\source\\repos\\贪吃蛇\\贪吃蛇\\背景音乐.mp3 alias bgm", NULL, 0, NULL);
	mciSendString(L"play bgm repeat", NULL, 0, NULL);


	initgraph(1000, 800);
	setbkcolor(bgc);
	cleardevice();
	setlinecolor(RED);

	initgraph(1000, 800);
	setbkcolor(YELLOW);
	setfillcolor(RED);
	fillrectangle(0, 0, 1000, 800);
	setfillcolor(YELLOW);
	setbkmode(TRANSPARENT);
	IMAGE img;
	img.Resize(960, 760);
	loadimage(&img, _T("IMAGE"), MAKEINTRESOURCE(IDR_IMAGE1));
	putimage(20, 20, &img);
	//fillrectangle(120, 120	, 930, 730);
	settextcolor(RED);
	settextstyle(64, 0, _T("Rosewood Std Regular"));
	outtextxy(270, 200, _T("GLUTTONOUS SNAKE"));
	settextstyle(45, 0, _T("Viner Hand ITC"));
	outtextxy(490, 450, _T("S T A R T"));
	outtextxy(470, 500, _T("STANDARD"));
	outtextxy(490, 550, _T("ABOUT"));
	setfillcolor(GREEN);
	drawLeftArrow(435, 510);
	drawRightArrow(650, 510);
	setfillcolor(RGB(158, 255, 142));
	setlinecolor(RGB(158, 255, 142));
	while (true) {
		MOUSEMSG m = GetMouseMsg();
		if (m.mkLButton&&m.x > 455 && m.x < 640 && m.y>450 && (m.y) < 490) { cmd = 1; break; }
		else if (m.mkLButton&&m.x > 455 && m.x < 640 && m.y>500 && (m.y) < 540) { cmd = 2; break; }
		else if (m.mkLButton&&m.x > 455 && m.x < 640 && m.y>550 && (m.y) < 590) { cmd = 3; break; }
		else if ((m.mkLButton&&m.x > 435 && m.x < 455 && m.y>510 && m.y < 530) || (m.mkLButton&&m.x > 650 && m.x < 670 && m.y>510 && m.y < 530)) {
			mode++;
			mode %= 2;
			if (mode == 0) { fillrectangle(470, 500, 640, 540); outtextxy(470, 500, _T("STANDARD")); }
			else {	
				fillrectangle(470, 500, 640, 540);
				outtextxy(470, 500, _T("ENTERTAIN"));
			}
		}
	}

}


//游戏界面描绘
void gameInterface() {
	setbkcolor(bgc);
	cleardevice();
	IMAGE img;
	img.Resize(1000, 800);
	loadimage(&img, _T("IMAGE"), MAKEINTRESOURCE(IDR_IMAGE3));
	putimage(0, 0, &img);
	int width = 6; //空心边界线的宽度
	setlinecolor(BLACK);
	//游戏界面
	setfillcolor(YELLOW);
	fillroundrect(99 - width, 99 - width, 581 + width, 701 + width, 20, 20);
	setfillcolor(gbgc);
	fillrectangle(99, 99, 581, 701);	
	setlinecolor(BLACK);
	settextcolor(BLACK);
	settextstyle(80, 0, _T("Rosewood Std Regular"));
	outtextxy(600, 220, _T("Score:"));
	outtextxy(600, 450, _T("Goal:"));
	outtextxy(600, 100, _T("Level:"));

	drawScoreBox();														//分数框
	updateScore();
	drawRinkBox();														//等级框
	updateRank();
		
	drawANewFood(Food);													//第一个食物
																		//提示框
	setfillcolor(YELLOW);
	fillroundrect(95, 40, 586, 85, 5, 5);
	setfillcolor(gbgc);
	fillroundrect(101, 46, 580, 79, 5, 5);
	settextcolor(RED);
	settextstyle(20, 20, L"Adobe 仿宋 Std R");
	outtextxy(100, 48, L"	    Be careful not to hit yourself or the border");
}

//
void gameOver(int &_end) {
	mciSendString(L"close bgm",NULL,0,NULL);
	PlaySound(L"C:\\Users\\TTOD\\source\\repos\\贪吃蛇\\贪吃蛇\\死亡.wav", NULL, SND_FILENAME | SND_ASYNC);
	setbkmode(TRANSPARENT);
	setfillcolor(YELLOW);
	fillroundrect(150, 300, 530, 500, 10, 10);
	setlinecolor(BLACK);
	fillroundrect(153, 303, 527, 497, 10, 10);
	settextcolor(BLACK);
	settextstyle(50, 0, _T("Rosewood Std Regular"));
	fillroundrect(220, 370, 470, 440, 10, 10);
	outtextxy(230, 380, _T("GAME OVER!"));
	settextstyle(30, 0, 0);
	fillroundrect(155, 465, 270, 495, 5, 5);
	fillroundrect(455, 465, 520, 495, 5, 5);
	outtextxy(160, 470, _T("Restart"));
	outtextxy(460, 470, _T("Quit"));
	MOUSEMSG m;
	while (true) {
		m = GetMouseMsg();
		if (m.mkLButton && m.x >= 155 && m.x <= 270 && m.y >= 465 && m.y <= 495) { _end = 0; break; }
		else if (m.mkLButton && m.x >= 455 && m.x <= 520 && m.y >= 465 && m.y <= 495) { _end = 1; break; }
	}
}


void game();

//游戏关于界面,用以显示游戏的相关信息
void drawAboutBox() {
	IMAGE img;
	img.Resize(1000,800);
	loadimage(&img,_T("IMAGE"),MAKEINTRESOURCE(IDR_IMAGE3));
	putimage(0, 0, &img);
	fillrectangle(100, 100, 100 + 20 * 20,100+25*20);
	point p(0, 0);
	for (int i = 0; i <= 20; i++) {
		p.y = 0;
		p.x = i;
		drawPointPlus(p,YELLOW,RED);
		p.y = 25;
		drawPointPlus(p, YELLOW, RED);
	}
	for (int i = 0; i <= 25; i++) {
		p.x = 0;
		p.y = i;
		drawPointPlus(p, YELLOW, RED);
		p.x =20 ;
		drawPointPlus(p, YELLOW, RED);
	}
	setlinecolor(RED);
	for (int i = 160; i < 600; i+=40) {
		line(130, i, 480, i);
	}
	setbkmode(TRANSPARENT);
	settextcolor(RED);
	settextstyle(20,20,L"Adobe 仿宋 Std R");
	outtextxy(130,130,L"ABOUT");
	outtextxy(130, 170, L"  Gluttonous Snake is a fun game ,have");
	outtextxy(130, 210, L" a good time~~");
	outtextxy(130, 250, L"( click anywhere to back )");
	outtextxy(130, 490, L" The last updated time :");
	outtextxy(130, 530, L"              2019.12.8");

	//cleardevice();
	MOUSEMSG m;
	while (1) {
		m = GetMouseMsg();
		if (m.mkLButton) break;
	
	}
	game();
}


//游戏过程
void playGame() {

	while (true) {
		Sleep(120 - 5 * level);
		if (getFood(S, Food)) {
			growAndMove(S);
			drawANewFood(Food);
			score +=  10*level;
			setlinecolor(BLACK);
			setfillcolor(YELLOW);
			fillroundrect(95, 40, 586, 85,5,5);
			setfillcolor(gbgc);
			fillroundrect(101, 46, 580, 79, 5, 5);
			updateScore();
			int temp = score%100;
			if (score == goal) {
				PlaySound(L"C:\\Users\\TTODS\\source\\repos\\贪吃蛇\\贪吃蛇\\关卡升级.wav", NULL, SND_FILENAME | SND_ASYNC);
				settextstyle(40, 0, _T("Rosewood Std Regular"));
				settextcolor(RED);
				outtextxy(240, 42, L"level up!!");
				level++;
				updateRank();
				goal += 100 * level;
			}
			else {
				settextcolor(RED);
				settextstyle(20, 20, L"Adobe 仿宋 Std R");
				PlaySound(L"C:\\Users\\TTODS\\source\\repos\\贪吃蛇\\贪吃蛇\\吃到食物.wav", NULL, SND_FILENAME | SND_ASYNC);

				switch (temp)
				{
				case  0:
					outtextxy(100, 48, L"	    Be careful not to hit yourself or the border");
					break;
				case 10:
				case 40:
				case 70:
					outtextxy(100, 48, L"      Press the ASDW keys to change the direction");
					break;
				case 20:
				case 50:
				case 80:
					outtextxy(100, 48, L"               Speed increases with level");
					break;
				case 30:
				case 60:
				case 90:
					outtextxy(100, 48, L"     It will grow long when you eat food");
				default:
					break;
				}

			}
		}
		else
			move(S);
			
		flashFood(Food);	
		if (hitEdge(S) || hitItself(S)) {
			gameOver(_end);
			return;
		}       //游戏结束标志
														//监听按键,w s a d 分别为上、下、左、右。空格为暂停(按下任意键继续)
		if (_kbhit()) {
			char ch = _getch();
			switch (ch)
			{
			case 'A':
			case 'a':
				if (S->drc != direction::right) {
					S->drc = direction::left;
					break;
				}
			case 'W':
			case 'w':
				if (S->drc != direction::down) {
					S->drc = direction::up;
					break;
				}
			case 's':
			case 'S':
				if (S->drc != direction::up) {
					S->drc = direction::down;
					break;
				}
			case 'd':
			case 'D':
				if (S->drc != direction::left) {
					S->drc = direction::right;
					break;
				}
			case ' ':
				_getch();
				break;
			default:
				break;
			}
		}

	}
}

void  restart() {
	mciSendString(L"open  C:\\Users\\TTODS\\source\\repos\\贪吃蛇\\贪吃蛇\\背景音乐.mp3 alias bgm", NULL, 0, NULL);
	mciSendString(L"play bgm repeat", NULL, 0, NULL);
	initGame(mode);
	gameInterface();
	playGame();
}


void game() {
	
	int cmd = 0; mode = 0;
	startInterface(cmd,mode);
	initGame(mode);
	//cleardevice();
	switch (cmd)
	{
	case 1:
			gameInterface();
			playGame();
			while (_end == 0) {
				restart();
			}
			return;
		break;
	case 2:
		break;
	case 3:
		drawAboutBox();
		break;
	default:
		break;
	}
	
	

};

int main() {
	game();
	
	return 0;
}

符加说明:本程序使用了简单好用的easyx图形库:可以Easyx官网中下载安装,且Easyx官网提供的文档详细的介绍了各种函数的用法,很容易上手。
代码中可能会有一些本人电脑上的资源路径,导致直接copy代码不能成功运行代码,想要学习的童鞋可以将其换为自己电脑上的资源路径或者直接删除即可运行,游戏相关的资源文件链接:资源链接

创建一个简单的贪吃蛇游戏通常需要以下几个步骤: 1. 初始化游戏环境和图形界面。 2. 创建蛇的数据结构和移动逻辑。 3. 生成食物并处理蛇的吃食逻辑。 4. 实现游戏的主循环,包括输入处理和游戏更新。 5. 判断游戏胜负和结束条件。 由于这是一个复杂的任务,我无法在这里提供完整的代码,但我可以给出一个简化的代码框架,你可以根据这个框架来进一步开发。 ```cpp #include <graphics.h> #include <conio.h> #include <list> #include <iostream> // 定义方向枚举 enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN }; // 蛇节点结构体 struct SnakeNode { int x; int y; SnakeNode(int col, int row) : x(col), y(row) {} }; // 蛇类 class Snake { public: Snake(int initPosX, int initPosY) { // 初始化蛇头位置 head = new SnakeNode(initPosX, initPosY); // 初始化蛇身体 body.push_back(head); } ~Snake() { // 释放蛇身内存 for (auto node : body) { delete node; } } void Move(Direction dir); void Grow(); void Draw(); // ... 其他成员函数 private: SnakeNode* head; std::list<SnakeNode*> body; // ... 其他成员变量 }; // 游戏类 class Game { public: Game() { init(); } void Run() { while (!_kbhit()) { // 按键退出游戏 // 游戏更新逻辑 // ... // 绘制游戏画面 draw(); } } private: void init() { // 初始化图形界面和游戏设置 // ... } void draw() { // 绘制贪吃蛇和食物等 // ... } // ... 其他成员函数 }; int main() { Game g; g.Run(); return 0; } // 请在这里继续完善具体的实现细节,例如蛇的移动,食物的生成,碰撞检测等。 ``` 注意:上述代码仅提供了一个框架和思路,并没有实现所有的细节,你需要自己填充函数的实现,处理游戏逻辑,如蛇的移动、吃食物、游戏结束条件等。而且,EasyX图形库的使用需要在安装有相应环境的Windows系统上进行,VS2022需要配置对应的EasyX库才能使用。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值