用C语言写一个简单的贪吃蛇游戏(用到easyx图形库)

学习内容:1.游戏的存储与读写

                  2.制作游戏菜单

                  3.制作定时器

目录

一、需要用到的头文件、全局变量和一些函数

二、定时器

三、数据的初始化和绘制

四、蛇的运行和吃食物

五、游戏菜单界面

六、游戏存储与读写

七、其他函数

八、主函数入口


主菜单

 游戏内容

一、需要用到的头文件、全局变量和一些函数

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

#define WIDTH 600//屏幕宽度与高度
#define HEIGHT 500
#define MAX_SNAKE 30//最大蛇长度

//全局变量
int game_state = 1;//游戏状态:1.游戏菜单选项 2.运行游戏 3.退出游戏  
int option;//菜单栏状态

bool game_pause;
bool snake_die;
MOUSEMSG m1;
MOUSEMSG m2;

//定一个方向枚举
enum DIR
{
	up,
	down,
	left,
	right
};

//蛇结构体
struct Snake
{
	POINT coord[MAX_SNAKE];
	int num;
	int len;
	int exis;
	int score;
	int dir;
}snake;

//食物结构体
struct Food
{
	POINT fd;
	int exis;
}food;

//需要用到的函数
void InitData();//初始化数据
void DrawImag();//绘制图画
void ReadGame();//读取要保存的数据
void SaveGame();//保存数据
void EatFood();//吃食物
void GameOver();//游戏结束
void GameMenu();//游戏菜单
void UpdataWithInput();//有数据输入
void UpdataWithoutInput();//无数据输入
void SnakeMove();//蛇的移动
void KeyControl();//键盘输入

二、定时器

用static 定义 start避免循环时被覆盖

开始start与end处以同一时间,start保存的时间不变,end时间一直在变化,直至end和start时间差大于等于ms,当相等时,再将start与end时间同步,重复以上操作,用时间差来控制程序运行快慢。

作用:满足时间要求时可进行某个操作,也不影响其他操作的进行。(可用于蛇的运动快慢)

bool timer(int ms, int id)
{
	static int start[6] = { clock() };
	int end = clock();
	if (end - start[id] >= ms)
	{
		start[id] = end;
		return true;
	}
	return false;
}

三、数据的初始化和绘制

void InitData()
{

	initgraph(WIDTH, HEIGHT, 1);//1表示显示控制台
	
	//播放背景音乐
	mciSendString("open .\\resource\\bk1.mp3 alias bgm1", NULL, 0, NULL);
	mciSendString("play bgm1 repeat", NULL, 0, NULL);

	//初始化蛇
	snake.len = 10;
	snake.num = 3;
	snake.dir = right;
	snake.score = 0;
	snake.coord[2].x = 0;
	snake.coord[2].y = 0;
	snake.coord[1].x = snake.len;
	snake.coord[1].y = 0;
	snake.coord[0].x = 2 * snake.len;//作为蛇头
	snake.coord[0].y = 0;

	// 画食物
	food.fd.x = rand() % (WIDTH / 10) * 10;
	food.fd.y = rand() % (HEIGHT / 10) * 10;
	food.exis = 1;

	//按键选项初始化0
	option = 0;
	//蛇是否死亡
	snake_die = false;
	//游戏是否暂停初始化为否
	game_pause = false;
}

