C或C++项目实战之贪吃蛇

  1. 编译环境:VS2017(VS其他版本皆可),EasyX图形库
  2. 编程语言:c/c++
  3. 当前版本:snakeGame1.0
  4. 修改时间:2019/6/13
  5. 项目组成:
    5.1 头文件:snake\snake.h,
    5.2 源文件:main.cpp, snake\snake.cpp,
    5.3 资源文件:1.mp3, jinbi.jpg, jinbi.mp3, siwang.mp3,

一、头文件:snake\snake.h

#pragma once

/*
 * 贪吃蛇头文件
 */

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

//蛇的状态,U:上; D:下; L:左; R:右.
constexpr auto U = 1;
constexpr auto D = 2;
constexpr auto L = 3;
constexpr auto R = 4;

//蛇类型
struct snake
{
    
    
	int				x, y;		//坐标
	int				color;		//颜色 
	struct snake*	next;		//下一节蛇身
};

//贪吃蛇游戏类
class snakeGame
{
    
    
public:
	//全局变量
	HWND hWnd;				//窗口句柄
	//IMAGE bk;				//背景图片变量
	int score;				//金币
	int add;				//单价
	int grade;				//难度等级
	int sleeptime;			//每次运行的时间间隔
	int endGamestatus;		//游戏结束的情况,1:撞到墙; 2:咬到自己; 3:主动退出游戏.
	int status;				//蛇的状态
	snake *head, *food;		//蛇头指针和食物指针
	snake *q;				//遍历蛇用到的指针
	IMAGE jinbi;			//金币图片

	//函数声明
	snakeGame(int score = 0, int add = 10, int grade = 1, 
		int sleeptime = 150, int endGamestatus = 0);	//拷贝构造函数
	void initGame();		//游戏初始化
	void drawGame();		//绘制游戏界面
	void ctolGame();		//游戏控制
	void initSnake();		//蛇身初始化
	void creatMap();		//创建地图
	void createFood();		//随机出现食物
	void snakeMove();		//蛇移动
	int endGame();			//游戏结束
	int snakeMain();		//贪吃蛇主函数
};

二、源文件:main.cpp

#include "snake\snake.h"

int main()
{
    
    
	snakeGame Snake;
	Snake.snakeMain();
	return 0;
}

三、源文件:snake\snake.cpp

#include "snake.h"

/*
 * 贪吃蛇游戏函数定义
 */

//拷贝构造函数
snakeGame::snakeGame(int score, int add, int grade, int sleeptime, int endGamestatus)
{
    
    
	this->score = score;
	this->add = add;
	this->grade = grade;
	this->sleeptime = sleeptime;
	this->endGamestatus = endGamestatus;
}

 //游戏初始化
void snakeGame::initGame()
{
    
    
	//创建地图
	creatMap();

	//蛇身初始化
	initSnake();

	//创建食物
	createFood();

	//加载背景音乐
	mciSendString("open snake\\1.mp3", NULL, NULL, NULL);
	//循环播放背景音乐
	mciSendString("play snake\\1.mp3 repeat", NULL, NULL, NULL);
	//加载金币图片
	loadimage(&jinbi, "snake\\jinbi.jpg", 20, 20, true);
}

//绘制游戏界面
void snakeGame::drawGame()
{
    
    
	char mon[32] = {
    
     NULL };		//金币
	char vel[32] = {
    
     NULL };		//速度
	char dif[32] = {
    
     NULL };		//困难
	char one[32] = {
    
     NULL };		//单价

	BeginBatchDraw();

	setfillcolor(RGB(195, 195, 195));		//边框颜色
	solidrectangle(0, 0, 680, 680);
	setfillcolor(RGB(128, 255, 0));			//背景颜色
	solidrectangle(20, 20, 660, 660);
	setfillcolor(RGB(0, 0, 255));			//网格颜色
	for (int i = 40; i <= 640; i += 20)
		for (int j = 40; j <= 640; j += 20)
			solidcircle(i, j, 1);

	//绘制蛇身
	q = head;
	setfillcolor(YELLOW);
	solidcircle(q->x + 10, q->y + 10, 10);	//蛇头 
	q = q->next;
	while (q != NULL)
	{
    
    
		setfillcolor(q->color);
		solidcircle(q->x + 10, q->y + 10, 10);	//蛇身  
		q = q->next;
	}

	//绘制食物
	putimage(food->x, food->y, &jinbi);

	//当前信息
	setfillcolor(RGB(0, 0, 0));		//信息区背景颜色
	solidrectangle(680, 0, 1020, 680);
	setbkcolor(RGB(0, 0, 0));		//字体背景颜色
	_itoa_s(score, mon, 10);
	_itoa_s((10000 / sleeptime), vel, 10);
	_itoa_s((300 - sleeptime) / 30, dif, 10);
	_itoa_s(add, one, 10);
	setcolor(RGB(255, 255, 255));	//字体颜色
	outtextxy(730, 10, "金币:"); outtextxy(775, 10, mon);
	outtextxy(730, 30, "速度:"); outtextxy(775, 30, vel);
	outtextxy(730, 60, "难度:"); outtextxy(775, 60, dif);
	outtextxy(730, 80, "单价:"); outtextxy(775, 80, one);

	//说明界面
	outtextxy(700, 150, "不能穿墙,不能咬到自己!");
	outtextxy(700, 200, "控制方向:");
	outtextxy(800, 200, "↑↓←→");
	outtextxy(700, 250, "加速:F1");
	outtextxy(780, 250, "减速:F2");
	outtextxy(700, 270, "退出:Esc");
	outtextxy(780, 270, "暂停:Space");
	EndBatchDraw();
}

