贪吃蛇课设(C++)

实现思路

本贪吃蛇主要运用C++和EasyX图形库进行开发。
详细的设计:
1.场景设计
运用了EasyX Graphics Library和Windows函数进行了对本游戏的图形化设计,我们的蛇采用若干个圆连接的形式组成,食物也采用圆的形式随机生成在地图上。
2.蛇和食物的储存结构
蛇和食物分别用一个类来储存,并且在该类中会储存相应的坐标、方向、速度、半径、等一些成员和成员函数。
3.蛇的移动
这里运用的kbhit()和getch()函数来接收用户的输入,并根据用户的输入来定蛇的方向。
4.蛇吃食物的判定
这里里的蛇吃食物的判定是根据蛇头和食物的距离来判定的,因游戏里的蛇头和食物都是一个圆构成的,所以我只需判定两个圆是否相交即可。
5.食物的生成,本游戏的食物是运用随机函数随机生成的。
6.蛇的死亡,这里的蛇是有2钟方式判定为死亡,一种是蛇头撞到墙和蛇头撞到身体,我们只需根据蛇头的坐标和蛇身的坐标来判定即可。
7.音乐的播放,运用Windows函数里的mciSendString()函数来播放音乐。

ps:这里的蛇的移动,是根据蛇头的方向移动而移动的,然后蛇身跟着前一节蛇身的位置而移动。

运行截图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

源代码(附注释)

头文件(head.h)

#include <iostream>
#include <Windows.h>
#define WIGHT 800 //窗口的宽度
#define HEIGHT 600 //窗口的高度
#define Snake_Num 500 //蛇最大的节数
using namespace std; 

class food;
void Time_Out();
void Bgm();
void Begin();
double Distance(int x1, int y1, int x2, int y2);
enum dir //枚举类型,UP,DOWN...相当于0,1...
{
	UP, DOWN, LEFT, RIGHT
};

class snake
{
public:
	snake();
	bool Box();
	bool Is_dead();
	void GameDraw(food&);
	void SnakeMove();
	void KeyControl();
	void EatFood(food&);
private:
	int len; //蛇的节数
	int dir; //蛇的方向
	int r;
	int grade;
	int speed; //蛇的速度
	bool flag; //判断蛇是否死亡
	POINT coor[Snake_Num]; //蛇的坐标,<Windows.h>里封装的结构体
};

class food
{
public:
	food();
	void friend snake::GameDraw(food&);
	void friend snake::EatFood(food&);
private:
	int x, y;
	int r;
	bool flag;
};


源文件(snake.cpp)

#include "head.h";
#include <iostream>
#include <cmath>
#include <conio.h>
#include <stdlib.h>
#include <Windows.h>
#include <graphics.h>
#include <mmsystem.h>   //包含多媒体设备接口文件
#pragma comment(lib,"winmm.lib")   //加载静态库

using namespace std;

food::food()
{
	r = 5;
	x = rand() % (WIGHT - 2 * r) + r;
	y = rand() % (HEIGHT - 2 * r) + r;
	flag = true;
}

snake::snake()
{
	len = 3;
	dir = RIGHT;
	r = 5;
	speed = 10;
	grade = 0;
	flag = true;
	for (int i = 0; i <= len - 1; i++) {
		coor[i].x = 10 * (len - 1 - i) + 20;
		coor[i].y = 10;
	}
}

void snake::GameDraw(food &f)
{
	BeginBatchDraw(); //防止闪屏
	setbkcolor(RGB(56, 147, 186)); //设置填充颜色
	cleardevice();

	// 绘制蛇
		
	for (int i = 0; i < len; i++)
		solidcircle(coor[i].x, coor[i].y, r);
	
	//绘制食物
	if (f.flag)
		solidcircle(f.x, f.y, f.r);

	// 显示分数
	wchar_t s[20] = L""; // L的作用,给s中的字符分配2个字节,wchar_t:宽字符
	swprintf_s(s, L"分数:%d", grade); //把字符输入到s中
	outtextxy(700, 20, s); // outtextxy(x, y, s),(x, y) 为坐标,是为要打印的内容
	EndBatchDraw();
}

