Easyx库-贪吃蛇小游戏

#include <graphics.h>
#include <string.h>
#include <stdio.h>             //sprintf将整数转换为字符串      
#include <time.h>              //srand产生随机数
#define SQU_LONG 15            //正方形的长
#define SQU_NUMBER 30          //正方形个数
#pragma comment(lib,"Winmm.lib")               //导入音乐头文件

IMAGE img,right,stop,play,fail,change;         //定义背景,右边,游戏暂停,正在游戏,游戏失败,分数改变图片
int NUM=3;                                     //节点个数
char score[5];                                 //存储分数的字符串
int foodx,foody;                               //食物的坐标,用于批绘制

void food();                            //产生食物
void snakeMove();                       //蛇移动
int Direction(int savec);               //控制方向
void eat();                             //吃食物
void over();                            //蛇死亡

struct snake
{
	int x;                      //蛇头x坐标
	int y;                      //蛇头y坐标
	int dire;                   //蛇头方向
	struct snake *next;         //结构体指针
};
struct snake *head=(snake *)malloc(sizeof(snake));           //定义头指针
struct snake *p;                                             //用于遍历结构体
struct snake saveLast,saveBody;                              //saveLast用于保存前一个节点,saveBody用于保存后一个节点 

void main()//主方法
{
	initgraph(SQU_LONG*SQU_NUMBER+200,SQU_LONG*SQU_NUMBER);		    //创建画布
	loadimage(&img,"image/bk_picture.jpg");                         //读取背景图片
	putimage(0,0,&img);                                             //在坐标(0,0)处放置背景图片
	loadimage(&right,"image/right.jpg");                            
	putimage(495,0,&right);                                                                                     
	settextcolor(WHITE);											//文字颜色为白色
	setbkmode(TRANSPARENT);                                         //文字背景为透明
	settextstyle(20,0,"楷体");                                      //文字字号为20,正常宽度,字体为楷体
	outtextxy(530,40,"游戏规则:");                                 //在坐标(530,70)处输出“游戏规则”四个字,只能输出字符串格式
	outtextxy(502,70,"方向键控制方向");
	outtextxy(502,90,"  Space键暂停");
	outtextxy(502,110,"  Shift键加速");	
	loadimage(&play,"image/play.jpg");
	putimage(495,290,&play);
	mciSendString("open music/bk_audio.mp3 alias bk_audio",NULL,0,NULL);            //读取背景音乐文件并命名为bk_audio
	mciSendString("play bk_audio repeat",NULL,0,NULL);                              //repeat为循环播放

	int x,y;                                        //蛇头坐标        
	srand((unsigned)time(NULL));                    //产生随机数的语句,与rand()连用
	do
	{
		x=rand()%SQU_LONG*SQU_NUMBER;               //先算求余,后算乘法,随机产生蛇头的坐标
		y=rand()%SQU_LONG*SQU_NUMBER;
	}while(x>SQU_LONG*(SQU_NUMBER-3)||y>SQU_LONG*(SQU_NUMBER-3)||x<3*SQU_LONG||y<3*SQU_LONG);             //不能出现在四周靠边的位置
	struct snake *a=(snake *)malloc(sizeof(snake));             //用于存储蛇头
	struct snake *b=(snake *)malloc(sizeof(snake));             //一开始出现的第一节身子
	struct snake *c=(snake *)malloc(sizeof(snake));             //一开始出现的第二节身子
	p=head;                           //p指向head
	p->next=a;
	a->x=x;
	a->y=y;
	a->dire=rand()%4+1;               //a为蛇头,随机产生方向
	a->next=b;
	b->next=c;
	c->next=NULL;	                  //一开始只有一个蛇头两个身子,最后一个身子无指向
	p=p->next;                        //p指向蛇头
	setfillcolor(RED);                //设置填充颜色红色,表示蛇头
	bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);              //在(p->x,p->y)处画一个长度为SQU_LONG的填充红色的正方形	
	saveLast.x=p->x;                  //将移动前蛇头信息保存为上一个节点的信息
	saveLast.y=p->y;
	saveLast.dire=p->dire;
	saveLast.next=p->next;
	if(p->dire==1)
		p->x-=SQU_LONG;         //向左,p->x-1
	else if(p->dire==2)         
		p->y-=SQU_LONG;         //向上,p->y-1
	else if(p->dire==3)
		p->x+=SQU_LONG;         //向右,p->x+1
	else if(p->dire==4)
		p->y+=SQU_LONG;         //向下,p->y+1
	setfillcolor(RED);          //移动后重新画蛇头
	bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);              //在移动后坐标处画一个长度为SQU_LONG的填充红色的正方形
	p=p->next;                  //p指向第一个身子
	while(p)                           //p不为空就进入循环,一开始设置链表有三个节点,一共可进入两次
	{
		saveBody.x=p->x;               //将移动后的信息保存为现在节点的信息
		saveBody.y=p->y;
		saveBody.dire=p->dire;
		p->x=saveLast.x;               //重新将保存的移动前的信息读取出,赋给当前p指向的身子
		p->y=saveLast.y;
		p->dire=saveLast.dire;
		saveLast.x=saveBody.x;         //保存的移动前的失去作用,重新将移动后的再作为上一个节点,保证蛇每个身子记录前一个身子的信息
		saveLast.y=saveBody.y;
		saveLast.dire=saveBody.dire;
		setfillcolor(YELLOW);          //设置填充颜色黄色,表示蛇身子
		bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);		        //在读取到信息的坐标处画一个长度为SQU_LONG的填充黄色的正方形
		p=p->next;                     //p指向下一个身子
	}	
	food();                      //调用生成食物方法
	snakeMove();	             //调用蛇移动方法
}