//绘制图形画面
void DrawImag()
{
	setbkcolor(GREEN);
	cleardevice();
	BeginBatchDraw();
	while (game_state == 1)
	{
		GameMenu();
	}
	//画蛇
	for (int i = snake.num - 1; i >= 0; i--)
	{
		setfillcolor(YELLOW);
		setlinecolor(BLACK);
		fillrectangle(snake.coord[i].x, snake.coord[i].y, snake.coord[i].x + snake.len, snake.coord[i].y + snake.len);
		//printf("%d,%d\n", snake.coord[i].x, snake.coord[i].y);
	}

	//画食物
	setfillcolor(RED);
	solidellipse(food.fd.x, food.fd.y, food.fd.x + snake.len, food.fd.y + snake.len);

	settextstyle(25, 0, "黑体");
	outtextxy(20, 20,"得分:");
	TCHAR c[3];
	sprintf(c, "%02d", snake.score);
	outtextxy(90, 20, c);
	setbkmode(TRANSPARENT);

	//画出暂停与返回菜单界面按键
	char button_name1[10] = { "暂停游戏" };
	char button_name2[10] = { "继续游戏" };
	char button_name3[10] = { "返回菜单" };
	//按键框(仅供参考,可以自己在做一个小按键隐藏按钮,避免遮挡视线)
	setfillcolor(WHITE);
	fillrectangle(10, 400, 130, 440);
	fillrectangle(10, 450, 130, 490);
	setlinecolor(WHITE);//当鼠标不再范围内边框变白
	rectangle(10, 400, 130, 440);
	rectangle(10, 450, 130, 490);

	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(10 + 60 - textwidth(button_name3) / 2, 450 + 20 - textheight(button_name3) / 2, button_name3);
	if (game_pause)
	{
		outtextxy(10 + 60 - textwidth(button_name1) / 2, 400 + 20 - textheight(button_name1) / 2, button_name2);
	}
	else
	{
		outtextxy(10 + 60 - textwidth(button_name2) / 2, 400 + 20 - textheight(button_name2) / 2, button_name1);
	}
	if (m2.x >= 10 && m2.x <= 130 && m2.y >= 400 && m2.y <= 440)
	{
		setlinecolor(RED);//鼠标在方形区域时边框变红
		rectangle(10, 400, 130, 440);
		option = 1;
	}
	if (m2.x >= 10 && m2.x <= 130 && m2.y >= 450 && m2.y <= 490)
	{
		setlinecolor(RED);
		rectangle(10, 450, 130, 490);
		option = 2;
	}
    //当游戏结束时
	if (snake_die)
	{
		setbkmode(TRANSPARENT);
		settextcolor(RED);
		settextstyle(40, 20, "黑体");
		outtextxy(100, 200, "吃到自己了,游戏结束!!");
		outtextxy(100, 240, "是否继续游戏!!");
		outtextxy(100, 280, "继续请按Y   否请按N");
	}

	FlushBatchDraw();
}

四、蛇的运行和吃食物

//蛇的移动
void SnakeMove()
{
	
	for (int i = snake.num - 1; i > 0; i--)
	{
		snake.coord[i].x = snake.coord[i - 1].x;
		snake.coord[i].y = snake.coord[i - 1].y;
	}
	//snake.coord[0].x += 10;
	switch (snake.dir)
	{
	case up:
		snake.coord[0].y -= 10;
		if (snake.coord[0].y +10 == 0)
		{
			snake.coord[0].y = HEIGHT;
		}
		break;
	case down:
		snake.coord[0].y += 10;
		if (snake.coord[0].y - 10 == HEIGHT)
		{
			snake.coord[0].y = 0 ;
		}
		break;
	case right:
		snake.coord[0].x += 10;
		if (snake.coord[0].x -10 == WIDTH)
		{
			snake.coord[0].x = 0;
		}
		break;
	case left:
		snake.coord[0].x -= 10;
		if (snake.coord[0].x +10 == 0)
		{
			snake.coord[0].x = WIDTH;
		}
		break;
	default:
		break;
	}
	//判断蛇是不是吃到自己了
	for (int i = 3; i < snake.num; i++)//当蛇身只有三个时吃不到自己
	{
		if (snake.coord[0].x == snake.coord[i].x&&snake.coord[0].y == snake.coord[i].y)
		{
			snake_die = true;
		}
	}
}

//用键盘控制
void KeyControl()
{
	if (GetAsyncKeyState(VK_UP) && snake.dir != down)
	{
		snake.dir = up;
	}
	if (GetAsyncKeyState(VK_DOWN) && snake.dir != up)
	{
		snake.dir = down;
	}
	if (GetAsyncKeyState(VK_RIGHT) && snake.dir != left)
	{
		snake.dir = right;
	}
	if (GetAsyncKeyState(VK_LEFT) && snake.dir != right)
	{
		snake.dir = left;
	}
}

//吃食物
void EatFood()
{
	srand((unsigned int)time(NULL));
	if (snake.coord[0].x == food.fd.x&&snake.coord[0].y == food.fd.y)
	{
		food.fd.x = rand() % (WIDTH / 10)  * 10;
		food.fd.y = rand() % (HEIGHT / 10)  * 10;
		snake.num++;
		snake.score++;
	}
}

