C++实现贪吃蛇(为女朋友做的)

最近刷LeetCode学数据结构,闲下来了想着自己做个游戏玩玩,于是想到了小时候玩的贪吃蛇,因此决定实践,用了一天的时间终于完成,有很多地方都是边写边改,以后还是先规划好然后依次写完,养成良好的习惯,并且为了保证封装性,每一个类的属性都应该是私有属性

分析:
1.小彭(蛇)需要一个地图移动,并且这个地图不可能是无限大的,因此用一个char型的二维数组来表示map[25][50]来表示地图,并且地图的周围一圈用 # 来围住表示地图边界

*2.小彭 本身需要坐标来表示位置,由许多节组成,那么这每一节都包含一个坐标,头部在地图中由 @ 来表示 身体部分用 来表示 因此写一个结构体Point,其中包含x,y,蛇就由Point类型的数组组成
小彭由几个部分组成,我们来进行拆分:
第一点、画小彭
因为小彭需要在地图中被显示出来,所以在进行绘画画面时我们要先画出小彭
第二点、小彭是否还存活
这需要判断小彭的头有没有与自己的身体相撞,也就是自噬,还需要判断有没有撞墙,即其头部坐标有没有到墙壁
第三点、小彭有没有吃到食物(此处要把小彭作为食物的友元类,才能访问到食物的坐标)
如果小彭吃到了食物,就是小彭此时的头部坐标与食物的坐标重合,将地图中食物此时的符号修改为空格,代表食物已经被吃掉,而且小彭是需要增长的,这就代表我们需要在类中有一个小彭的静态变量代表小彭现在的长度,并以此为依据来进行画小彭的操作
第四点、小彭的移动
在贪吃蛇中,如果我们不进行操作,蛇也是会自动向前运动的,小彭也是同理,因此我们设置一个char队列用来存键盘是否有进行操作,如果键盘按到了 wasd就将这些键位入队,然后从对头开始来依次改变小彭头部方向
第五点、小彭的方向
用一个Point型的变量来代表其头部目前指向的方向:有四个状态(1,0)(-1,0)(0,1)(0,-1)分别代表着向上、向下、向右、向左的移动方向,小彭此时的行进状态就以这个为准,移动过程其实就是后面的每一节到其之前的那一节的坐标,然后蛇头向着目前的方向移动一个坐标即可

3.小彭需要吃东西,因此我们还需要食物,创造一个食物类,食物在地图中由 $ 表示,因为谁会不喜欢吃钱呢
第一点、食物的生成
食物需要在地图内随机生成,所以使用srand加rand进行随机生成,将生成后的坐标放到地图中,并将该坐标的符号修改为 ‘$’
第二点、判断食物是否被吃掉
在小彭吃掉食物后,食物的位置已经变成了‘ ’,可以作为食物被吃掉的判断条件,再进行一次食物的随机生成

新学习的地方:
1.使用system(“cls”)清屏再重构画面,导致画面闪烁
2.利用了kbhit()判断键盘是否发生敲击,ch=getch()来读取输入的字符,并且不用在界面显示