//游戏控制
void snakeGame::ctolGame()
{
    
    
	if (GetAsyncKeyState(VK_UP) && status != D)
	{
    
    	//上
		status = U;
	}
	else if (GetAsyncKeyState(VK_DOWN) && status != U)
	{
    
    	//下
		status = D;
	}
	else if (GetAsyncKeyState(VK_LEFT) && status != R)
	{
    
    	//左
		status = L;
	}
	else if (GetAsyncKeyState(VK_RIGHT) && status != L)
	{
    
    	//右
		status = R;
	}
	else if (GetAsyncKeyState(VK_SPACE))
	{
    
    	//暂停
		while (1)
		{
    
    
			Sleep(300);
			if (GetAsyncKeyState(VK_SPACE))
			{
    
    	//再次按空格键退出死循环
				break;
			}
		}
	}
	else if (GetAsyncKeyState(VK_ESCAPE))
	{
    
    	//退出
		while (1)
		{
    
    	//松手检测
			if (!GetAsyncKeyState(VK_ESCAPE))
			{
    
    	//松开退出游戏
				endGamestatus = 3;
				endGame();
				break;
			}
		}

	}
	else if (GetAsyncKeyState(VK_F1))
	{
    
    	//加速
		while (1)
		{
    
    
			if (!GetAsyncKeyState(VK_F1))
			{
    
    	//松手检测
				if (sleeptime > 60)
				{
    
    	//速度不能太快
					sleeptime = sleeptime - 30;
					add = add + 2;
				}
				break;
			}
		}
	}
	else if (GetAsyncKeyState(VK_F2))
	{
    
    	//减速
		while (1)
		{
    
    
			if (!GetAsyncKeyState(VK_F2))
			{
    
    	//松手检测
				if (sleeptime < 270)
				{
    
    	//单价不能小于0
					sleeptime = sleeptime + 30;
					add = add - 2;
				}
				break;
			}
		}

	}
	Sleep(sleeptime);
	snakeMove();
}

//蛇身初始化
void snakeGame::initSnake()
{
    
    
	snake *tail;		//蛇尾指针
	int i;

	//从蛇尾开始,头插法,以x,y设定开始的位置
	tail = (snake*)malloc(sizeof(snake));
	tail->x = 200;
	tail->y = 40;
	tail->color = RGB(255, 0, 0);
	tail->next = NULL;

	//初始长度为4
	for (i = 1; i <= 4; i++)
	{
    
    
		head = (snake*)malloc(sizeof(snake));
		head->next = tail;
		head->x = 200 + 20 * i;
		head->y = 40;
		head->color = RGB(255, 0, 0);
		tail = head;
	}

	//蛇移动方向向右
	status = R;
}

//创建地图
void snakeGame::creatMap()
{
    
    
	hWnd = initgraph(1020, 680);	//做窗口

	//欢迎界面
	MessageBox(hWnd, "欢迎来到贪吃蛇游戏!", "帅气的龙少提示你:", MB_OK);
	outtextxy(320, 260, "用↑.↓.←.→分别控制蛇的移动, F1 为加速,F2为减速");
	outtextxy(360, 280, "加速将能得到更高的分数");
	getch();
	cleardevice();
}

//随机出现食物
void snakeGame::createFood()
{
    
    
	snake *food_1;

	//为了防止每次产生的随机数相同,种子设置为time
	srand((unsigned)time(NULL));

	//创建食物
	food_1 = (snake*)malloc(sizeof(snake));
	if (food_1 == NULL) return createFood();

	do
	{
    
    	//保证其为10的倍数,使得食物能与蛇头对其
		food_1->x = rand() % 620 + 20;
		food_1->y = rand() % 620 + 20;
	} while ((food_1->x % 20 != 0) || (food_1->y % 20 != 0));
	food_1->color = RGB(rand() % 256, rand() % 256, rand() % 256);

	q = head;
	while (q)
	{
    
    
		if (q->x == food_1->x && q->y == food_1->y)
		{
    
    	//判断蛇身是否与食物重合
			free(food_1);
			createFood();
			return;
		}
		q = q->next;
	}

	//加载食物
	food = food_1;
}

