贪吃蛇
效果图如下:
所有功能由Widget类进行维护,主要模块有:
- 界面的初始化、墙体的打印与基本功能的实现
- 蛇的维护(初始化、移动、增长、状态、坐标)
- 排行榜的实现
界面的维护:
维护一个二维数字用于打印界面
enum WidgetSize//用于做数组参数
{
Row = 40,
Col=26
};
char m_widget[Row][Col];//界面信息的数组
界面的初始化与打印
void Widget::initialize()
{
//初始化
m_nowScore = 0;
for (size_t row = 0; row < Row; row++)
{
for (size_t col = 0; col < Col; col++)
{
if (row==0||row==Row-1||col==0||col==Col-1)
m_widget[row][col] = '*';//墙体
else m_widget[row][col] = ' ';//空
}
}
}
void Widget::setWidget()//打印界面
{
for (size_t i = 0; i < Col; i++)
{
for (size_t j = 0; j < Row; j++)
{
cout << m_widget[j][i]<<" ";
}
if(i>4||i<17)
printInformation(i);//打印其他信息
cout << "\n";
}
}
void Widget::printInformation(size_t pos)//打印其他信息
{
if (pos == 4)cout << " 贪吃蛇";
if (pos == 6)cout << "w:上 s:下 a:左 d:右";
if (pos == 8)cout << "制作者:Pointer=NULL";
if (pos == 10)cout << "当前得分: " << m_nowScore;
if (pos == 12)cout << " 排行榜";
if (pos == 14)cout << m_information.at(0);
if (pos == 15)cout << m_information.at(1);
if (pos == 16)cout << m_information.at(2);
}
食物的生成
void Widget::setFood()//设置食物
{
int x, y;
while (true)
{
srand((unsigned int)time(NULL));//设置随机数种子
x = rand()%38+1;
y = rand() % 24 + 1;
if (m_widget[x][y] == ' ')
{
m_widget[x][y] = '@';//生成食物
break;
}
}
}
蛇的维护
蛇的身体采用链表与对组进行维护
list<pair<int,int>> m_snake;//存放蛇坐标的数组
bool m_snakeStatus;//蛇的状态 用以确定游戏是否结束
char m_MoveDirection;//蛇的移动方向,用以解决用户的错误操作
身体的生成(蛇头与蛇身的方向随机)
void Widget::setSnake()
{
int posRow = 0;
int posCol = 0;
srand((unsigned int)time(NULL));//设置随机数种子
posRow = (rand() % 33) + 3;//取行的随机数
posCol = (rand() % 20) + 3;//取列的随机数
m_widget[posRow][posCol]='@';
m_snake.push_back(pair<int,int>(posRow, posCol));//放入头的坐标
int body = rand() % 4 + 1;//随机身体的方向
if (body == 1)//身体向上
{
m_widget[posRow][posCol -1] = '$';
m_widget[posRow][posCol -2] = '$';
m_snake.push_back(pair<int, int>(posRow, posCol - 1));
m_snake.push_back(pair<int, int>(posRow, posCol - 2));
m_MoveDirection = 's';
}
else if (body == 2)//向下
{
m_widget[posRow][posCol +1] = '$';
m_widget[posRow][posCol +2] = '$';
m_snake.push_back(pair<int, int>(posRow, posCol + 1));
m_snake.push_back(pair<int, int>(posRow, posCol + 2));
m_MoveDirection = 'w';
}
else if (body == 3)//向左
{
m_widget[posRow -1][posCol] = '$';
m_widget[posRow -2][posCol] = '$';
m_snake.push_back(pair<int, int>(posRow -1, posCol));
m_snake.push_back(pair<int, int>(posRow -2, posCol));
m_MoveDirection = 'd';
}
else//向右
{
m_widget[posRow + 1][posCol] = '$';
m_widget[posRow + 2][posCol] = '$';
m_snake.push_back(pair<int, int>(posRow +1, posCol));
m_snake.push_back(pair<int, int>(posRow + 2, posCol));
m_MoveDirection = 'a';
}
}
蛇的移动(链表的移动)
void Widget::snakeMove(char action)
{
m_MoveDirection = action;//记录蛇的方位
switch (action)
{
case 'w':
if (m_widget[m_snake.front().first][m_snake.front().second - 1] == ' '|| m_widget[m_snake.front().first][m_snake.front().second - 1] == '@')
move(m_snake.front().first, m_snake.front().second - 1);
else
{
m_snakeStatus = false;
m_widget[m_snake.front().first][m_snake.front().second -1] = '!';
system("cls");
setWidget();
inputScore(m_nowScore);//处理排行榜
cout << " game over\n";
}
break;
case 's':
if (m_widget[m_snake.front().first][m_snake.front().second + 1] == ' ' || m_widget[m_snake.front().first][m_snake.front().second + 1] == '@')
move(m_snake.front().first, m_snake.front().second + 1);
else
{
m_snakeStatus = false;
m_widget[m_snake.front().first][m_snake.front().second + 1] = '!';
system("cls");
setWidget();
inputScore(m_nowScore);
cout << " game over\n";
}
break;
case 'a':
if (m_widget[m_snake.front().first-1][m_snake.front().second ] == ' ' || m_widget[m_snake.front().first-1][m_snake.front().second ] == '@')
move(m_snake.front().first-1, m_snake.front().second );
else
{
m_snakeStatus = false;
m_widget[m_snake.front().first-1][m_snake.front().second ] = '!';
system("cls");
setWidget();
inputScore(m_nowScore);
cout << " game over\n";
}
break;
case 'd':
if (m_widget[m_snake.front().first+1][m_snake.front().second ] == ' ' || m_widget[m_snake.front().first+1][m_snake.front().second ] == '@')
move(m_snake.front().first+1, m_snake.front().second );
else
{
m_snakeStatus = false;
m_widget[m_snake.front().first+1][m_snake.front().second] = '!';
system("cls");
setWidget();
inputScore(m_nowScore);
cout << " game over\n";
}
break;
default:
break;
}
}
void Widget::move(int x,int y)
{
m_widget[m_snake.front().first][m_snake.front().second] = '$';//重置原头部
if (m_widget[x][y]!='@')//没有吃到食物
{
m_widget[m_snake.back().first][m_snake.back().second] = ' ';//蛇尾改为空
m_snake.pop_back();//删除原蛇尾结点
}
else
{
setFood();
m_nowScore++;
}
m_snake.push_front(pair<int, int>(x, y));//添加新蛇头
m_widget[m_snake.front().first][m_snake.front().second] = '@';
system("cls");
setWidget();
}
蛇的状态(关系到界面维护是否能继续)
bool Widget::getStatus()
{
return m_snakeStatus;
}
void Widget::setStatus(bool status)
{
m_snakeStatus = status;
}
排行榜的实现(文件的读写)
用于排行榜的实现
int m_nowScore;//得分
array<string, 6> m_information;//排行榜信息
int m_score[3];//排行榜成绩用于对比
读取文件中的信息(自定义后缀的文件)
void Widget::readRanking()
{
ofstream outFile("./Ranking.rk",ios::app);//确保文件存在
ifstream inFile;//读取信息
inFile.open("./Ranking.rk");
string tmp;//临时存储数据
if (inFile.is_open()&&!inFile.eof())
{
for (size_t i = 0; !inFile.eof(); i++)
{
getline(inFile, tmp);
m_information.at(i) = tmp;//将数据读入内存
tmp.clear();
}
}
outFile.close();//关闭文件
inFile.close();
for (size_t j = 0; j < 3; j++)
{
if (m_information.at(j).length()!=0)//判断是否有排名信息
{
size_t pos = m_information.at(j).find(":", 6);//获取分数的位置
m_score[j] = atoi(m_information.at(j).substr(pos + 2).c_str());//截取成绩并转为整型
}
}
}
对满足要求的信息录入文件
void Widget::inputScore(int score)
{
if (m_score[0] < score)
{
cout << "得分:" << m_nowScore <<" 恭喜您成为第一名! 请输入您的昵称:(不超过5个字)"<< endl;
char name[10];
cin >> name;
string strFront="昵称:";
string str = name;
strFront += name;
string strTail = " 得分:";
str = to_string(score);
strTail += str;
//将下一位排名后移
m_information.at(2) = m_information.at(1);
m_information.at(1) = m_information.at(0);
m_information.at(0) = strFront + strTail;
}
else if(m_score[1] < score)
{
cout << "得分:" << m_nowScore << " 恭喜您成为第二名! 请输入您的昵称:(不超过5个字)" << endl;
char name[10];
cin >> name;
string strFront = "昵称:";
string str = name;
strFront += name;
string strTail = " 得分:";
str = to_string(score);
strTail += str;
//将下一位后移
m_information.at(2) = m_information.at(1);
m_information.at(1) = strFront + strTail;
}
else if(m_score[2] < score)
{
cout << "得分:" << m_nowScore << " 恭喜您成为第三名! 请输入您的昵称:(不超过5个字)" << endl;
char name[10];
cin >> name;
string strFront = "昵称:";
string str = name;
strFront += name;
string strTail = " 得分:";
str = to_string(score);
strTail += str;
m_information.at(2) = strFront + strTail;
}
else cout << "得分:" << m_nowScore << endl;
ofstream outFile("./Ranking.rk", ios::out);//清楚重写
if (outFile.is_open())
{
for (size_t i = 0; i < 3; i++)
{
outFile << m_information.at(i)<<endl;
}
}
outFile.close();
}
以上就是主要模块的实现
main函数(游戏的启动与基本设置)
bool game()
{
Widget w;
w.setSnake();//设置蛇
w.setStatus(true);//设置状态
w.setFood();//设置食物
w.readRanking();//读取排行榜
w.setWidget();//打印窗口
char input;
while (w.getStatus())//蛇死则本次游戏结束
{
input = _getch();//读取用户的按键输入
do
{
Sleep(250);
if (!w.getStatus())break;
switch (input)//用getMoveDirection()函数判断蛇当前方向,防止蛇出现不符合逻辑的方向变动`在这里插入代码片`
{
case 'w':
if(w.getMoveDirection()!='s')w.snakeMove(input);
else w.snakeMove(w.getMoveDirection());
break;
case 's':
if (w.getMoveDirection() != 'w')w.snakeMove(input);
else w.snakeMove(w.getMoveDirection());
break;
case 'a':
if (w.getMoveDirection() != 'd')w.snakeMove(input);
else w.snakeMove(w.getMoveDirection());
break;
case 'd':
if (w.getMoveDirection() != 'a')w.snakeMove(input);
else w.snakeMove(w.getMoveDirection());
break;
default:
break;
}
} while (!_kbhit());
}
cout << "任意键再次游戏 -(减号退出)" << endl;
input = _getch();
if (input == '-')return false;
return true;
}
int main()
{
while (game())
{
Sleep(1500);
system("cls");
}
return 0;
}
使用到的头文件
#include <iostream>
#include<ctime>
#include<list>
#include<conio.h>
#include<Windows.h>
#include<fstream>
#include<array>
#include<string>
以上就是此贪吃蛇的基本功能代码,存在不足或优化点希望各位大神在评论区指出。
如需源码参考请转至资源下载中心或留下邮箱!