#include <iostream>
#include <cstring>//字符串
#include<stdlib.h>
#include<cmath>//数学
#include<iomanip>//精度控制
#include<string>//字符串
#include<vector>//容器 
#include<algorithm>//算法
#include<stdlib.h>//用system("cls")清屏
#include<conio.h>//用于键盘操作
#include<stack>//栈
#include<queue>
#include <ctime>
using namespace std;
void Startpic();
class food;
class snake;
void Createmap(char imap[25][50], int mapsize);//初始化地图
void gameover();//游戏结束
void Drawhuamian();//画出蛇,食物和地图
void startgame();//游戏开始
char map[25][50];
int source = 0;
queue<char> direction;
void gameover() {//游戏结束
	cout << "小彭撞晕啦!!!" << endl;
	cout << "你的得分为:" << source << endl;
	cout << "1.重新开始" << endl << "2.退出游戏" << endl;
	int a; 
	cin >> a;
	if (a == 1) {
		for (int i = 1; i < 24; i++) {
			for (int j = 1; j < 49; j++) {
				map[i][j] = ' ';
			}
		}
		system("cls"); Startpic();
	}
	else{
		system("cls");
	cout << "~~~小彭携手小周感谢您的游玩!~~~" << endl;
	}
}
void Startpic() {//开始界面
	cout << "##############################################################" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                       贪吃小彭                             #" << endl;
	cout << "#                     ~~~~~~~~~~~~                           #" << endl;
	cout << "#                      1.开始游戏                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                      2.最高纪录                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                      3.退出游戏                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                      I LOVE YOU~                           #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "#                                                            #" << endl;
	cout << "##############################################################" << endl;
	cout << "请进行选择" << endl;
	int a;
	cin >> a;
	if (a == 1) {
		startgame();
	}
	else if (a == 2) {
		cout << "~最高分为~" <<source<<endl;
	}
	else if (a == 3) {
		cout << "~~~小彭携手小周感谢您的游玩!~~~" << endl;
	}
}
class food {//将food类中函数都公有化这样方便调用
	friend class snake;
private:
	int x;
	int y;
	char f1;
public:
	food() {//产生食物
		srand((unsigned)time(NULL));
		x = 10;
		y = 10;
		this->f1 = '$';//代表食物,如果食物变成了空格那么说明食物没了
	}
	void panduanfood() {//判断食物是否还在
		if (map[x][y]!='$') {//食物已经被吃掉
			srand((unsigned)time(NULL));
			x = rand() % 23 - 2;
			y = rand() % 48 - 2;
			map[x][y] = f1;
		}
	}
};
void Createmap(char imap[25][50]) {//初始化地图
	for (int i = 0; i < 25; i++) {
		for (int j = 0; j < 50; j++) {
			if (i == 0 || i == 25 - 1 || j == 0 || j == 50 - 1) {
				imap[i][j] = '#';
			}
		}
	}
	for (int i = 0; i < 25; i++) {
		for (int j = 0; j < 50; j++) {
			if (j == 50 - 1) {
				cout << imap[i][j] << endl;
			}
			else
				cout << imap[i][j];
		}
	}
}
struct Point {//代表点
	int x;
	int y;
};
class snake{
	//1.蛇的长度2.蛇每一节的坐标
public:
	snake() {
		mysnake[0] = { 1,3 };
		mysnake[1] = { 1,2 };
		mysnake[2] = { 1,1 };
		snakehead.x = 0;
		snakehead.y = 1;
		snakesize = 3;
	}
	~snake() {

	}
	void drawsnake() {//画蛇
		map[mysnake[0].x][mysnake[0].y] = '@';//蛇头
		for (int i = 1; i < snakesize; i++) {
			map[mysnake[i].x][mysnake[i].y] = '*';
		}
	}
	void movesnake() {//移动蛇
		if (!direction.empty()) {//已经存入方向
			auto p = direction.front();
			direction.pop();

			if (p == 'w' &&snakehead.x==0) {
				snakehead.x = -1;
				snakehead.y = 0;
			}
			else if (p == 's' && snakehead.x == 0) {
				snakehead.x = 1;
				snakehead.y = 0;
			}
			else if (p == 'a' && snakehead.y == 0) {
				snakehead.x = 0;
				snakehead.y = -1;
			}
			else if (p == 'd' && snakehead.y == 0) {
				snakehead.x = 0;
				snakehead.y = 1;
			}
		}
		map[mysnake[snakesize - 1].x][mysnake[snakesize - 1].y] = ' ';//将map中原本尾巴的位置变为空
		for (int i = snakesize - 1; i >= 1; i--) {//从尾部开始,每一节的坐标都等于其前一节的坐标
			mysnake[i] = { mysnake[i - 1].x,mysnake[i - 1].y };
		}
		mysnake[0] = { mysnake[0].x + snakehead.x,mysnake[0].y + snakehead.y };
	}
	void is_eatfood(food &f1) {
		if (mysnake[0].x == f1.x && mysnake[0].y == f1.y) {
			snakesize++;//蛇长度增加
			source++;//分数增加
			mysnake[snakesize-1] = { mysnake[snakesize - 2].x - snakehead.x,mysnake[snakesize - 2].y - snakehead.y };
			map[f1.x][f1.y] = ' ';//食物已经被吃掉
		}
	}
	bool is_Life() {//判断蛇是否死亡
		if (mysnake[0].x == 24 || mysnake[0].x == 0 || mysnake[0].y == 49 || mysnake[0].y == 0) {
			return false;
		}
		for (int i = 1; i < snakesize; i++) {//检查是否有头撞到身体
			if (mysnake[0].x == mysnake[i].x && mysnake[0].y == mysnake[i].y) {
				return false;
			}
		}
		return true;
	}
protected:
	Point mysnake[100];//蛇最多有100节,用于存坐标
	int snakesize;//蛇目前的节数
	Point snakehead;//蛇的方向由AWSD控制
};
void Drawhuamian(food &f, snake &s1) {//画出蛇,食物和地图
	system("cls");//清屏做地图
	s1.drawsnake();
	s1.is_eatfood(f);
	f.panduanfood();
	Createmap(map);
	s1.movesnake();
}
void startgame() {//开始游戏
	food f1;
	snake s1;
	while (s1.is_Life()) {
		char ch;
		if (kbhit())
		{
			ch = getch();
			switch (ch)
			{
			case 'a':
				direction.push('a');
				break;
			case 'w':
				direction.push('w');
				break;
			case 's':
				direction.push('s');
				break;
			case 'd':
				direction.push('d');
				break;
			}
		}
		Drawhuamian(f1,s1);
	}
	if (!s1.is_Life()) {
		system("cls");
		gameover();
	}
}
int main() {
	Startpic();
}
发布了70 篇原创文章 · 获赞 39 · 访问量 2227

猜你喜欢

转载自blog.csdn.net/weixin_45221477/article/details/105289203