void food()//生成食物       
{
	int x,y;                             //食物坐标
	do
	{
		x=rand()%SQU_LONG*SQU_NUMBER+SQU_LONG;
		y=rand()%SQU_LONG*SQU_NUMBER+SQU_LONG;
	}while(getpixel(x,y)==RED||getpixel(x,y)==YELLOW||x>SQU_LONG*(SQU_NUMBER-1)||y>SQU_LONG*(SQU_NUMBER-1));        //不能出现在蛇头和蛇身上还有边框右边和下边
	foodx=x;                             //将坐标保存为全局变量,用于其他方法批绘制
	foody=y;
}

void snakeMove()//蛇移动
{	
	int i,savec;                //savec用于在选择方向是临时保存     
	while(1)
	{			
		p=head->next;                              //p指向蛇头
		saveLast.x=p->x;                           //依然是将移动前蛇头信息保存为上一节点信息
		saveLast.y=p->y;
		saveLast.dire=p->dire;
		if(p->dire==1)
			p->x-=SQU_LONG;                        //向左,p->x-1
		else if(p->dire==2)
			p->y-=SQU_LONG;                        //向上,p->y-1
		else if(p->dire==3)
			p->x+=SQU_LONG;                        //向右,p->x+1
		else if(p->dire==4)
			p->y+=SQU_LONG;                        //向下,p->y+1
		p=p->next;                                 //p指向第一个身子
		while(p)
		{
			saveBody.x=p->x;                       //依然是将移动后信息保存为现在节点的信息
			saveBody.y=p->y;
			saveBody.dire=p->dire;
			p->x=saveLast.x;
			p->y=saveLast.y;
			p->dire=saveLast.dire;
			saveLast.x=saveBody.x;
			saveLast.y=saveBody.y;
			saveLast.dire=saveBody.dire;
			p=p->next;                             //p指向第二个身子
		}
		p=head->next;                                         //p重新指向蛇头
		if(getpixel(p->x,p->y)==YELLOW||p->x<0||p->y<0||p->x>(SQU_LONG*(SQU_NUMBER-1)+45)||p->y>SQU_LONG*(SQU_NUMBER-1))       //如果获取到蛇头坐标的颜色为黄色(蛇头覆盖在身子上)活着蛇头碰到边缘
			over();	                                          //调用失败方法
		else if(getpixel(p->x,p->y)==GREEN)                   //如果蛇头坐标的颜色为绿色(蛇头覆盖在食物上,代表吃掉食物)
		{
			mciSendString("open music/eat_food.mp3 alias eat_food",NULL,0,NULL);           //调用吃掉食物的音乐
			mciSendString("play eat_food from 0",NULL,0,NULL);                             //from 0为播放一次
			eat();                                            //调用吃食物方法
			food();                                           //调用生成食物方法
		}
		BeginBatchDraw();                                                 //开始批绘制
		putimage(0,0,&img);                                               //每一次绘制都需要刷新,所以每次都需要调用背景图片
		p=head->next;
		setfillcolor(RED);                                    //移动后重新画蛇头
		bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);	  
		p=p->next;
		while(p)
		{
			setfillcolor(YELLOW);                             //移动后重新画身子
			bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);
			p=p->next;					
		}
		setfillcolor(GREEN);                                              //设置填充颜色为绿色,表示食物
		bar(foodx,foody,foodx+SQU_LONG-1,foody+SQU_LONG-1);               //绿色代表食物		
		outtextxy(540,200,"得分:");
		sprintf(score,"%d",(NUM-3)*10);                                   //将整数(NUM-3)*10转换为字符串保存在score中
		loadimage(&change,"image/score.jpg");
		putimage(495,220,&change);
		outtextxy(546,220,score);
		FlushBatchDraw();                                                 //每更新一次绘制一次
		p=head->next;
		for(i=0;i<5;i++)
		{
			Sleep(NUM<20?(200-4*NUM):100);	                              //蛇移动停顿的时间,随着吃的食物个数的增多停顿时间减少,减少到0.1秒后保持不变
			savec=p->dire;                                                //将蛇头原来的方向保存到savec中
			p->dire=Direction(savec);                                     //调用按键方法并传递savec参数
			if(p->dire==5)                                                //如果选择了加速按键
			{
				p->dire=savec;                                            //方向仍然是原方向
				break;                                                    //跳出循环,不停顿
			}
		}		
		EndBatchDraw();                                                   //关闭批量绘图
	}
}