五、游戏菜单界面

//游戏 界面菜单
void GameMenu()
{
	
	cleardevice();

	BeginBatchDraw();
	//游戏名字
	char game_name[20] = { "贪吃蛇" };
	setbkcolor(TRANSPARENT);
	settextcolor(GREEN);
	settextstyle(40, 20, "华文琥珀");
	outtextxy(WIDTH / 2 - textwidth(game_name) / 2, 40, game_name);
	
	if (MouseHit())
	{
		m1 = GetMouseMsg();
		if (m1.uMsg == WM_LBUTTONDOWN)
		{
			//开始新游戏
			if (option == 1) 
			{
				game_state = 2;
				mciSendString("close bgm1", NULL, 0, NULL);
				Sleep(400);
				mciSendString("open .\\resource\\bk2.mp3 alias bgm2", NULL, 0, NULL);
				mciSendString("play bgm2 repeat", NULL, 0, NULL);
			}
			else if (option == 2) 
			{ 
				ReadGame(); game_state = 2; mciSendString("close bgm1", NULL, 0, NULL);
				Sleep(400);
				mciSendString("open .\\resource\\bk2.mp3 alias bgm2", NULL, 0, NULL);
				mciSendString("play bgm2 repeat", NULL, 0, NULL);
			}//读取进度开始游戏
			else if (option == 3) { SaveGame(); closegraph(); _exit(0); }//保存并退出游戏
		}
	}

	option = 0;
	char select1[9] = { "游戏开始" };
	char select2[9] = { "继续游戏" };
	char select3[9] = { "保存退出" };

	int textw = 140;
	int texth = 40;

	
	settextcolor(WHITE);
	//开始游戏按钮
	if (m1.x >= WIDTH*0.39 &&m1.x <= WIDTH*0.39 + textw &&m1.y >= HEIGHT*0.3&&m1.y <= HEIGHT*0.3 + texth)
	{
		//settextcolor(RED);
		settextstyle(35, 0, "华文彩云");//悬浮在按钮上
		outtextxy(WIDTH*0.39, HEIGHT*0.3, select1);
		option = 1;
		//getchar();
	}
	else 
	{ 
		settextstyle(35, 0, "黑体"); //不在按钮上
		outtextxy(WIDTH*0.39, HEIGHT*0.3, select1);
	}

	//继续游戏
	if (m1.x >= WIDTH*0.39 &&m1.x <= WIDTH*0.39 + textw &&m1.y >= HEIGHT*0.5&&m1.y <= HEIGHT*0.5 + texth)
	{
		settextstyle(35, 0, "华文彩云");
		outtextxy(WIDTH*0.39, HEIGHT*0.5, select2);
		option = 2;
	}
	else
	{
		settextstyle(35, 0, "黑体");
		outtextxy(WIDTH*0.39, HEIGHT*0.5, select2);
	}

	//保存并退出游戏
	if (m1.x >= WIDTH*0.39 &&m1.x <= WIDTH*0.39 + textw &&m1.y >= HEIGHT*0.7&&m1.y <= HEIGHT*0.7 + texth)
	{
		settextstyle(35, 0, "华文彩云");
		outtextxy(WIDTH*0.39, HEIGHT*0.7, select3);
		option = 3;
	}
	else
	{
		settextstyle(35, 0, "黑体");
		outtextxy(WIDTH*0.39, HEIGHT*0.7, select3);
	}
	FlushBatchDraw();
	//clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);//用背景色清除当前区域
}

六、游戏存储与读写

文件打开失败没有连接其他功能,可自行添加

打开文件之后需要关闭文件

