C++课程设计:贪吃蛇

1 内容提要

       项目题目是贪吃蛇(Greedy Snake),实现了Windows控制台下的一个小游戏,这是一个广为人知的非常经典的休闲类小游戏。该游戏功能玩法简单,玩家通过键盘方向键控制蛇上下左右移动,蛇吃到食物得分并增长,直到撞墙等造成死亡游戏才会结束。整个游戏其实就是一个无穷的循环,直到退出游戏时退出循环。这个项目目前仅可进行最基本的贪吃蛇游戏,即开始游戏、选择游戏模式、退出游戏。该项目使用的编程语言为C++语言;所采用的开发环境为code blocks。

2 类设计

       该项目中仅直接定义了一个类,就是Snake(蛇)类。该类的作用,即定义了一个Snake类封装贪吃蛇游戏,并声明了一些基本的变量和成员函数:游戏地图、蛇的长度、蛇头坐标、蛇尾坐标、描述蛇的移动方向、蛇的速度、显示游戏地图的函数、移动函数、生成食物的函数。通过Snake类,可以控制蛇的移动和吃到食物;除此之外,还有蛇的速度游戏地图的展开。该类中的这些设计,在整个项目中发挥着重要作用,是项目正常运行的一大核心。

3 总体设计流程

       输入代码并开始运行程序,首先出现的是游戏开始界面,可选择开始游戏或者退出游戏。若选择退出游戏,则退出程序,程序关闭;若选择开始游戏,则进入游戏模式选择界面,若选择正常模式,直接开始游戏,玩家操作小蛇吃到食物得分并长大,直到小蛇撞墙等造成死亡游戏才结束并显示最终得分,最后可按enter键回到游戏开始界面;若选择无障碍模式,同样直接进入游戏,开始操作小蛇吃到食物。但小蛇撞到墙并不会死亡,如果想结束游戏。可按Esc键退出回到游戏开始界面。

模块划分:

      Snake类:声明一些基本的变量和成员函数,基本的变量包括游戏地图、蛇的长度、蛇头坐标、蛇尾坐标、描述蛇的移动方向、蛇的速度等。

       移动函数move():控制蛇的移动以及蛇头、蛇尾的操作。

       转弯函数turn():蛇的转弯,向左、向右、向上、向下。

       生产食物的函数create():食物是随机生成的,小蛇每吃掉一个食物就得出现新的食物。

       游戏开始函数GameStart函数():用来集成函数,实现函数的基本功能。

4 详细设计

4.1 游戏地图

       显示游戏地图采用函数print(),游戏地图map为二维数组,如果数组元素map[i][j]的值为0,代表该位置什么也没有;如果map[i][j]的值大于0,代表该位置是蛇的身体;如果-1==map[i][j],代表该位置是食物;如果map[i][j]>0,代表该位置是蛇的头部,如表4.1所示。用8,2,4,6作为方向指针来描述蛇的身体,用-8,-2,-4,-6作为方向指针来描述蛇的头部。蛇的身体任何位置沿蛇的身体指向头部,蛇的头部指向蛇的身体。

游戏地图

map[i][j]的值为0

Map[i][j]的值大于0

-1==map[i][j]

Map[i][j]>0

该位置

蛇的身体

食物

蛇的头部

食物用“◇”表示,蛇头用“¤”表示,蛇身用“■”表示实现的代码为:

4.2 蛇的移动

       运用移动move()函数。蛇的移动可以通过“加头去尾”实现,即把蛇尾去掉,在蛇的移动方向加上新的蛇头。这个过程可以拆分成蛇头操作和蛇尾操作。

4.2.1 蛇头操作

       蛇头操作时,先现在的蛇头,在移动后将成为蛇的身体;然后根据蛇的移动方向,生成一个新的蛇头,新蛇头位置指向蛇身。设置几个返回值:0为正常移动,1为撞墙,2为咬到自己。向上移动时,如果蛇头上方是蛇的身体,则咬到自己,返回2;若当前蛇头位置指向新蛇头位置(上),新蛇头位置指向蛇身,则正常移动,返回0;如果0==head[0],则撞墙,返回1。其它向下、左、右也是同样的方法。

4.2.2 蛇尾操作

       蛇尾操作时,由于蛇尾是沿蛇的身体指向蛇头的,所以将蛇尾指向的位置设为新的蛇尾。运行时,如果蛇尾指向下,则蛇尾横坐标-1;如果蛇尾指向下,则蛇尾横坐标+1;如果蛇尾指向左,则蛇尾纵坐标-1;如果蛇尾指向右,则蛇尾纵坐标+1。

4.3 蛇的转弯

       蛇的转弯用转弯函数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;
		}
	}

       用WSAD来控制光标的上下左右移动。如果输入W,则调用转弯函数turn(),参数为上;如果输入S,则调用转弯函数turn(),参数为下;如果输入A,则调用转弯函数turn(),参数为左;如果输入D,则调用转弯函数turn(),参数为右。实现代码如下所示:

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;

4.4 食物

