贪吃蛇详细教程-C++实现

和小白一起做贪吃蛇吧!会C++就可以上车!

小白第一次写文章,如有不足之处,欢迎大家指出!
因为本人是新手,所以尽量使用通俗易懂的话,没有太多专业术语,不太会用目录,大佬还请多多包涵!

前言:本文所有的方向用8,2,4,6表示,对应小键盘上的↑,↓,←,→,这么做可以直观地看出方向,方便程序的编写。
考虑到有读者可能不了解一些游戏必备的函数,所以我做了简要的介绍,大佬请跳过*部分。

首先,我们定义一个Snake类封装贪吃蛇游戏,并声明一些基本的变量和成员函数:

class Snake {
private:
	signed char**map;//游戏地图
	int length;//蛇的长度
	int head[2];//蛇头坐标
	int tail[2];//蛇尾坐标
	char direction;//描述蛇的移动方向:8-↑,2-↓,4-←,6-→
	char speed;//蛇的速度
	
	void print()const;	//显示游戏地图的函数
	int move() ;//移动函数:0-正常移动,1-撞墙,2-咬到自己
	void turn(int const&kbinput) ;//转弯函数
	void create() ;//生成食物的函数
}

核心设计思路:
游戏地图map为二维数组,如果数组元素map[ i ][ j ]的值为0,代表该位置什么也没有;如果map[ i ][ j ]的值>0,代表该位置是蛇的身体;如果 -1 == map[ i ][ j ],代表该位置是食物;如果map[ i ][ j ] > 0,代表该位置是蛇的头部。
如果把蛇的头部和身体都用一个定值来表示,则我们无法描述蛇的形状,也无从得知蛇头在哪里;所以我们不妨用8,2,4,6作为方向指针来描述蛇的身体,用-8,-2,-4,-6作为方向指针来描述蛇的头部。蛇的身体任何位置沿蛇的身体指向头部,蛇的头部指向蛇的身体,如果这段解释很难读懂,请看下面的例子:

例1:蛇头向右,长度为5的一条蛇,可以表示为:→→→→←即6 6 6 6 (-4)
例2:蛇头向右的一条蛇
→→→↓□□□→←
□□□→→→→↑
可以表示为:
6 6 6 2 0 0 0 6 (-4)
0 0 0 6 6 6 6 8

移动函数move():
我们很容易想到,蛇的移动可以通过“加头去尾”实现,即把蛇尾去掉,在蛇的移动方向加上新的蛇头。这个过程可以拆分成蛇头操作和蛇尾操作:
1)蛇头操作:先现在的蛇头,在移动后将成为蛇的身体;然后根据蛇的移动方向,生成一个新的蛇头:

int move() {//返回值:0-正常移动,1-撞墙,2-咬到自己
			//direction是描述蛇的移动方向的变量成员:8-↑,2-↓,4-←,6-→
			switch (direction) {
			int front;//判断蛇头前方有无障碍物的变量
			case 8://向上移动
				if (head[0]) {
					if ((front = map[head[0] - 1][head[1]]) > 0)return 2;//如果蛇头上方是蛇的身体,则咬到自己,返回2
					map[head[0]--][head[1]] = 8;//当前蛇头位置指向新蛇头位置(上)
					map[head[0]][head[1]] = -2;//新蛇头位置指向蛇身
					return 0;//正常移动,返回0
				}
				else return 1;//如果0==head[0]则撞墙,返回1
			case 2://向下移动
				if (head[0] < maxRow - 1) {
					if ((front = map[head[0] + 1][head[1]]) > 0)return 2;//如果蛇头下方是蛇的身体,则咬到自己,返回2
					map[head[0]++][head[1]] = 2;//当前蛇头位置指向新蛇头位置(下)
					map[head[0]][head[1]] = -8;//新蛇头位置指向蛇身
					return 0;//正常移动,返回0
				}
				else return 1;//如果maxRow-1==head[0]则撞墙,返回1
			case 4://向左移动
				if (head[1]) {
					if ((front = map[head[0]][head[1] - 1]) > 0)return 2;//如果蛇头左方是蛇的身体,则咬到自己,返回2
					map[head[0]][head[1]--] = 4;//当前蛇头位置指向新蛇头位置(左)
					map[head[0]][head[1]] = -6;//新蛇头位置指向蛇身
					return 0;//正常移动,返回0
				}
				else return 1;//如果0==head[1]则撞墙,返回1
			case 6://向右移动
				if (head[1] < maxCol - 1) {
					if ((front = map[head[0]][head[1] + 1]) > 0) return 2;//如果蛇头右方是蛇的身体,则咬到自己,返回2
					map[head[0]][head[1]++] = 6;//当前蛇头位置指向新蛇头位置(右)
					map[head[0]][head[1]] = -4;//新蛇头位置指向蛇身
					return 0;//正常移动,返回0
				}
				else return 1;//如果maxCol-1==head[0]则撞墙,返回1

2)蛇尾操作:由于蛇尾是沿蛇的身体指向蛇头的,所以只需要将蛇尾指向的位置设为新的蛇尾,我们将下面这段代码补充到move()函数中

switch (map[tail[0]][tail[1]]) {
					case 8:map[tail[0]--][tail[1]] = 0; break;//如果蛇尾指向上,则蛇尾横坐标-1
					case 2:map[tail[0]++][tail[1]] = 0; break;//如果蛇尾指向下,则蛇尾横坐标+1
					case 4:map[tail[0]][tail[1]--] = 0; break;//如果蛇尾指向左,则蛇尾纵坐标-1
					case 6:map[tail[0]][tail[1]++] = 0; break;//如果蛇尾指向上,则蛇尾纵坐标+1
					}

这样我们就完成了移动函数move()的定义,其他的函数相对简单,需要的读者可以继续往下看:

转弯函数turn():
需要注意的是,不是所有情况下都可以改变蛇的方向,比如蛇正在往右走,就不能把方向设置成左,也没必要把方向设置成右

//根据参数kbint来调整蛇的方向
void turn(int const&kbinput) {
		switch (kbinput) {
		case 8:if (4 == direction || 6 == direction)direction = 8; break;//如果蛇左右移动,则把方向设置成上
		case 2:if (4 == direction || 6 == direction)direction = 2; break;//如果蛇左右移动,则把方向设置成下
		case 4:if (8 == direction || 2 == direction)direction = 4; break;//如果蛇上下移动,则把方向设置成左
		case 6:if (8 == direction || 2 == direction)direction = 6; break;//如果蛇上下移动,则把方向设置成右
		}
	}

生成食物的函数create():
*食物是随机生成的,需要用到rand()函数,该函数在头文件或<stdlib.h>中,rand()函数的功能是返回一个0~RAND_MAX的随机值,RAND_MAX是一个很大的值,在本文中不做介绍,请读者自行查阅。
*需要注意的是,rand()函数返回的是一个假随机值,要得到相对真的随机值,需要设置随机数的种子为随机值,时间是随机的,所以我们用时间作为种子:

#include<cstdlib>
//将下面的代码放在游戏开始前
srand((unsigned)time(NULL));

设置了随机数的种子后,我们就可以使用随机数了:

void create() {
		int position[2];//食物的坐标
		do {
			position[0] = rand() % maxRow;//食物的行坐标为随机数除最大行数的余数,这样可以得到0到maxRow-1的一个随机数
			position[1] = rand() % maxCol;//食物的列坐标为随机数除最大列数的余数,这样可以得到0到maxCol-1的一个随机数
		} while (map[position[0]][position[1]]);//不能在蛇的身体上生成食物
		map[position[0]][position[1]] = -1;//按照我们的规定,在地图上把食物用-1表示
	}

完成了生成食物函数的书写,我们需要进一步完善移动函数move():
还记得move()函数的实现原理吗?“加头去尾”。那么吃到了食物后,我们希望蛇的长度增加,为了实现这个功能,应该"加头不去尾":

//在move()函数中加入条件判断语句,向上移动为例:
if (front < 0) { create(); length++; }//如果蛇头前方是食物,则食物会被吃掉->调用create()新生成一个食物,蛇的长度增加
//以下部分不变
else switch (map[tail[0]][tail[1]]) {
case 8:map[tail[0]--][tail[1]] = 0; break;
case 2:map[tail[0]++][tail[1]] = 0; break;
case 4:map[tail[0]][tail[1]--] = 0; break;
case 6:map[tail[0]][tail[1]++] = 0; break;
}

显示游戏地图的函数print()很简单,读者可以根据自己的喜好书写。

有了移动,转弯,生成食物和显示的函数,游戏的核心已经完备,下面我们在Snake类中添加一个GameStart()函数,用来集成这些函数,实现基本的游戏功能,不过在这之前我们先了解2个重要的函数:
*_getch()函数,和getchar()函数相似,不过_getch()函数可以直接读取键盘输入的字符,不用再敲击回车键,适合用来做控制台游戏。
*_kbhit()函数,如果有键盘输入,则返回一个非零值,否则返回零值。这个函数是非阻塞的,它不会暂停游戏的进程。我们希望不按键盘时蛇也会动,所以这个函数是必要的。
*以上2个函数在头文件<conio.h>中,这是一个非标准库。
用_getch()函数和_kbhit()函数完成基本游戏功能:

#include<conio.h>
public:
	void GameStart() {
		srand((unsigned)time(NULL));//设置随机数的种子
		while (true) {
			print();//显示地图
			//如果_kbhit()函数检测到键盘输入,则调用_getch()函数读取,否则游戏进程继续
			if (_kbhit())switch (_getch()) {
			case'w':case'W':turn(8); break;//如果输入w,则调用转弯函数turn(),参数为上
			case's':case'S':turn(2); break;//如果输入s,则调用转弯函数turn(),参数为下
			case'a':case'A':turn(4); break;//如果输入a,则调用转弯函数turn(),参数为左
			case'd':case'D':turn(6); break;//如果输入d,则调用转弯函数turn(),参数为右
			}
			if (move());//GameOver//如果move()函数的返回非零值,则游戏失败,游戏失败后怎么做请读者自行设计
		}
	}

有了游戏的基本框架,我们再来设计一些能丰富游戏性的功能:
我们希望蛇的长度增加时,游戏速度会加快,在设计这个功能之前,我们先了解Sleep()函数,知道CLOCK_PER_SEC的读者请跳过
Sleep()函数可以暂停游戏的进程,暂停的时间取决于参数,例如:

Sleep(1000);//休眠1000个单位时间,不是1000秒!

一般来说1秒有1000个单位时间,所以暂停几秒就Sleep几千。
在GameStart()函数中加入下面的代码,达到控制游戏速度的目的:

Sleep(1000/speed);//speed是蛇的速度

蛇的速度应该和蛇的长度相关,需要一定的计算公式,但是我们第一次编程时可能不知道多少合适,所以用宏来编写:

#define _SPEED(_LENGTH) _LENGTH-3//例如:蛇的速度=蛇的长度-3,速度公式宏读者可以自由改写
//将下面的代码加在create()函数末尾,因为生成了食物则蛇的长度一定发生了改变,则速度应该随之改变
speed=_SPEED(length);

到这里,简易的贪吃蛇游戏就写完了,最后附上完整代码:

//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
/*作者的话:
**游戏名称:OC贪吃蛇/OCSnake
**游戏版本:1.0
**游戏规则:WSAD控制光标,空格暂停,ENTER确定,ESC退出
*/
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
#include<iostream>
#include<string>
#include<Windows.h>
#include<ctime>
#include<conio.h>
using namespace std;
#define _SPEED(_LENGTH) _LENGTH>6?_LENGTH:6//蛇的速度
#define _SCORE(_LENGTH) _LENGTH//游戏得分
//贪吃蛇
class Snake {
public:
	//默认构造函数
	Snake() :length(3), direction(6), speed(3), maxRow(10), maxCol(15), initLength(3) {
		map = new signed char*[maxRow];
		int count;
		for (count = 0; count < maxRow; count++) {
			map[count] = new signed char[maxCol];
			memset(map[count], 0, maxCol);
		}
		head[0] = 0; head[1] = 2;
		tail[0] = 0; tail[1] = 0;
		for (count = 0; count < 2; count++)
			map[0][count] = 6;
		map[0][count] = -4;
		system("title OCSnake");
		system(string("mode con cols=" + to_string(2 * maxCol + 4) + " lines=" + to_string(maxRow + 2)).c_str());
		create();
	}
	//构造函数:MRow>=8,MCol>=10
	Snake(int const&MRow, int const&MCol, int const&init_length = 3) :direction(6), maxRow(MRow), maxCol(MCol), initLength(init_length) {
		length = initLength;
		map = new signed char*[maxRow];
		int count;
		for (count = 0; count < maxRow; count++) {
			map[count] = new signed char[maxCol];
			memset(map[count], 0, maxCol);
		}
		head[0] = 0; head[1] = initLength - 1;
		tail[0] = 0; tail[1] = 0;
		for (count = 0; count < initLength - 1; count++)
			map[0][count] = 6;
		map[0][count] = -4;
		system("title OCSnake");
		system(string("mode con cols=" + to_string(2 * maxCol + 4) + " lines=" + to_string(maxRow + 2)).c_str());
		create();
	}
	//游戏开始
	void GameStart() {
		srand((unsigned)time(NULL));
	LABEL_MAIN_WINDOW://主窗口标签
		if (MainWindow())
			if (QuitOrNot())goto LABEL_MAIN_WINDOW;
			else exit(0);
		else if (ChooseMode())goto LABEL_MAIN_WINDOW;
		Sleep(CLOCKS_PER_SEC);
		char pause_before_continue = 0;
		while (true) {
			print();
			if (pause_before_continue) { Sleep(CLOCKS_PER_SEC); pause_before_continue = 0; }
			if (_kbhit())switch (_getch()) {
			case'w':case'W':turn(8); break;
			case's':case'S':turn(2); break;
			case'a':case'A':turn(4); break;
			case'd':case'D':turn(6); break;
			case 27:case 32: LABEL_PAUSE_WINDOW://暂停窗口
				if (0 == pause()) {
					if (0 == ReturnToMainWindow())goto LABEL_MAIN_WINDOW; 
					else goto LABEL_PAUSE_WINDOW;
				}pause_before_continue = 1;
				break;
			}if (move()) { Sleep(CLOCKS_PER_SEC); score(); goto LABEL_MAIN_WINDOW; }
			Sleep(CLOCKS_PER_SEC / speed);
		}
	}
	//析构函数
	~Snake() {
		int count;
		for (count = 0; count < maxCol; count++)
			delete[]map[count];
		delete[]map;
	}
private:
	signed char**map;//地图
	int length;//蛇的长度
	int head[2];//蛇头坐标
	int tail[2];//蛇尾坐标
	char direction;//移动方向:8-↑,2-↓,4-←,6-→
	char speed;//蛇的速度
	const char maxRow;//地图最大行数
	const char maxCol;//地图最大列数
	const char initLength;//初始蛇长
	char mode;//游戏模式:0-正常模式,1-无障碍模式
	//打印
	void print()const {
		int i, j; signed char judge;
		for (i = 0; i < maxCol + 2; i++)cout << "□";
		cout << endl;
		for (i = 0; i < maxRow; i++) {
			cout << "□";
			for (j = 0; j < maxCol; j++) {
				judge = map[i][j];
				if (0 == judge)cout << "  ";
				else if (judge > 0)cout << "■";
				else if (-1 == judge)cout << "◇";
				else cout << "¤";
			}cout << "□" << endl;
		}for (i = 0; i < maxCol + 2; i++)cout << "□";
	}
	//移动:0-正常移动,1-撞墙,2-咬到自己
	int move() {
		int front;
		if (0 == mode) {
			switch (direction) {
			case 8:
				if (head[0]) {
					if ((front = map[head[0] - 1][head[1]]) > 0)return 2;
					map[head[0]--][head[1]] = 8;
					map[head[0]][head[1]] = -2;
					if (front < 0) { create(); length++; }
					else switch (map[tail[0]][tail[1]]) {
					case 8:map[tail[0]--][tail[1]] = 0; break;
					case 2:map[tail[0]++][tail[1]] = 0; break;
					case 4:map[tail[0]][tail[1]--] = 0; break;
					case 6:map[tail[0]][tail[1]++] = 0; break;
					}return 0;
				}
				else return 1;
			case 2:
				if (head[0] < maxRow - 1) {
					if ((front = map[head[0] + 1][head[1]]) > 0)return 2;
					map[head[0]++][head[1]] = 2;
					map[head[0]][head[1]] = -8;
					if (front < 0) { create(); length++; }
					else switch (map[tail[0]][tail[1]]) {
					case 8:map[tail[0]--][tail[1]] = 0; break;
					case 2:map[tail[0]++][tail[1]] = 0; break;
					case 4:map[tail[0]][tail[1]--] = 0; break;
					case 6:map[tail[0]][tail[1]++] = 0; break;
					}return 0;
				}
				else return 1;
			case 4:
				if (head[1]) {
					if ((front = map[head[0]][head[1] - 1]) > 0)return 2;
					map[head[0]][head[1]--] = 4;
					map[head[0]][head[1]] = -6;
					if (front < 0) { create(); length++; }
					else switch (map[tail[0]][tail[1]]) {
					case 8:map[tail[0]--][tail[1]] = 0; break;
					case 2:map[tail[0]++][tail[1]] = 0; break;
					case 4:map[tail[0]][tail[1]--] = 0; break;
					case 6:map[tail[0]][tail[1]++] = 0; break;
					}return 0;
				}
				else return 1;
			case 6:
				if (head[1] < maxCol - 1) {
					if ((front = map[head[0]][head[1] + 1]) > 0) return 2;
					map[head[0]][head[1]++] = 6;
					map[head[0]][head[1]] = -4;
					if (front < 0) { create(); length++; }
					else switch (map[tail[0]][tail[1]]) {
					case 8:map[tail[0]--][tail[1]] = 0; break;
					case 2:map[tail[0]++][tail[1]] = 0; break;
					case 4:map[tail[0]][tail[1]--] = 0; break;
					case 6:map[tail[0]][tail[1]++] = 0; break;
					}return 0;
				}
				else return 1;
			default:return -1;
			}
		}
		else {
			char judge;
			switch (direction) {
			case 8:
				if (head[0]) {
					if ((front = map[head[0] - 1][head[1]]) > 0)return 2;
					map[head[0]--][head[1]] = 8;
					map[head[0]][head[1]] = -2;
				}
				else {
					if ((front = map[maxRow - 1][head[1]]) > 0)return 2;
					map[head[0]][head[1]] = 8; head[0] = maxRow - 1;
					map[head[0]][head[1]] = -2;
				}
					if (front < 0) { create(); length++; }
					else {
						judge = map[tail[0]][tail[1]]; map[tail[0]][tail[1]] = 0;
						switch (judge) {
						case 8: if (tail[0])tail[0]--; else tail[0] = maxRow - 1; break;
						case 2: if (tail[0] < maxRow - 1)tail[0]++; else tail[0] = 0; break;
						case 4: if (tail[1])tail[1]--; else tail[1] = maxCol - 1; break;
						case 6:if (tail[1] < maxCol - 1)tail[1]++; else tail[1] = 0; break;
						}
					}return 0;
			case 2:
				if (head[0] < maxRow - 1) {
					if ((front = map[head[0] + 1][head[1]]) > 0)return 2;
					map[head[0]++][head[1]] = 2;
					map[head[0]][head[1]] = -8;
				}
				else {
					if ((front = map[0][head[1]]) > 0)return 2;
					map[head[0]][head[1]] = 2; head[0] = 0;
					map[head[0]][head[1]] = -8;
				}
				if (front < 0) { create(); length++; }
				else {
					judge = map[tail[0]][tail[1]]; map[tail[0]][tail[1]] = 0;
					switch (judge) {
					case 8: if (tail[0])tail[0]--; else tail[0] = maxRow - 1; break;
					case 2: if (tail[0] < maxRow - 1)tail[0]++; else tail[0] = 0; break;
					case 4: if (tail[1])tail[1]--; else tail[1] = maxCol - 1; break;
					case 6:if (tail[1] < maxCol - 1)tail[1]++; else tail[1] = 0; break;
					}
				}return 0;
			case 4:
				if (head[1]) {
					if ((front = map[head[0]][head[1] - 1]) > 0)return 2;
					map[head[0]][head[1]--] = 4;
					map[head[0]][head[1]] = -6;
				}
				else {
					if ((front = map[head[0]][maxCol - 1]) > 0)return 2;
					map[head[0]][head[1]] = 4; head[1] = maxCol - 1;
					map[head[0]][head[1]] = -6;
				}
				if (front < 0) { create(); length++; }
				else {
					judge = map[tail[0]][tail[1]]; map[tail[0]][tail[1]] = 0;
					switch (judge) {
					case 8: if (tail[0])tail[0]--; else tail[0] = maxRow - 1; break;
					case 2: if (tail[0] < maxRow - 1)tail[0]++; else tail[0] = 0; break;
					case 4: if (tail[1])tail[1]--; else tail[1] = maxCol - 1; break;
					case 6:if (tail[1] < maxCol - 1)tail[1]++; else tail[1] = 0; break;
					}
				}return 0;
			case 6:
				if (head[1] < maxCol - 1) {
					if ((front = map[head[0]][head[1] + 1]) > 0) return 2;
					map[head[0]][head[1]++] = 6;
					map[head[0]][head[1]] = -4;
				}
				else {
					if ((front = map[head[0]][0]) > 0) return 2;
					map[head[0]][head[1]] = 6; head[1] = 0;
					map[head[0]][head[1]] = -4;
				}
				if (front < 0) { create(); length++; }
				else {
					judge = map[tail[0]][tail[1]]; map[tail[0]][tail[1]] = 0;
					switch (judge) {
					case 8: if (tail[0])tail[0]--; else tail[0] = maxRow - 1; break;
					case 2: if (tail[0] < maxRow - 1)tail[0]++; else tail[0] = 0; break;
					case 4: if (tail[1])tail[1]--; else tail[1] = maxCol - 1; break;
					case 6:if (tail[1] < maxCol - 1)tail[1]++; else tail[1] = 0; break;
					}
				}return 0;
			default:return -1;
			}
		}
	}
	//转弯
	void turn(int const&kbinput) {
		switch (kbinput) {
		case 8:if (4 == direction || 6 == direction)direction = 8; break;
		case 2:if (4 == direction || 6 == direction)direction = 2; break;
		case 4:if (8 == direction || 2 == direction)direction = 4; break;
		case 6:if (8 == direction || 2 == direction)direction = 6; break;
		}
	}
	//生成食物
	void create() {
		int position[2];
		do {
			position[0] = rand() % maxRow;
			position[1] = rand() % maxCol;
		} while (map[position[0]][position[1]]);
		map[position[0]][position[1]] = -1;
		speed = _SPEED(length);
	}
	//暂停游戏:0-返回主界面,1-继续游戏
	int pause() {
		int i, j; signed char judge;
		for (i = 0; i < maxCol + 2; i++)cout << "□";
		cout << endl;
		for (i = 0; i < maxRow / 2 - 3; i++) {
			cout << "□";
			for (j = 0; j < maxCol; j++)cout << "  ";
			cout << "□" << endl;
		}
		cout << "□"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "◣    "; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "□" << endl;
		cout << "□"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■◣  "; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "□" << endl;
		cout << "□"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■■◣"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "□" << endl;
		cout << "□"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■■◤"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "□" << endl;
		cout << "□"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■◤  "; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "□" << endl;
		cout << "□"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "◤    "; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "□" << endl;
		for (; i < maxRow - 6; i++) {
			cout << "□";
			for (j = 0; j < maxCol; j++)cout << "  ";
			cout << "□" << endl;
		}
		for (i = 0; i < maxCol + 2; i++)cout << "□";
		judge = _getch();
		while (judge != 27 && judge != 32)judge = _getch();
		return 27 == judge ? 0 : 1;
	}
	//主界面:0-开始,1-退出
	int MainWindow() {
		system("cls");
		char cursor = 0, position = 0;
		do {
			unsigned short i, j;
			for (i = 0; i < maxCol + 2; i++)cout << "■";
			cout << endl;
			for (i = 0; i < maxRow / 2 - 1; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}
			cout << "■"; for (j = 0; j < maxCol - 8; j++)cout << ' '; cout << "OC贪吃蛇/OCSnake"; for (j = 0; j < maxCol - 8; j++)cout << ' '; cout << "■" << endl;
			cout << "■"; for (j = 0; j < maxCol - 4; j++)cout << ' '; cout << "开始游戏"; 
			if (0 == position)cout << "←"; for (j = 2 - 2 * position; j < maxCol - 4; j++)cout << ' '; cout << "■" << endl;
			cout << "■"; for (j = 0; j < maxCol - 4; j++)cout << ' '; cout << "退出游戏";
			if (position)cout << "←";  for (j = 2 * position; j < maxCol - 4; j++)cout << ' '; cout << "■" << endl;
			for (; i < maxRow - 3; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}
			for (i = 0; i < maxCol + 2; i++)cout << "■";
			cursor = _getch();
			if (('w' == cursor || 'W' == cursor) && position)position--;
			else if (('s' == cursor || 'S' == cursor) && 0 == position)position++;
			else if (27 == cursor)return 1;
		} while (cursor != '\r');
		return position;
	}
	//退出确认窗口:0-是,1-否
	int QuitOrNot() {
		char cursor = 0, position = 0;
		do {
			unsigned short i, j;
			for (i = 0; i < maxCol + 2; i++)cout << "■";
			cout << endl;
			for (i = 0; i < maxRow / 2 - 1; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}
			cout << "■"; for (j = 0; j < maxCol - 6; j++)cout << ' '; cout << "要结束游戏吗"; for (j = 0; j < maxCol - 6; j++)cout << ' '; cout << "■" << endl;
			cout << "■"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "是  否"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■" << endl;
			if (0 == position) { cout << "■"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "↑"; for (j = 0; j < maxCol + 1; j++)cout << ' '; cout << "■" << endl; }
			else { cout << "■"; for (j = 0; j < maxCol + 1; j++)cout << ' '; cout << "↑"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■" << endl; }
			for (; i < maxRow - 3; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}for (i = 0; i < maxCol + 2; i++)cout << "■";
			cursor = _getch();
			if (('a' == cursor || 'A' == cursor) && position)position--;
			else if (('d' == cursor || 'D' == cursor) && 0 == position)position++;
			else if (27 == cursor)return 1;
		} while (cursor != '\r');
		return position;
	}
	//返回主菜单:0-是,1-否
	int ReturnToMainWindow() {
		char cursor = 0, position = 0;
		do {
			unsigned short i, j;
			for (i = 0; i < maxCol + 2; i++)cout << "■";
			cout << endl;
			for (i = 0; i < maxRow / 2 - 1; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}
			cout << "■"; for (j = 0; j < maxCol - 7; j++)cout << ' '; cout << "要返回主菜单吗"; for (j = 0; j < maxCol - 7; j++)cout << ' '; cout << "■" << endl;
			cout << "■"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "是  否"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■" << endl;
			if (0 == position) { cout << "■"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "↑"; for (j = 0; j < maxCol + 1; j++)cout << ' '; cout << "■" << endl; }
			else { cout << "■"; for (j = 0; j < maxCol + 1; j++)cout << ' '; cout << "↑"; for (j = 0; j < maxCol - 3; j++)cout << ' '; cout << "■" << endl; }
			for (; i < maxRow - 3; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}for (i = 0; i < maxCol + 2; i++)cout << "■";
			cursor = _getch();
			if (('a' == cursor || 'A' == cursor) && position)position--;
			else if (('d' == cursor || 'D' == cursor) && 0 == position)position++;
			else if (27 == cursor)return 1;
		} while (cursor != '\r');
		return position;
	}
	//结算界面
	void score() {
		int count; signed char judge;
		system("cls");
		for (count = 0; count < maxCol/2-2; count++)cout << endl;
		for (count = 0; count < maxCol - 2; count++)cout << ' '; cout << "游戏结束" << endl;
		for (count = 0; count < maxCol - 6; count++)cout << ' '; cout << "你的最终得分为:" << _SCORE(length - initLength);
		for (count = 0; count < maxRow; count++) {
			map[count] = new signed char[maxCol];
			memset(map[count], 0, maxCol);
		}
		head[0] = 0; head[1] = initLength - 1;
		tail[0] = 0; tail[1] = 0;
		for (count = 0; count < initLength - 1; count++)
			map[0][count] = 6;
		map[0][count] = -4;
		direction = 6; 
		length = initLength; create();
		judge = _getch();
		while (judge != 27 && judge != '\r')judge = _getch();
	}
	//模式选择窗口:0-开始游戏,1-返回主菜单
	int ChooseMode() {
		char cursor = 0, position = 0;
		do {
			unsigned short i, j;
			for (i = 0; i < maxCol + 2; i++)cout << "■";
			cout << endl;
			for (i = 0; i < maxRow / 2 - 1; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}
			cout << "■"; for (j = 0; j < maxCol - 7; j++)cout << ' '; cout << "请选择游戏模式"; for (j = 0; j < maxCol - 7; j++)cout << ' '; cout << "■" << endl;
			cout << "■"; for (j = 0; j < maxCol - 6; j++)cout << ' '; cout << "正常  无障碍"; for (j = 0; j < maxCol - 6; j++)cout << ' '; cout << "■" << endl;
			if (0 == position) { cout << "■"; for (j = 0; j < maxCol - 5; j++)cout << ' '; cout << "↑"; for (j = 0; j < maxCol + 3; j++)cout << ' '; cout << "■" << endl; }
			else { cout << "■"; for (j = 0; j < maxCol + 2; j++)cout << ' '; cout << "↑"; for (j = 0; j < maxCol - 4; j++)cout << ' '; cout << "■" << endl; }
			for (; i < maxRow - 3; i++) {
				cout << "■";
				for (j = 0; j < maxCol; j++)cout << "  ";
				cout << "■" << endl;
			}for (i = 0; i < maxCol + 2; i++)cout << "■";
			cursor = _getch();
			if (('a' == cursor || 'A' == cursor) && position)position--;
			else if (('d' == cursor || 'D' == cursor) && 0 == position)position++;
			else if (27 == cursor)return 1;
		} while (cursor != '\r');
		mode = position;
		return 0;
	}
};
int main() {
	Snake OCSnake;
	OCSnake.GameStart();
	return 0;
}

有需要的话会再写一个无障碍模式的教程,觉得我说得不明白的话请在评论区批评指正,总之希望能帮到读者,感谢阅读!

  • 53
    点赞
  • 234
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
以下是一个简单的贪吃蛇C++语言程序代码: ```cpp #include <iostream> #include <conio.h> #include <windows.h> using namespace std; bool gameOver; const int width = 20; const int height = 20; int x, y, fruitX, fruitY, score; int tailX[100], tailY[100]; int nTail; enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN }; eDirection dir; void Setup() { gameOver = false; dir = STOP; x = width / 2; y = height / 2; fruitX = rand() % width; fruitY = rand() % height; score = 0; } void Draw() { system("cls"); for (int i = 0; i < width + 2; i++) cout << "#"; cout << endl; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == 0) cout << "#"; if (i == y && j == x) cout << "O"; else if (i == fruitY && j == fruitX) cout << "F"; else { bool print = false; for (int k = 0; k < nTail; k++) { if (tailX[k] == j && tailY[k] == i) { cout << "o"; print = true; } } if (!print) cout << " "; } if (j == width - 1) cout << "#"; } cout << endl; } for (int i = 0; i < width + 2; i++) cout << "#"; cout << endl; cout << "Score:" << score << endl; } void Input() { if (_kbhit()) { switch (_getch()) { case 'a': dir = LEFT; break; case 'd': dir = RIGHT; break; case 'w': dir = UP; break; case 's': dir = DOWN; break; case 'x': gameOver = true; break; } } } void Logic() { int prevX = tailX[0]; int prevY = tailY[0]; int prev2X, prev2Y; tailX[0] = x; tailY[0] = y; for (int i = 1; i < nTail; i++) { prev2X = tailX[i]; prev2Y = tailY[i]; tailX[i] = prevX; tailY[i] = prevY; prevX = prev2X; prevY = prev2Y; } switch (dir) { case LEFT: x--; break; case RIGHT: x++; break; case UP: y--; break; case DOWN: y++; break; default: break; } if (x > width || x < 0 || y > height || y < 0) gameOver = true; for (int i = 0; i < nTail; i++) if (tailX[i] == x && tailY[i] == y) gameOver = true; if (x == fruitX && y == fruitY) { score += 10; fruitX = rand() % width; fruitY = rand() % height; nTail++; } } int main() { Setup(); while (!gameOver) { Draw(); Input(); Logic(); Sleep(50); } return 0; } ```
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值