实现思路
本贪吃蛇主要运用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