//蛇前进,上U,下D,左L,右R
void snakeGame::snakeMove()
{
    
    
	snake * nexthead = (snake*)malloc(sizeof(snake));
	if (nexthead == NULL) return snakeMove();

	if (status == U)
	{
    
    
		nexthead->x = head->x;
		nexthead->y = head->y - 20;
		nexthead->color = RGB(255, 0, 0);
		if (nexthead->x == food->x && nexthead->y == food->y)//如果下一个有食物//
		{
    
    
			mciSendString("open snake\\jinbi.mp3 alias media", NULL, NULL, NULL);
			mciSendString("set media time format milliseconds", NULL, NULL, NULL);
			mciSendString("play media from 0", NULL, NULL, NULL);
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q != NULL)
			{
    
    
				q = q->next;
			}
			score = score + add;
			createFood();
		}
		else                                               //如果没有食物//
		{
    
    
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q->next->next != NULL)
			{
    
    
				q = q->next;
			}
			free(q->next);
			q->next = NULL;
		}
	}
	if (status == D)
	{
    
    
		nexthead->x = head->x;
		nexthead->y = head->y + 20;
		nexthead->color = RGB(255, 0, 0);
		if (nexthead->x == food->x && nexthead->y == food->y)  //有食物
		{
    
    
			mciSendString("open snake\\jinbi.mp3 alias media", NULL, NULL, NULL);
			mciSendString("set media time format milliseconds", NULL, NULL, NULL);
			mciSendString("play media from 0", NULL, NULL, NULL);
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q != NULL)
			{
    
    
				q = q->next;
			}
			score = score + add;
			createFood();
		}
		else                               //没有食物
		{
    
    
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q->next->next != NULL)
			{
    
    
				q = q->next;
			}
			free(q->next);
			q->next = NULL;
		}
	}
	if (status == L)
	{
    
    
		nexthead->x = head->x - 20;
		nexthead->y = head->y;
		nexthead->color = RGB(255, 0, 0);
		if (nexthead->x == food->x && nexthead->y == food->y)//有食物
		{
    
    
			mciSendString("open snake\\jinbi.mp3 alias media", NULL, NULL, NULL);
			mciSendString("set media time format milliseconds", NULL, NULL, NULL);
			mciSendString("play media from 0", NULL, NULL, NULL);
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q != NULL)
			{
    
    
				q = q->next;
			}
			score = score + add;
			createFood();
		}
		else                                //没有食物
		{
    
    
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q->next->next != NULL)
			{
    
    
				q = q->next;
			}
			free(q->next);
			q->next = NULL;
		}
	}
	if (status == R)
	{
    
    
		nexthead->x = head->x + 20;
		nexthead->y = head->y;
		nexthead->color = RGB(255, 0, 0);
		if (nexthead->x == food->x && nexthead->y == food->y)//有食物
		{
    
    
			mciSendString("open snake\\jinbi.mp3 alias media", NULL, NULL, NULL);
			mciSendString("set media time format milliseconds", NULL, NULL, NULL);
			mciSendString("play media from 0", NULL, NULL, NULL);
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q != NULL)
			{
    
    
				q = q->next;
			}
			score = score + add;
			createFood();
		}
		else                                         //没有食物
		{
    
    
			nexthead->next = head;
			head = nexthead;
			q = head;
			while (q->next->next != NULL)
			{
    
    
				q = q->next;
			}
			free(q->next);
			q->next = NULL;
		}
	}

	//判断蛇是否会咬到自己
	snake *self;
	self = head->next;
	while (self)
	{
    
    	//蛇自己指针遍历
		if (self->x == head->x && self->y == head->y)
		{
    
    
			endGamestatus = 2;
			endGame();
		}
		self = self->next;
	}

	if (head->x < 20 || head->x > 640 || head->y < 20 || head->y > 640)
	{
    
    	//不能穿墙
		endGamestatus = 1;
		endGame();
	}
}

//结束游戏
int snakeGame::endGame()
{
    
    
	mciSendString("stop snake\\1.mp3", NULL, NULL, NULL);
	mciSendString("open snake\\siwang.mp3", NULL, NULL, NULL);
	mciSendString("play snake\\siwang.mp3", NULL, NULL, NULL);
	switch (endGamestatus)
	{
    
    
	case 1: MessageBox(hWnd, "对不起,您撞到墙了,结束游戏!", "帅气的龙少提示你:", NULL); break;
	case 2: MessageBox(hWnd, "对不起,您咬到自己了,结束游戏!", "帅气的龙少提示你:", NULL); break;
	case 3: MessageBox(hWnd, "您的游戏已经结束了!", "帅气的龙少提示你:", NULL); break;
	}

	closegraph();//关闭图形界面
	exit(0);//退出
}

//贪吃蛇游戏主函数
int snakeGame::snakeMain()
{
    
    
	initGame();

	while (1)
	{
    
    
		drawGame();
		ctolGame();
	}

	return 0;
}

四、资源文件

1、1.mp3

百度网盘提取码:xpdm

2、jinbi.jpg

百度网盘提取码:pq7b

3、jinbi.mp3

百度网盘提取码:sow8

4、siwang.mp3

百度网盘提取码:xc1n

猜你喜欢

转载自blog.csdn.net/weixin_43302818/article/details/91899526