基于EasyX的贪吃蛇游戏

一、预备知识

1.使用EasyX必须要知道的一些基础函数
2.选择结构 if , switch
3.循环结构 for, while
4.多维数组 arr1[N], arr2[N][N] , arr3[N][N][N]
5.函数封装

二、游戏逻辑

想要写出推箱子,首先要知道推箱子游戏都有哪些元素和规则

1.贪吃蛇元素

素材
1.蛇身 2.蛇头 3.墙壁 4.食物
有了素材,首先拿数字对应起来,再来一个加载资源函数Loadimg()

#define SIZE 25
IMAGE img[8];//存放图片变量

enum element
{
	space=0,//空地
	food=-4,//食物
	wall=-1,//墙壁
	head=1, //蛇头
	move_rt=1,//向右
	move_dw=2,//向下
	move_lt=3,//向左
	move_up=4,//向上
};
void Loadimg()
{
	loadimage(&img[0],L"./images/0.jpg",SIZE,SIZE);
	loadimage(&img[1],L"./images/1.jpg",SIZE,SIZE);
	loadimage(&img[2],L"./images/2.jpg",SIZE,SIZE);
	loadimage(&img[3],L"./images/3.jpg",SIZE,SIZE);
	loadimage(&img[4],L"./images/4.jpg",SIZE,SIZE);
	loadimage(&img[5],L"./images/5.jpg",SIZE,SIZE);
	loadimage(&img[6],L"./images/6.jpg",SIZE,SIZE);
	loadimage(&img[7],L"./images/7.jpg",SIZE,SIZE);
}

2.贪吃蛇规则

1.按键可以改变蛇上、下、左、右移动
2.蛇默认沿当前方向移动
3.蛇吃到食物身体边长
4.蛇撞到墙或者自己的身体游戏结束

三、游戏设计

知道游戏元素和规则就可以开始设计游戏了

1.地图设计

地图是一个二维数组,蛇的身体一次用1,2,3,4表示,-1表示墙壁,0表示空地

#define NUM 21

int map[NUM][NUM]=
{
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};

地图初始化好了,开始贴图,根据移动方向的不同,贴不同的蛇头,写个Drawmap()函数

int move=1;//默认向右移动,1向右移动,2向下,3向左,4向右

void Drawmap()
{
	for(int i=0;i<NUM;i++)
	{
		for(int j=0;j<NUM;j++)
		{
			if(map[i][j]==wall)//贴墙
				putimage(j*SIZE,i*SIZE,&img[6]);
			else if(map[i][j]>1)//贴身
				putimage(j*SIZE,i*SIZE,&img[0]);
			else if(map[i][j]==food)//贴食物
				putimage(j*SIZE,i*SIZE,&img[7]);
			else if(map[i][j]==head)//贴头
				if(move==move_rt)//向右移动
					putimage(j*SIZE,i*SIZE,&img[move_rt]);
				else if(move==move_dw)//向下移动
					putimage(j*SIZE,i*SIZE,&img[move_dw]);
				else if(move==move_lt)//向左移动
					putimage(j*SIZE,i*SIZE,&img[move_lt]);
				else if(move==move_up)//向上移动
					putimage(j*SIZE,i*SIZE,&img[move_up]);
		}
	}
}

地图上还需要有蛇吃的食物,用随机函数产生食物,需要包含<time.h>,写个产生食物函数Producefood()

void Producefood()//产生食物
{
	srand((unsigned)time(NULL));//根据时间设置随机数种子
	for(int k=0;k<1; )
	{
		int x=rand()%(NUM-4) +2;//生成2 ~ 18的随机数
		int y=rand()%(NUM-4) +2;//为避免产生相同的坐标,采用下面的方式
		if(map[x][y]==0)
		{//如果是空地
			map[x][y]=food;
			k++;//食物设置成功才加加
		}
	}
}

2.移动设计

上文提到

1.按键可以改变蛇上、下、左、右移动
2.蛇默认沿当前方向移动

但是我们知道,蛇向某个方向移动的时候,不能往该方向的相反方向移动,写一个函数Controlsnake()用键盘控制蛇移动