int Direction(int savec)//按键
{
	p=head->next;                                              //p指向蛇头                                                   
	if(p->dire!=3&&GetAsyncKeyState(VK_LEFT)&0x8000)           //如果原来方向不向右并且按下左键
		p->dire=1;
	else if(p->dire!=4&&GetAsyncKeyState(VK_UP)&0x8000)        //如果原来方向不向下并且按下上键
		p->dire=2;
	else if(p->dire!=1&&GetAsyncKeyState(VK_RIGHT)&0x8000)     //如果原来方向不向左并且按下右键
		p->dire=3;
	else if(p->dire!=2&&GetAsyncKeyState(VK_DOWN)&0x8000)      //如果原来方向不向上并且按下下键
		p->dire=4;
	else if(GetAsyncKeyState(VK_SHIFT)&0x8000)                 //按shift键
		p->dire=5;
	else if(GetAsyncKeyState(VK_SPACE)&0x8000)                 //按空格键
	{
		loadimage(&stop,"image/stop.jpg");
		putimage(495,290,&stop);                               //更新游戏暂停图片
		FlushBatchDraw();                                      //批绘制
		mciSendString("stop bk_audio",NULL,0,NULL);            //暂停,音乐停止
		system("pause");                                       //暂停,按任意键继续
		loadimage(&play,"image/play.jpg");
		putimage(495,290,&play);                               //更新正在游戏图片
		FlushBatchDraw();                                      //批绘制
		mciSendString("play bk_audio",NULL,0,NULL);            //音乐重新从上一次结束的地方播放
		p->dire=savec;                   //暂停结束继续向同一个方向走
	}		
	else
		p->dire=savec;                   // 若是没有选择依然是原先的方向
	return p->dire;
}

void over()//结束
{
	loadimage(&fail,"image/fail.jpg");
	putimage(495,290,&fail);                              //更新游戏失败图片
	FlushBatchDraw();                                     //批绘制
	mciSendString("stop bk_audio",NULL,0,NULL);	          //结束,音乐停止
	system("pause");
	exit(0);                                              //退出到控制台
}

void eat()//吃食物
{
	p=head;
	while(p->next!=NULL)                                  //若p不是尾节点,则继续进入循环遍历
		p=p->next;
	struct snake *a=(snake *)malloc(sizeof(snake));       //重新声明一个节点,用于添加身子
	a->x=saveLast.x;                                      //将最后保存的节点信息赋给新节点
	a->y=saveLast.y;
	a->dire=saveLast.dire;
	a->next=NULL;
	p->next=a;                                            //连接到链表中
	p=p->next;
	NUM+=1;                                               //节点个数加1
}

 

