[C语言] 自制的贪吃蛇游戏

6 篇文章 0 订阅
3 篇文章 0 订阅

使用C语言自带的游戏图新库开发贪吃蛇

我看网上好多制作贪吃蛇的帖子都是对刚学习C语言的同学们很不友好,制作的都是控制台,黑窗口的贪吃蛇游戏,能做出来但是感觉很无趣,不太像正常的游戏,接下来我将制作完全制作一款有趣的C语言贪吃蛇游戏

直接上游戏效果

请添加图片描述

开发环境搭建

小伙伴们首先应该学会 工欲善其事必先利其器

  1. 开发工具VC 6.0 或 使用VS2010 Express即可
  2. 下载C语言的EasyX图形库

注解1:
首先为啥用VC/VS2010 Express,这两个开发工具兼容C语言的EasyX库,不要在乎工具有多老,和项目最搭配的才是最好的,就像我以前使用Turbe C开发过游戏一样,适合就好。

注解2:
直接面向百度,不了解的小伙伴可以自己查查EasyX是个啥,然后第一条链接是下载的官网里面有任何你想要学习的内容,很多程序员开发的游戏可以学习:
在这里插入图片描述
我这里下载的是Vs2010 Express,然后使用图形库的api来开发游戏

开发思路

  1. 制作蛇通过结构体描述
  2. 制作地图通过结构体描述
  3. 制作随机产生食物
  4. 蛇能通过上下左右移动、能穿墙、不能撞自己
  5. 蛇吃到食物长一节身体

项目结构

在这里插入图片描述

img保存了所有使用的图片素材
music游戏中使用的音乐、音效
snake.cpp就是这个游戏的代码了

img内容如下
在这里插入图片描述
music内容如下
在这里插入图片描述

实际开发

首先导入所用到的头文件

#include <easyx.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>
#pragma comment(lib, "winmm.lib")

再声明好整个项目所用到的所有函数,这里我做了一个具体的思考过后,所用到的函数如下:

void move();
void body();
void wall();
void eat();
void kill();
void gameOver();
void reGame();
void stop();
void gameWin();

然后定义游戏中所用到的所有数据结构,代码如下:

struct BODYXY
{
	int x;
	int y;
};

struct snake
{
	int x;
	int y;
	int width;
	int height;
	bool life;
	int drection;	//1上 2右 3下 4左
	int body;
	BODYXY bodyxy[215];
};

struct foods
{
	bool needcreate;
	int x;
	int y;
};

struct MAP
{
	int x;
	int y;
};

定义好游戏中所有用到的全局变量,代码如下:

snake s;
foods f;
IMAGE bodyimg;
IMAGE foodimg;
IMAGE continueimg;
MOUSEMSG m;
#define WIDTH 900	//屏幕宽高900*600
#define HEIGHT 600
MAP map[12][18];
bool gameover = false;
bool stopgame = false;

这里图形库中播放音乐使用代码如下:

PlaySound("music/game_music.wav", NULL, SND_ASYNC | SND_LOOP);

输出图片的代码如下:

putimage(50*j,50*i,&background);

循环播放SND_LOOP

游戏延迟的代码如下:

Sleep(250);