void Controlsnake()
{
	char ch =_getch();
	if( (ch=='w' || ch=='W' || ch==72) && move!=move_dw)
	//如果想往上移动且现在不在向下移动
		move=move_up;//向上移动
	else if( (ch=='s' || ch=='S' || ch==80) && move!=move_up)
	//如果想往下移动且现在不在向上移动
		move=move_dw;//向下移动
	else if( (ch=='a' || ch=='A' || ch==75) && move!=move_rt)
	//如果想往左移动且现在不在向右移动
		move=move_lt;//向左移动
	else if( (ch=='d' || ch=='D' || ch==77) && move!=move_lt)
	//如果想往右移动且现在不在向左移动
		move=move_rt;//向右移动
}

上文提到

3.蛇吃到食物身体边长
4.蛇撞到墙或者自己的身体游戏结束

下面就要划重点了,我们如何让蛇在二维数组上移动呢?
此并非我自己想出来的,来源mooc,详情见下方链接

假设小蛇元素为54321,其中1为蛇头、5432为蛇身、最大值5为蛇尾。首先将所有大于0的元素加1,得到65432;将最大值6变为0,即去除了原来的蛇尾;再根据对应移动方向,将2对应方向的元素由0变成1;如此即实现了小蛇的移动。小蛇向上移动的双应流程如图3-14所示。

mooc
基于以上的描述,我们就可以写出蛇的移动函数Snakemove()

int oldheadx,oldheady,newheadx,newheady,tailx,taily;
int score=0,speed=150;//当前得分,和蛇的移动速度,越小速度越快
TCHAR s[100];//存放消息提示语句

void Snakemove()
{
	//遍历地图把地图上正数全+1
	for(int i=0;i<NUM;i++)
	{
		for(int j=0;j<NUM;j++)
		{
			if(map[i][j]>0)
				map[i][j]++;
		}
	}
	//最大数是尾巴,找到最大数坐标,移动后变成0
	int max=0;
	for(int a=0;a<NUM;a++)
	{
		for(int b=0;b<NUM;b++)
		{
			if(map[a][b]==2)
			{
				oldheadx=a;
				oldheady=b;//旧蛇头坐标
			}
			if(map[a][b]>max)
			{
				max=map[a][b];
				tailx=a;
				taily=b;//蛇尾坐标
			}
		}
	}
	//根据移动方向计算新蛇头坐标的位置
	if(move==move_rt)//如果向右移动
	{
		newheadx=oldheadx;
		newheady=oldheady+1;
	}
	else if(move==move_dw)//如果向下移动
	{
		newheadx=oldheadx+1;
		newheady=oldheady;
	}
	else if(move==move_lt)//如果向左移动
	{
		newheadx=oldheadx;
		newheady=oldheady-1;
	}
	else if(move==move_up)//如果向上移动
	{
		newheadx=oldheadx-1;
		newheady=oldheady;
	}

	if(map[newheadx][newheady]==food)
	{//如果吃到食物
		PlaySound(L"./images/eat.wav", nullptr, SND_FILENAME | SND_ASYNC);//播放吃到食物音效
		score++;//得分增加
		Producefood();//产生新的食物
		//尾部不变
	}
	else if(map[newheadx][newheady]==wall || map[newheadx][newheady]>0 )
	{//如果撞墙或撞自己
		mciSendString(_T("close ./images/bg.mp3"), 0, 0, 0);//关闭背景音乐
		PlaySound(L"./images/over.wav", nullptr, SND_FILENAME | SND_ASYNC);//播放结束音效
		_stprintf_s(s, _T("游戏结束,你的得分:%d分"), score);
		MessageBox(NULL,s,_T("游戏提示"),MB_OK | MB_SYSTEMMODAL) ;//显示得分
		system("pause");
	}
	else
	{//没吃到食物 游戏没结束
		map[tailx][taily]=0;//尾巴变成0
	}
	map[newheadx][newheady]=1;//新的蛇头是1
	oldheadx=newheadx;
	oldheady=newheady;//新头坐标变为旧坐标
}

3.速度设计

我们用Sleep()函数来控制蛇移动的速度,写一个根据得分改变速度函数Changespeed()

void Changespeed()
{
	if(score>=5 && score<10)
		speed=130;
	else if(score>=10 && score<15)
		speed=110;
	else if(score>=15 && score<20)
		speed=90;
	else if(score>=20 && score<25)
		speed=70;
	else if(score>=25 && score<30)
		speed=50;
	else if(score>=30)
		speed=30;
	Sleep(speed);
}

4.整体设计

下面把上面的函数组合起来就是贪吃蛇游戏,再来点音乐