//存档
void SaveGame()
{
	char ch[20];
	sprintf(ch, "del storage.txt");
	system(ch);//删除已有存档

	FILE* stor;

	if ((stor = fopen("storage.txt", "w+")) == NULL)//打开失败
	{
		cleardevice();
		setbkmode(TRANSPARENT);
		settextcolor(RED);
		settextstyle(40, 20, "黑体");
		outtextxy(200, 300, "存档失败!!");
	}
	else
	{
		fwrite(&(snake.num), sizeof(snake.num), 1, stor);
		fwrite(&(snake.score), sizeof(snake.score), 1, stor);
		fwrite(&(snake.score), sizeof(snake.score), 1, stor);
		fwrite(&(snake.dir), sizeof(snake.dir), 1, stor);
		fwrite(&(snake.len), sizeof(snake.len), 1, stor);
		fwrite(&(food.fd), sizeof(food.fd), 1, stor);
		fwrite(&(food.exis), sizeof(food.exis), 1, stor);
		for (int i = 0; i <= snake.num; i++)
		{
			fwrite(&snake.coord[i], sizeof(snake.coord[i]), 1, stor);
		}
	}
	fclose(stor);
}

//读取游戏
void ReadGame()
{
	FILE* stor;
	if ((stor = fopen("storage.txt", "r")) == NULL)
	{
		cleardevice();
		setbkmode(TRANSPARENT);
		settextcolor(RED);
		settextstyle(40, 20, "黑体");
		outtextxy(200, 300, "读写失败,可能没有存档!!");
		getchar();
	}
	else
	{
		fread(&(snake.num), sizeof(snake.num), 1, stor);
		fread(&(snake.score), sizeof(snake.score), 1, stor);
		fread(&(snake.exis), sizeof(snake.exis), 1, stor);
		fread(&(snake.dir), sizeof(snake.dir), 1, stor);
		fread(&(snake.len), sizeof(snake.len), 1, stor);
		fread(&(food.fd), sizeof(food.fd), 1, stor);
		fread(&(food.exis), sizeof(food.exis), 1, stor);
		for (int i = 0; i <= snake.num ; i++)
		{
			fread(&snake.coord[i] , sizeof(snake.coord[i]) , 1, stor);
		}
	}
	fclose(stor);
}

七、其他函数

//当蛇吃到自己时游戏结束
void GameOver()
{
	if (snake_die)
	{
		char ch;
		ch = _getch();
		switch (ch)
		{
		case 'Y':
		case 'y':
			closegraph();
			InitData();
			mciSendString("close bgm1", NULL, 0, NULL);
			break;
		case'N':
		case'n':
			EndBatchDraw();
			closegraph();
			_exit(0);
			break;
		default:
			break;
		}
	}
}

//需输入更新
void UpdataWithInput()
{
	KeyControl();

	//判断是否有鼠标介入
	while (MouseHit())
	{
		m2 = GetMouseMsg();
		if (m2.uMsg == WM_LBUTTONDOWN)
		{
			if (option == 1)
			{
				game_pause = true;
			}
			else if (option == 2)
			{
				game_state = 1;
				mciSendString("close bgm2", NULL, 0, NULL);
				mciSendString("open .\\resource\\bk1.mp3 alias bgm1", NULL, 0, NULL);
				mciSendString("play bgm1 repeat", NULL, 0, NULL);
			}
		}

		//游戏暂停将会一直在此循环直到点击继续游戏或者返回主页菜单
		while (game_pause)
		{
			DrawImag();
			while (MouseHit())
			{
				m2 = GetMouseMsg();
				if (m2.uMsg == WM_LBUTTONDOWN)
				{
					if (option == 1)
					{
						game_pause = false;
					}
					else if (option == 2)
					{
						game_state = 1;
						mciSendString("close bgm2", NULL, 0, NULL);
						mciSendString("open .\\resource\\bk1.mp3 alias bgm1", NULL, 0, NULL);
						mciSendString("play bgm1 repeat", NULL, 0, NULL);
					}
				}
			}
		}

	}
}

//无需输入更新
void UpdataWithoutInput()
{
	if (timer(100, 0))
	{
		SnakeMove();
	}
	GameOver();
	EatFood();
	
}

八、主函数入口

//主入口
int main()
{
	InitData();
	
	while (true)
	{
		DrawImag();
		UpdataWithInput();
		UpdataWithoutInput();
	}
	closegraph();
	getchar();
	return 0;
}

总结:难点在于设计菜单需要用到多重循环,以及按键效果,数据存储时避免遗漏。

此游戏功能简单,仅供学习参考。(有不足的地方欢迎大家指出,希望能和大家一起学习进步)