源代码文件:源代码

  • 5
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,以下是一个使用 EasyX 图形实现的贪吃蛇游戏的示例代码: ```c++ #include <graphics.h> #include <conio.h> #include <time.h> const int WIDTH = 600; // 游戏窗口宽度 const int HEIGHT = 600; // 游戏窗口高度 const int CELL_SIZE = 20; // 每个蛇身格子的大小 const int ROWS = HEIGHT / CELL_SIZE - 1; // 游戏窗口中行数 const int COLS = WIDTH / CELL_SIZE - 1; // 游戏窗口中列数 struct Snake { int x, y; struct Snake *next; }; enum Direction { UP, DOWN, LEFT, RIGHT }; Direction direction = RIGHT; // 蛇的初始方向 Snake *head = NULL; // 蛇头指针 int score = 0; // 得分 void initSnake() { head = new Snake; head->x = 5; head->y = 5; head->next = NULL; } void drawSnake() { setfillcolor(YELLOW); for (Snake *p = head; p; p = p->next) { solidrectangle(p->x * CELL_SIZE, p->y * CELL_SIZE, (p->x + 1) * CELL_SIZE, (p->y + 1) * CELL_SIZE); } } void moveSnake() { int x = head->x, y = head->y; switch (direction) { case UP: y--; break; case DOWN: y++; break; case LEFT: x--; break; case RIGHT: x++; break; } Snake *p = new Snake; p->x = x; p->y = y; p->next = head; head = p; if (x < 0 || x > COLS || y < 0 || y > ROWS) { // 撞墙 closegraph(); printf("Game Over!\n"); exit(0); } for (Snake *p = head->next; p; p = p->next) { // 撞自己 if (p->x == head->x && p->y == head->y) { closegraph(); printf("Game Over!\n"); exit(0); } } if (x == food_x && y == food_y) { // 吃到食物 score += 10; food_x = rand() % COLS; food_y = rand() % ROWS; } else { Snake *p = head; while (p->next->next) { p = p->next; } delete p->next; p->next = NULL; } } void drawFood() { setfillcolor(RED); solidcircle(food_x * CELL_SIZE + CELL_SIZE / 2, food_y * CELL_SIZE + CELL_SIZE / 2, CELL_SIZE / 2); } void updateScore() { setbkmode(TRANSPARENT); settextcolor(WHITE); char buf[32]; sprintf(buf, "Score: %d", score); outtextxy(10, 10, buf); } int food_x, food_y; int main() { initgraph(WIDTH, HEIGHT); setbkcolor(DARKGRAY); initSnake(); food_x = rand() % COLS; food_y = rand() % ROWS; while (true) { cleardevice(); drawSnake(); drawFood(); updateScore(); moveSnake(); Sleep(100); if (_kbhit()) { switch (_getch()) { case 'W': case 'w': if (direction != DOWN) direction = UP; break; case 'S': case 's': if (direction != UP) direction = DOWN; break; case 'A': case 'a': if (direction != RIGHT) direction = LEFT; break; case 'D': case 'd': if (direction != LEFT) direction = RIGHT; break; } } } return 0; } ``` 在这个示例代码中,我们使用了 EasyX 图形来实现游戏窗口和绘制图形。我们使用 Snake 结构体来表示蛇身,其中的 next 指针指向下一个蛇身。当蛇移动时,我们将一个新的 Snake 节点插入到蛇头位置,然后删除蛇尾节点,从而实现蛇的移动。当蛇头碰到墙壁或者自己的身体时,游戏结束。当蛇头碰到食物时,得分加 10 分,并在随机位置生成一个新的食物。 在游戏循环中,我们使用 cleardevice() 函数清空屏幕,然后分别绘制蛇身、食物和得分。我们使用 Sleep(100) 函数控制游戏的帧率,从而实现动画效果。我们使用 _kbhit() 和 _getch() 函数来读取键盘输入,从而控制蛇的方向。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值