C++ 实现贪吃蛇(控制台)

贪吃蛇

效果图如下:
效果图
所有功能由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>

以上就是此贪吃蛇的基本功能代码,存在不足或优化点希望各位大神在评论区指出。
如需源码参考请转至资源下载中心或留下邮箱!

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pointer=NULL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值