有兴趣可以尝试完成其他功能,比如封装、添加ai蛇,速度随着长度增加,障碍物或用链表写一个贪吃蛇等。

easyx图形库资源,音乐资源网上可下载。

  • 8
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 好的,我会尽力回答您的问题。关于使用C语言easyX图形五子棋游戏,可以按照以下步骤来实现: 1. 首先,您需要下载并安装easyX图形,以便在C语言中使用图形界面。在安装完成后,您需要包含easyX头文件并链接easyX文件。 2. 然后,您需要创建一个窗口并初始化easyX图形。可以使用initgraph函数来完成这个任务。您可以指定窗口的大小、标题等参数。 3. 接着,您需要在窗口中绘制五子棋棋盘。可以使用line函数来绘制棋盘的线条。您还可以使用circle函数在棋盘上绘制棋子。 4. 在绘制完棋盘后,您需要编逻辑代码来处理游戏规则。可以使用一个二维数组来表示棋盘上的棋子状态。当玩家下棋时,您需要判断当前位置是否为空,如果为空则将棋子放置在该位置。在下完棋子后,您还需要判断是否出现五个连续的棋子,以决定胜负。 5. 最后,您需要实现游戏的交互界面。可以使用鼠标点击事件来控制玩家下棋。在玩家下完棋后,您需要切换到另一个玩家,并等待其下棋。 以上是使用C语言easyX图形五子棋游戏的基本步骤。希望能对您有所帮助。 ### 回答2: 使用C语言五子棋游戏需要使用EasyX图形。首先,我们需要在EasyX中建立一个窗口,用于显示游戏界面。接下来,我们需要定义一个二维数组来表示棋盘,并在窗口中将其显示出来。 接着,我们可以定义一些全局变量,如棋盘大小、落子的颜色、上一个落子位置等等。这些变量将在游戏过程中使用。 在游戏过程中,我们需要捕捉用户的鼠标点击事件,以确定落子的位置。当用户点击某个位置时,我们需要判断该位置是否为空,如果为空,则将该位置标记为当前落子的颜色,并在棋盘上显示出来。 同时,我们需要编判断胜利的函数。在每次落子后,我们需要判断当前落子的颜色在水平、垂直、对角线方向上是否形成了五子连珠。如果存在五子连珠,游戏结束,并显示胜利信息。 此外,我们还可以添加悔棋、重新开始等功能,以增强游戏的可玩性。 最后,在游戏结束后,我们需要释放图形资源,并提醒用户是否重新开始游戏。 综上所述,使用C语言五子棋游戏,结合EasyX图形,可以实现一个简单的五子棋游戏,增加了图形化的界面和用户交互性,提升了用户体验。 ### 回答3: 使用C语言五子棋游戏,并使用EasyX图形,可以在Windows平台上进行图形化显示和交互。下面以简单的方式介绍如何实现: 1. 准备工作:首先需要下载安装EasyX图形,并将相关头文件和文件配置到C语言编译环境中。 2. 创建界面:使用EasyX的绘图函数,绘制游戏界面,包括棋盘、棋子、背景等元素。 3. 实现游戏逻辑:定义一个二维数组作为棋盘,用来存储棋子的位置。使用两个整型变量记录当前轮到哪一方下棋,以及判断游戏是否结束。通过鼠标事件监听鼠标点击的位置,根据当前轮和点击的位置在棋盘数组上落子。每当有棋子落下后,检查是否五连珠,如果有则游戏结束,并显示获胜方信息。 4. 实现AI对战:可以添加一个简单的AI算法,使得人机对战成为可能。AI算法可以根据当前棋盘的情况,计算出最佳下棋位置。例如,可以采用极大极小搜索算法,评估每个可能的下棋位置的得分,并选择得分最高的位置进行下棋。 5. 完善交互功能:可以添加悔棋、重新开始、退出游戏等功能,以提升游戏的体验。 总之,通过C语言EasyX图形的组合,我们可以实现一个简单但功能完备的五子棋游戏。这个游戏将具有图形化的界面,可以与人机对战,具备基本的游戏功能和操作。通过添加一些额外的功能,能够实现更好的用户体验和更高难度的游戏对战。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值