键盘控制上下左右代码如下:

	if(kbhit())
		{flag = getch();
			if(flag == 224)
			{flag = getch();
			if(flag == 72 && s.drection != 3)	//上
				{
					s.drection = 1;
				}
			if(flag == 80 && s.drection != 1)	//下
				{
					s.drection = 3;
				}
			if(flag == 75 && s.drection != 2)	//左
				{
					s.drection = 4;
				}
			if(flag == 77 && s.drection != 4)	//右
				{
					s.drection = 2;
				}
			}	

在游戏地图中,是分成每个块每个块的,所以我们让游戏跑起来之前必先要做的一件事就是开发地图,详细原理如下图:
在这里插入图片描述

实现的地图每个块的算法大概就是,如下代码:

	for(int i=0;i<12;i++)
	{
		for(int j=0;j<18;j++)
		{	
			map[i][j].x = 50*j;
			map[i][j].y = 50*i;
		}
	}

游戏内所有属性的初始化

	//初始化蛇属性
	s.x = map[11][9].x;
	s.y = map[11][9].y;
	s.width = 50;
	s.height = 50;
	s.life = true;
	s.drection = 1;
	s.body = 1;
	for(int i=0;i<215;i++)
	{
		s.bodyxy[i].x = -10000;
		s.bodyxy[i].y = -10000;
	}

	f.needcreate = true;
	f.x = -100000;
	f.y = -100000;
	//绘制背景
	initgraph(WIDTH,HEIGHT);
	IMAGE background;
	loadimage(&background,_T("img/rectbg3.png"));
	//绘制蛇头
	IMAGE head;
	loadimage(&head,_T("img/snake_head2.png"));
	
	loadimage(&bodyimg,_T("img/snake_body.png"));
	
	loadimage(&foodimg,_T("img/addblood2.png"));
	
	loadimage(&continueimg,_T("img/continue.png"));

主体函数代码如下:

while(true)
	{	
		int flag;
		if(kbhit())
		{flag = getch();
			if(flag == 224)
			{flag = getch();
			if(flag == 72 && s.drection != 3)	//上
				{
					s.drection = 1;
				}
			if(flag == 80 && s.drection != 1)	//下
				{
					s.drection = 3;
				}
			if(flag == 75 && s.drection != 2)	//左
				{
					s.drection = 4;
				}
			if(flag == 77 && s.drection != 4)	//右
				{
					s.drection = 2;
				}
			}	
			
			if(gameover)
			{
				if(flag == 32)
				{
					reGame();
				}
			}
			else if(flag == 32)
			{
				//暂停
				stop();
			}
		}
		if(!gameover && !stopgame)
		{
			//绘制游戏背景
			for(int i=0;i<12;i++)
			{
				for(int j=0;j<18;j++)
				{	
					putimage(50*j,50*i,&background);
				}
			}
			
			//移动蛇
			move();
			//碰撞
			eat();

			//蛇头
			putimage(s.x,s.y,&head);
			//蛇身体
			body();
			//食物
			if(f.needcreate == false){
				putimage(f.x,f.y,&foodimg);
			}
			//是否自杀
			kill();
			//gameover
			if(gameover == true)
			{
				gameOver();
			}
			//win
			if(s.body >= 215)
			{
				gameover = true;
				gameWin();
			}
			wall();
		}
		Sleep(250);
	}

绘制游戏主体函数,代码如下:

void body()
{		
	//绘制body
	for(int i=0;i<s.body;i++)
	{	
		putimage(s.bodyxy[i].x,s.bodyxy[i].y,&bodyimg);
	}
}

蛇具体移动函数,代码如下:

void move()
{	
	//循环得到前一个body
	int prx,pry;
	for(int i=s.body-1;i>0;i--)
	{
		s.bodyxy[i].x = s.bodyxy[i-1].x;
		s.bodyxy[i].y = s.bodyxy[i-1].y;
	}
	s.bodyxy[0].x = s.x;
	s.bodyxy[0].y = s.y;


	if(s.drection == 1)
	{
		s.y-=50;
	}
	else if(s.drection == 2)
	{
		s.x+=50;
	}
	else if(s.drection == 3)
	{
		s.y+=50;
	}
	else if(s.drection == 4)
	{
		s.x-=50;
	}
}

撞墙后,让蛇从另一边穿过,具体代码如下:

void wall()
{	
	//上方
	if(s.y+50 < 0)
	{
		s.y = HEIGHT - 50;
	}
	//上方
	if(s.y+50 > HEIGHT)
	{
		s.y = 0;
	}
	//左方
	if(s.x+50 < 0)
	{
		s.x = WIDTH - 50;
	}
	//右方
	if(s.x+50 > WIDTH)
	{
		s.x = 0;
	}
}

吃到食物后的具体函数,代码如下:

void eat()
{	
	int sx = s.x + s.width/2;
	int sy = s.y + s.height/2;

	if(sx >= f.x && sx <= f.x + 50)
		if(sy >= f.y && sy <= f.y + 50)
		{	
			f.needcreate = true;
			s.body++;
		}
	
	if(f.needcreate == true)
	{
		srand((unsigned)time(NULL));
		int ri = (int)(rand()%12);
		int rj = (int)(rand()%18);
		f.x = map[ri][rj].x;
		f.y = map[ri][rj].y;
		f.needcreate = false;
	}

}

吃到食物后,也就是碰撞到食物后让食物继续创建,通过needcreate这个枚举变量来操作,通过rand()函数实现让食物随机出现在地图上某个位置。

如果蛇碰到了自己就执行游戏结束,代码如下:

void kill()
{		
	int sx = s.x + s.width/2;
	int sy = s.y + s.height/2;
	for(int i=0;i<s.body;i++)
	{
		if(sx >= s.bodyxy[i].x && sx <= s.bodyxy[i].x + 50)
			if(sy >= s.bodyxy[i].y && sy <= s.bodyxy[i].y + 50)
			{	
				gameover = true;
				break;
			}
	}

}

制作游戏结束音效和页面,代码如下:

void gameOver()
{	
	PlaySound("music/game_over.wav", NULL, SND_ASYNC);
	putimage(WIDTH/2-150,HEIGHT/2-150,&continueimg);
}

继续游戏,然后初始化数据,代码如下:

void continueGame()
{
	//初始化蛇属性
	s.x = map[11][9].x;
	s.y = map[11][9].y;
	s.width = 50;
	s.height = 50;
	s.life = true;
	s.drection = 1;
	s.body = 1;
	for(int i=0;i<215;i++)
	{
		s.bodyxy[i].x = -10000;
		s.bodyxy[i].y = -10000;
	}

	f.needcreate = true;
	f.x = -100000;
	f.y = -100000;
}

游戏胜利的音效和页面,代码如下:

void gameWin()
{
	PlaySound("music/win.wav", NULL, SND_ASYNC);
	putimage(WIDTH/2-150,HEIGHT/2-150,&continueimg);
}

重新游戏,代码如下:

void reGame()
{	
	gameover = false;
	//初始化蛇属性
	s.x = map[11][9].x;
	s.y = map[11][9].y;
	s.width = 50;
	s.height = 50;
	s.life = true;
	s.drection = 1;
	s.body = 1;
	for(int i=0;i<215;i++)
	{
		s.bodyxy[i].x = -10000;
		s.bodyxy[i].y = -10000;
	}

	f.needcreate = true;
	f.x = -100000;
	f.y = -100000;
	PlaySound("music/game_music.wav", NULL, SND_ASYNC | SND_LOOP);
}

暂停游戏,代码如下:

void stop()
{
	stopgame = !stopgame;
	PlaySound("music/stop.wav", NULL, SND_ASYNC);

	if(stopgame == false)
	{
		PlaySound("music/game_music.wav", NULL, SND_ASYNC | SND_LOOP);
	}
}

整个游戏的代码如下:

#include <easyx.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>
#pragma comment(lib, "winmm.lib")

void move();
void body();
void wall();
void eat();
void kill();
void gameOver();
void reGame();
void stop();
void gameWin();

struct BODYXY
{
	int x;
	int y;
};

struct snake
{
	int x;
	int y;
	int width;
	int height;
	bool life;
	int drection;	//1上 2右 3下 4左
	int body;
	BODYXY bodyxy[215];
};

struct foods
{
	bool needcreate;
	int x;
	int y;
};

struct MAP
{
	int x;
	int y;
};

snake s;
foods f;
IMAGE bodyimg;
IMAGE foodimg;
IMAGE continueimg;
MOUSEMSG m;
#define WIDTH 900
#define HEIGHT 600
MAP map[12][18];
bool gameover = false;
bool stopgame = false;
int main()
{	
	PlaySound("music/game_music.wav", NULL, SND_ASYNC | SND_LOOP);
	for(int i=0;i<12;i++)
	{
		for(int j=0;j<18;j++)
		{	
			map[i][j].x = 50*j;
			map[i][j].y = 50*i;
		}
	}
	//初始化蛇属性
	s.x = map[11][9].x;
	s.y = map[11][9].y;
	s.width = 50;
	s.height = 50;
	s.life = true;
	s.drection = 1;
	s.body = 1;
	for(int i=0;i<215;i++)
	{
		s.bodyxy[i].x = -10000;
		s.bodyxy[i].y = -10000;
	}

	f.needcreate = true;
	f.x = -100000;
	f.y = -100000;
	//绘制背景
	initgraph(WIDTH,HEIGHT);
	IMAGE background;
	loadimage(&background,_T("img/rectbg3.png"));
	//绘制蛇头
	IMAGE head;
	loadimage(&head,_T("img/snake_head2.png"));
	
	loadimage(&bodyimg,_T("img/snake_body.png"));
	
	loadimage(&foodimg,_T("img/addblood2.png"));
	
	loadimage(&continueimg,_T("img/continue.png"));
	while(true)
	{	
		int flag;
		if(kbhit())
		{flag = getch();
			if(flag == 224)
			{flag = getch();
			if(flag == 72 && s.drection != 3)	//上
				{
					s.drection = 1;
				}
			if(flag == 80 && s.drection != 1)	//下
				{
					s.drection = 3;
				}
			if(flag == 75 && s.drection != 2)	//左
				{
					s.drection = 4;
				}
			if(flag == 77 && s.drection != 4)	//右
				{
					s.drection = 2;
				}
			}	
			
			if(gameover)
			{
				if(flag == 32)
				{
					reGame();
				}
			}
			else if(flag == 32)
			{
				//暂停
				stop();
			}
		}
		if(!gameover && !stopgame)
		{
			//绘制游戏背景
			for(int i=0;i<12;i++)
			{
				for(int j=0;j<18;j++)
				{	
					putimage(50*j,50*i,&background);
				}
			}
			
			//移动蛇
			move();
			//碰撞
			eat();

			//蛇头
			putimage(s.x,s.y,&head);
			//蛇身体
			body();
			//食物
			if(f.needcreate == false){
				putimage(f.x,f.y,&foodimg);
			}
			//是否自杀
			kill();
			//gameover
			if(gameover == true)
			{
				gameOver();
			}
			//win
			if(s.body >= 215)
			{
				gameover = true;
				gameWin();
			}
			wall();
		}
		Sleep(250);
	}
	_getch();
	closegraph();
	return 0;
}

void body()
{		
	//绘制body
	for(int i=0;i<s.body;i++)
	{	
		putimage(s.bodyxy[i].x,s.bodyxy[i].y,&bodyimg);
	}
}

void move()
{	
	//循环得到前一个body
	int prx,pry;
	for(int i=s.body-1;i>0;i--)
	{
		s.bodyxy[i].x = s.bodyxy[i-1].x;
		s.bodyxy[i].y = s.bodyxy[i-1].y;
	}
	s.bodyxy[0].x = s.x;
	s.bodyxy[0].y = s.y;


	if(s.drection == 1)
	{
		s.y-=50;
	}
	else if(s.drection == 2)
	{
		s.x+=50;
	}
	else if(s.drection == 3)
	{
		s.y+=50;
	}
	else if(s.drection == 4)
	{
		s.x-=50;
	}
}

void wall()
{	
	//上方
	if(s.y+50 < 0)
	{
		s.y = HEIGHT - 50;
	}
	//上方
	if(s.y+50 > HEIGHT)
	{
		s.y = 0;
	}
	//左方
	if(s.x+50 < 0)
	{
		s.x = WIDTH - 50;
	}
	//右方
	if(s.x+50 > WIDTH)
	{
		s.x = 0;
	}
}


void eat()
{	
	int sx = s.x + s.width/2;
	int sy = s.y + s.height/2;

	if(sx >= f.x && sx <= f.x + 50)
		if(sy >= f.y && sy <= f.y + 50)
		{	
			f.needcreate = true;
			s.body++;
		}
	
	if(f.needcreate == true)
	{
		srand((unsigned)time(NULL));
		int ri = (int)(rand()%12);
		int rj = (int)(rand()%18);
		f.x = map[ri][rj].x;
		f.y = map[ri][rj].y;
		f.needcreate = false;
	}

}

void kill()
{		
	int sx = s.x + s.width/2;
	int sy = s.y + s.height/2;
	for(int i=0;i<s.body;i++)
	{
		if(sx >= s.bodyxy[i].x && sx <= s.bodyxy[i].x + 50)
			if(sy >= s.bodyxy[i].y && sy <= s.bodyxy[i].y + 50)
			{	
				gameover = true;
				break;
			}
	}

}


void gameOver()
{	
	PlaySound("music/game_over.wav", NULL, SND_ASYNC);
	putimage(WIDTH/2-150,HEIGHT/2-150,&continueimg);
}

void continueGame()
{
	//初始化蛇属性
	s.x = map[11][9].x;
	s.y = map[11][9].y;
	s.width = 50;
	s.height = 50;
	s.life = true;
	s.drection = 1;
	s.body = 1;
	for(int i=0;i<215;i++)
	{
		s.bodyxy[i].x = -10000;
		s.bodyxy[i].y = -10000;
	}

	f.needcreate = true;
	f.x = -100000;
	f.y = -100000;
}

void gameWin()
{
	PlaySound("music/win.wav", NULL, SND_ASYNC);
	putimage(WIDTH/2-150,HEIGHT/2-150,&continueimg);
}

void reGame()
{	
	gameover = false;
	//初始化蛇属性
	s.x = map[11][9].x;
	s.y = map[11][9].y;
	s.width = 50;
	s.height = 50;
	s.life = true;
	s.drection = 1;
	s.body = 1;
	for(int i=0;i<215;i++)
	{
		s.bodyxy[i].x = -10000;
		s.bodyxy[i].y = -10000;
	}

	f.needcreate = true;
	f.x = -100000;
	f.y = -100000;
	PlaySound("music/game_music.wav", NULL, SND_ASYNC | SND_LOOP);
}

void stop()
{
	stopgame = !stopgame;
	PlaySound("music/stop.wav", NULL, SND_ASYNC);

	if(stopgame == false)
	{
		PlaySound("music/game_music.wav", NULL, SND_ASYNC | SND_LOOP);
	}
}

代码量总共三百多行实现了一个小游戏

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值