4.4.1 生成食物

     物的生成用函数create()。食物是随机生成的,用rand()函数,该函数在头文件或<stdlib.h>中,rand()函数的功能是返回一个0~RAND_MAX的随机值,RAND_MAX是一个很大的值。但是,rand()函数返回的是一个假随机值,为了得到相对真的随机值,设置了随机数的种子为随机值,时间是随机的,所以用时间作为种子。设置随机数的种子采用代码srand((unsigned)time(NULL))来实现。先确定食物的坐标,食物的行坐标为随机数除最大行数的余数,可以得到0到maxRow-1的一个随机数,食物的列坐标为随机数除最大列数的余数,可得到0到maxCol-1的一个随机数,如表4.4.1。除此之外,不能在蛇的身体上生成食物;最后,按照先前规定的,在地图上把食物用-1表示。实现代码如下:

4.4.2 吃到食物

       前面move()函数的实现原理——“加头去尾”。而吃掉食物之后,蛇的长度要增加,要实现这个功能,就得“加头不去尾”。在move()函数中加入条件判断语句,以向上移动为例:如果蛇头前方是食物,则食物会被蛇吃掉;调用create()新生成一个食物,蛇的长度增加。

实现的代码为:

4.5 游戏开始

     有了移动、转弯、生成食物和显示的函数,游戏的核心已经完备,在Snake类中添加一个GameStart()函数,用来集成这些函数,实现基本的游戏功能。采用_getch()函数和_kbhit()函数完成基本游戏功能。这两个函数在头文件<conio.h>中,这是一个非标准库。如果move()函数的返回非零值,则游戏失败。这几个在代码中的关系如下所示:

       _getch()函数,和getchar()函数类似,不过_getch()函数可以直接读取键盘输入的字符,不用在敲击回车键,适合用来做控制台游戏。如果_kbhit()函数检测到键盘输入,则调用_getch()函数读取,否则游戏进程继续。

       _kbhit()函数,如果有键盘输入,则返回一个非零值,否则返回零值。这个函数是非阻塞的,它不会暂停游戏的进程。为了让蛇在不按键盘时也动,引入了这个函数。如果_kbhit()函数检测到键盘输入,则调用_getch()函数读取,否则游戏进程继续。

实现代码如下所示:

4.6 游戏暂停

       在游戏过程中,按空格键可以使游戏暂停,且暂停界面将出现一个暂停符号;暂停后,在按空格键可以继续游戏。

4.7 蛇的速度

      蛇的长度增加时,速度会加快,Sleep()函数可以暂停游戏的进程,暂停的时间取决于参数,例如:Sleep(1000)表示休眠1000个单位时间。一般来说,1秒有1000个单位时间,则暂停几秒就Sleep几千。在GameStart()函数中加入代码Sleep(1000/speed)来控制游戏速度。蛇的速度和蛇的长度相关,需要计算公式,但无法确定多少合适,用宏来编写:

#define _SPEED(_LENGTH) _LENGTH>6?_LENGTH:6
speed = _SPEED(length);

4.8 游戏界面

       这个项目的运行也由很多界面组成,包括主界面、退出确认窗口、返回确认窗口、结算界面、模式选择窗口。

4.8.1 主界面

       游戏开始的主界面,显示游戏名称贪吃蛇以及边框,并上下选择开始游戏或退出游戏。用maxRow和maxCol来实现边框,确认位置。实现代码如下所示:

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 << "贪吃蛇(GreedySnake)"; 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;
	}

4.8.2 确认窗口

       当选择退出游戏时,会弹出退出确认窗口,左右选择是否要结束游戏。其边框同样由maxRow和maxCol来实现。

       当游戏过程中,选择退出时,会弹出返回确认窗口,左右选择是否返回主菜单,与退出确认窗口相类似,采用的同样的方法。实现代码如下:

4.8.3 结算界面

       小蛇死亡游戏结束后,会弹出结算界面,显示你的最终得分。而游戏得分与蛇的速度采用了同一方法,在代码前面加入#define _SCORE(_LENGTH) _LENGTH,最后得到最终得分,cout << ' '; cout << "你的最终得分为:" << _SCORE(length - initLength)。

4.8.3 选择窗口

       在主界面选择开始游戏之后,进入模式选择窗口,左右选择正常模式或者无障碍模式。与前面的退出确认窗口和返回确认窗口一样,采用的同样的做法。

5 总结

       该项目最大的亮点就是设置了正常与无障碍两种模式。正常模式与无障碍模式区别就在于无障碍模式下,小蛇撞到墙游戏不会结束。当然,这个项目也存在着不足,首先游戏界面太小可能会影响游戏体验,其次,可以植入音乐或是图形库,让游戏效果更好;除此之外,还有一个问题,就是在玩游戏的过程中,游戏界面可能会出现闪的情况,且目前还不知道出现这个问题原因,也没能找到解决办法。

参考文献

[1] 谭浩强.C++程序设计(第三版).北京:清华大学出版社,2015.

[2] 百度百科,rand(),https://baike.baidu.com/item/rand%28%29/3002042

[3] 百度百科,getch(),https://baike.baidu.com/item/getch%28%29/1099639 4

[4]百度百科,kbhit,https://baike.baidu.com/item/kbhit/3921261 

[5]百度百科,Sleep函数,https://baike.baidu.com/item/Sleep%E5%87%BD%E6%95%B0/67350 27

详细软件说明书下载链接:https://download.csdn.net/download/cxx0316/89582641?spm=1001.2014.3001.5503

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

茜茜西西CeCe

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

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

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

打赏作者

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

抵扣说明:

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

余额充值