(语言:C++ 版本:vs 2019 community )
提示:文章最末有代码的GitHub链接,可以直接下载,别忘记给星哦!
温馨提示:本代码对于锦城的学生尤其适用!(转载本文请指明出处)
贪吃蛇是我们的一个基本项目,但是我发现网上的贪吃蛇有很多拓展的写法,对于一些只需要的基本需求的贪吃蛇,有时候还不能拿来直接用,于是乎,在学校写这个贪吃蛇的时候,我就顺便记录一下。(本代码没有图形化,没有使用EasyX图形库)
本文中的贪吃蛇一些功能如下:
1.蛇的自由移动(w,s,a,d)
2.蛇移动时有效输入的判断:例如蛇往右移动时,输入a蛇不能改向
3.蛇的吃食物变长,分数增加,等级提升
3.食物的随机出现
4.背景音乐:用了playSound函数,不需要直接注释掉
5.菜单:不需要的话直接不添加文件并需要稍微修改原有代码
贪吃蛇项目总体上用了6个类封装,分别是CUnit类, CFood类,CMap类, CSnake类, CGame类, CMenu类。
CUnit类主要功能:实现一个点的显示与擦除。
CFood类主要功能:创建随机食物位置。
CMap类主要功能:初始化窗口大小,绘制地图,显示初始信息。
CSnake类主要功能:显示、擦除,自由移动,吃食物蛇身变长等。
CGame类主要功能:运行、结束游戏,隐藏光标,运行时检测游戏等级、游戏分数、食物是否被吃并改变相应显示信息。
CMenu类主要功能:游戏加载页面,菜单显示。
CSnake类:新增quitGame()函数,用于实现选择退出游戏。在该蛇的自由移动过程中,另外实现了按空格键暂停,按q键选择退出游戏,按+键增加游戏速度。
CMap类:新增了drawGameWindows函数,用于实现初始化游戏界面大小。
CGame类:增加了hideCursor函数,用于实现隐藏光标,增加了GameOver函数,用于蛇死亡后的一系列操作。
CMenu类:新增类,增加了showMenu()函数(菜单显示),startGame()函数(开始游戏),quitGame()函数(退出游戏),gameHelp()函数(游戏帮助),loadGame()函数(加载游戏界面)。
Cunit类:
//.h
```cpp
#pragma once
#include
class Cunit
{
public:
Cunit(int x = 0, int y = 0, char pic = '*');
virtual ~Cunit();
void show();
void erase();
static void gotoxy(int x, int y);
public:
int m_ix;
int m_iy;
char m_cPic;
};
#include "CUnit.h"
#include
using namespace std;
Cunit::Cunit(int x, int y, char pic)
{
m_ix = x;
m_iy = y;
m_cPic = pic;
}
Cunit::~Cunit()
{
}
void Cunit::gotoxy(int x, int y)
{
COORD pos = {
x,y };
pos.X = x;
pos.Y = y;
//设置光标位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void Cunit::show()
{
gotoxy(m_ix, m_iy);
cout << m_cPic;
}
void Cunit::erase()
{
gotoxy(m_ix, m_iy);
cout << " ";
}
CFood类:
#pragma once
#include "CUnit.h"
class CFood :
public Cunit
{
public:
CFood(int x =0, int y=0, char pic = '#');
virtual ~CFood();
void createPos();
};
#include "CFood.h"
#include"CUnit.h"
#include"CMap.h"
#include
#include
#include
using namespace std;
CFood::CFood(int x, int y, char pic) : Cunit(x, y, pic)
{
}
CFood::~CFood()
{
}
void CFood::createPos()
{
/*m_ix = CMap::KLEFT + rand() % (CMap::KWIDTH - 2);
m_iy = CMap::KUP + rand() % (CMap::KHEIGHT - 4);*/
m_ix = CMap::KLEFT + rand() % (CMap::KWIDTH - CMap::KLEFT - 1);
m_iy = CMap::KUP + rand() % (CMap::KHEIGHT - CMap::KUP - 1);
}
CSnake类:
#pragma once
#include"CFood.h"
#include
#include
#include
#include
using namespace std;
typedef enum {
w,s,a,d
}Directions;
class CSnake
{
public:
CSnake(int x = 40, int y = 15, int length = 4, Directions direction = d, int speed = 400, char pic = '*');
virtual~CSnake();
bool move();
void eraseSnake();
void eraseSnake(int flag);
bool changeDirections(char vkValue);
void changeDirections(Directions dir); //改变方向
bool quitGame();
bool eatFood(CFood* pfood);
bool checkFoodPos(CFood *pFood); //检查食物位置
void movePos();
void growup();
void showSnake();
public:
int m_iLength;
int m_iHeadX;
int m_iHeadY;
int m_iSpeed; //蛇当前速度
char m_pic;
Directions m_enumCurrentDirection; //蛇当前方向
vector<Cunit> m_vecBody; //存储蛇的位置
};
#include
#include
#include
#include
#include"CSnake.h"
#include"Cunit.h"
#include"CMap.h"
#include"CFood.h"
#include"CMenu.h"
using namespace std;
CSnake::CSnake(int x, int y, int length, Directions direct, int speed, char pic)
{
m_iLength = length;
m_iHeadX = x;
m_iHeadY = y;
m_iSpeed = speed;
m_pic = pic;
m_enumCurrentDirection = direct;
Cunit c(0, 0, '@');
m_vecBody.push_back(c);
m_vecBody[0].m_ix = m_iHeadX;
m_vecBody[0].m_iy = m_iHeadY;
for (int i = 1; i < m_iLength; i++)
{
Cunit c;
m_vecBody.push_back(c);
switch (m_enumCurrentDirection)
{
case w:
m_vecBody[i].m_ix = m_iHeadX;
m_vecBody[i].m_iy = m_iHeadY + i;
break;
case s:
m_vecBody[i].m_ix = m_iHeadX;
m_vecBody[i].m_iy = m_iHeadY - i;
break;
case a:
m_vecBody[i].m_ix = m_iHeadX + i;
m_vecBody[i].m_iy = m_iHeadY;
break;
case d:
m_vecBody[i].m_ix = m_iHeadX - i;
m_vecBody[i].m_iy = m_iHeadY;
break;
}
}
}
CSnake::~CSnake()
{
}
//显示蛇
void CSnake::showSnake()
{
for (int i = 0; i < m_iLength; i++)
{
m_vecBody[i].show();
}
}
//擦除
void CSnake::eraseSnake()
{
/*for (int i = 0; i < m_iLength; i++)
{
m_vecBody[i].erase();
}*/
int i;
for (i = 0; i < m_iLength - 1; i++);
m_vecBody[i].erase();
}
void CSnake::eraseSnake(int flag)
{
for (int i = 0; i < m_iLength; i++)
m_vecBody[i].erase();
}
//改变方向
bool CSnake::changeDirections(char vkValue)
{
switch (vkValue)
{
case'w':
m_vecBody[0].m_iy--;
m_enumCurrentDirection = w;
return false;
case's':
m_vecBody[0].m_iy++;
m_enumCurrentDirection = s;
return false;
case'a':
if (m_enumCurrentDirection == a)
m_iSpeed -= 20;
m_vecBody[0].m_ix--;
m_enumCurrentDirection = a;
return false;
case'd':
m_vecBody[0].m_ix++;
m_enumCurrentDirection = d;
return false;
case 'q': //代表quit
changeDirections(m_enumCurrentDirection);
showSnake();
if (quitGame())
{
return true;
}
return false;
case '+':
changeDirections(m_enumCurrentDirection);
showSnake();
m_iSpeed -= 50;
return false;
case ' ':
changeDirections(m_enumCurrentDirection);
showSnake();
Cunit::gotoxy(CMap::KLEFT, CMap::KHEIGHT + 1);
cout << "游戏暂停,请按任意键继续...";
_getch(); //游戏暂停
Cunit::gotoxy(CMap::KLEFT, CMap::KHEIGHT + 1);
for (int i = 0; i < 27; i++)
cout << ' ';
return false;
default:
changeDirections(m_enumCurrentDirection);
showSnake();
return false;
}
}
void CSnake::changeDirections(Directions dir)
{
switch (dir)
{
case w:
m_vecBody[0].m_iy--;
break;
case s:
m_vecBody[0].m_iy++;
break;
case a:
m_vecBody[0].m_ix--;
break;
case d:
m_vecBody[0].m_ix++;
break;
default:
break;
}
}
bool CSnake::quitGame() //退出游戏
{
Cunit::gotoxy(CMap::KLEFT, CMap::KHEIGHT + 1);
cout << "退出游戏?(y/n):";
char ch;
cin >> ch;
Cunit::gotoxy(CMap::KLEFT, CMap::KHEIGHT + 1);
for (int i = 0; i < 17; i++)
cout << ' ';
if (ch == 'y')
{
return true;
}
else return false;
}
//存储移动坐标
void CSnake::movePos()
{
for (int i = m_iLength - 1; i > 0; i--)
{
m_vecBody[i].m_iy = m_vecBody[i - 1].m_iy;
m_vecBody[i].m_ix = m_vecBody[i - 1].m_ix;
}
}
//移动
bool CSnake::move()
{
bool flag = false;
movePos();
if (_kbhit())
{
char key;
key = _getch();
if (key == 'a' && m_enumCurrentDirection == d)
{
key = 'd';
flag=changeDirections(key);
}
else if (key == 'd' && m_enumCurrentDirection == a)
{
key = 'a';
flag=changeDirections(key);
}
else if (key == 'w' && m_enumCurrentDirection == s)
{
key = 's';
flag=changeDirections(key);
}
else if (key == 's' && m_enumCurrentDirection == w)
{
key = 'w';
flag=changeDirections(key);
}
else flag=changeDirections(key);
}
else changeDirections(m_enumCurrentDirection);
showSnake();
Sleep(m_iSpeed);
eraseSnake();
return flag;
}
//判断是否吃到食物
bool CSnake::eatFood(CFood* pfood)
{
if (pfood->m_ix == m_vecBody[0].m_ix && pfood->m_iy == m_vecBody[0].m_iy)
return true;
else
return false;
}
//检查食物位置是否在蛇身上
bool CSnake::checkFoodPos(CFood *pFood)
{
for (int i = 0; i < m_iLength; i++)
{
if (pFood->m_ix == m_vecBody[i].m_ix &&
pFood->m_iy == m_vecBody[i].m_iy)
return true;
}
return false;
}
//蛇吃到食物变长
void CSnake::growup()
{
Cunit c;
m_vecBody.push_back(c);
m_iLength++;
}
由于代码量过大,所以这里只附加了部分代码,更多的请点击GitHub链接:
https://github.com/qing-qing-mei/Snake