#include<time.h>
#include<easyx.h>//图形库
#include<conio.h>//按键
#include<mmsystem.h>//音乐
#pragma comment(lib,"winmm.lib")//库文件

int main()
{
	initgraph(NUM*SIZE,NUM*SIZE);//创建地图大小的窗口
	Loadimg();//加载资源
	setbkcolor(WHITE);//设置背景白色
	Producefood();//产生食物
	//循环播放背景音乐
	mciSendString(L"open ./images/bg.mp3 ", 0, 0, 0);
	mciSendString(_T("play ./images/bg.mp3 repeat"), 0, 0, 0);
	while(true){
		//绘制界面
		BeginBatchDraw();//批量绘图开始
		cleardevice();//清理屏幕
		Drawmap();//绘制地图
		EndBatchDraw();//批量绘图结束
		if (_kbhit())//获取按键消息
		{
			Controlsnake();//改变蛇的移动
		}	
		Snakemove();//蛇默认移动
		Changespeed();//根据得分改变速度
	}
	return 0;
}

把上面所有代码复制到一个cpp文件里,再把素材改好命名放到images文件夹里,images文件夹在cpp文件旁边,就可以编译运行了!

图片音乐素材及可执行程序需要的点击下载

以下是基于easyx贪吃蛇游戏C++的代码示例: ```cpp #include <graphics.h> #include <conio.h> #include <time.h> #include <stdlib.h> #define WIDTH 800 #define HEIGHT 600 #define SIZE 20 struct Snake { int x, y; struct Snake *next; }; struct Food { int x, y; }; int score = 0; int high_score = 0; int direction = VK_RIGHT; struct Snake *head, *tail; struct Food food; void init(); void draw(); void update(); void generate_food(); bool check_collision(int x, int y); void game_over(); void save_score(); void restart_game(); int main() { init(); while (true) { draw(); update(); Sleep(100); } return 0; } void init() { initgraph(WIDTH, HEIGHT); setbkcolor(BLACK); setcolor(WHITE); settextstyle(20, 0, _T("Consolas")); head = new Snake{WIDTH / 2, HEIGHT / 2, NULL}; tail = head; generate_food(); } void draw() { cleardevice(); // 画蛇 struct Snake *p = head; while (p != NULL) { fillrectangle(p->x, p->y, p->x + SIZE, p->y + SIZE); p = p->next; } // 画食物 setfillcolor(RED); fillcircle(food.x + SIZE / 2, food.y + SIZE / 2, SIZE / 2); // 画分数 TCHAR str[20]; _stprintf_s(str, _T("Score: %d"), score); outtextxy(10, 10, str); _stprintf_s(str, _T("High Score: %d"), high_score); outtextxy(10, 40, str); } void update() { // 移动蛇头 int x = head->x, y = head->y; switch (direction) { case VK_LEFT: x -= SIZE; break; case VK_RIGHT: x += SIZE; break; case VK_UP: y -= SIZE; break; case VK_DOWN: y += SIZE; break; } // 检查是否吃到食物 if (x == food.x && y == food.y) { score++; if (score > high_score) { high_score = score; } generate_food(); } else { // 移动蛇尾 tail->x = x; tail->y = y; head->next = tail; head = tail; tail = tail->next; } // 检查是否撞到墙或自己 if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT || check_collision(x, y)) { game_over(); } } void generate_food() { srand((unsigned)time(NULL)); do { food.x = rand() % (WIDTH / SIZE) * SIZE; food.y = rand() % (HEIGHT / SIZE) * SIZE; } while (check_collision(food.x, food.y)); } bool check_collision(int x, int y) { struct Snake *p = tail; while (p != head) { if (p->x == x && p->y == y) { return true; } p = p->next; } return false; } void game_over() { save_score(); TCHAR str[20]; _stprintf_s(str, _T("Game Over! Score: %d"), score); MessageBox(NULL, str, _T("Game Over"), MB_OK); restart_game(); } void save_score() { FILE *fp; fopen_s(&fp, "score.txt", "w"); fprintf_s(fp, "%d", high_score); fclose(fp); } void restart_game() { score = 0; direction = VK_RIGHT; struct Snake *p = tail->next; while (p != NULL) { struct Snake *q = p; p = p->next; delete q; } head = new Snake{WIDTH / 2, HEIGHT / 2, NULL}; tail = head; generate_food(); } --相关问题--:
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值