void snake::KeyControl()
{
	// kbhit()和getch()都得在<conio.h>下才可以用
	if (_kbhit()) //检查当前是否有键盘输入,若有返回一个非0的值,否则返回0
	{
		switch (_getch()) //从控制台读取,不显示在屏幕上,即当用户按下某个字符时,无需按回车,函数自动读取
		{
		case 'w':
		case 'W':
		case 72:
			if (dir == DOWN) break; // 防止蛇调头
			dir = UP;
			break;
		case 's':
		case 'S':
		case 80:
			if (dir == UP) break;
			dir = DOWN;
			break;
		case 'a':
		case 'A':
		case 75:
			if (dir == RIGHT) break;
			dir = LEFT;
			break;
		case 'd':
		case 'D':
		case 77:
			if (dir == LEFT) break;
			dir = RIGHT;
			break;
		case ' ':
			Time_Out();
			while (_getch() == ' ') break;
			break;
		default:
			break;
		}
	}
}

void snake::SnakeMove()
{
	// 每节都跟着前一节移动
	for (int i = len - 1; i > 0; i--)
	{
		coor[i].x = coor[i - 1].x;
		coor[i].y = coor[i - 1].y;
	}

	// 蛇头移动
	switch (dir)
	{
	case UP:
		coor[0].y -= speed;
		break;
	case DOWN:
		coor[0].y += speed;
		break;
	case LEFT:
		coor[0].x -= speed;
		break;
	case RIGHT:
		coor[0].x += speed;
		break;
	default:
		break;
	}

	//判断是否撞墙
	if (coor[0].x < r || coor[0].x > WIGHT - r)
		flag = false;
	if (coor[0].y < r || coor[0].y > HEIGHT - r)
		flag = false;
	
	// 判断是否撞到自己的身体
	for (int i = 1; i < len; i++)
	{
		if (Distance(coor[0].x, coor[0].y, coor[i].x, coor[i].y) < 2 * r)
		{
			flag = false;
			break;
		}
	}
}

void snake::EatFood(food &f)
{
	if (f.flag && Distance(coor[0].x, coor[0].y, f.x, f.y) <= r + f.r)
	{
		f.flag = false;
		len++;
		grade += 10;
	}

	if (!f.flag)
	{
		f.r = 5;
		f.x = rand() % (WIGHT - 2 * f.r) + f.r;
		f.y = rand() % (HEIGHT - 2 * f.r) + f.r;
		f.flag = true;
	}
}

double Distance(int x1, int y1, int x2, int y2)
{
	double t1 = x1 - x2;
	double t2 = y1 - y2;
	return sqrt(t1 * t1 + t2 * t2);
}

bool snake::Box()
{
	wchar_t s[20] = L"";
	swprintf_s(s, L"你的分数为:%d\n是否再来一次", grade);
	HWND hWnd = GetHWnd(); // 获取窗口句柄
	int id = MessageBox(hWnd, s, L"snake", MB_YESNO); //设置消息框
	if (id == IDYES) return true;
	return false;
}

bool snake::Is_dead()
{
	return flag;
}

void Begin()
{
	IMAGE img;
	loadimage(&img, L"./snack.jpg", WIGHT, HEIGHT);
	putimage(0, 0, &img);
}

void Bgm()
{
	mciSendString(L"open bgm.mp3", 0, 0, 0);
	mciSendString(L"play bgm.mp3", 0, 0, 0);
}

void Time_Out()
{
	HWND hWnd = GetHWnd();
	MessageBox(hWnd, L"游戏暂停,按空格键继续", L"提示", MB_OKCANCEL);
}

主函数(main.cpp)

#include "head.h";
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <conio.h>
#include <Windows.h>
#include <graphics.h>
using namespace std;

int main()
{
	Bgm();
	srand(GetTickCount()); //设置种子为开机时间
	initgraph(WIGHT, HEIGHT);
	while (1)
	{
		Begin();
		if (_kbhit()) break;
	}
	snake s;
	food f;
	while (1)
	{
		s.KeyControl();
		s.SnakeMove();
		s.EatFood(f);
		s.GameDraw(f);
		if (!s.Is_dead())
		{
			//重新开始
			if (s.Box())
			{
				snake ds; s = ds;
				food df; f = df;
			}
			else break;
		}
		Sleep(50);
	}
	return 0;
}

总结废话

总的来说这贪吃蛇做的并没有那么好,蛇和食物和背景都是非常的简陋,并且可玩性也不是非常的好,其实可以加速度选择,加关卡模式,还有界面的美化,甚至还可以和数据库进行链接,保存游戏的状态,但是作为一个课设,我觉得这样也够了,哈哈,懒是原罪。
好了,废话不多说了,如对大佬们有帮助,还请大佬们给个大拇指,哈哈

ps:这里在给大家一个打包教程:https://blog.csdn.net/qq_41506111/article/details/102777940
如果大家需要源码和课设报告,可以到这里下载:
https://download.csdn.net/download/weixin_52068218/85485458

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值