【需求规格说明】
问题:设计一个迷宫寻宝游戏的程序
实现以下功能:
1) 设计一个迷宫地图,包含墙壁、通道、宝藏和敌人。可以使用不同的字符表示地
图的各个元素。
2) 程序随机生成迷宫地图,并在地图上随机放置宝藏和敌人。
3) 玩家通过控制字符移动,尝试找到宝藏。玩家可以使用上、下、左、右四个方向
键控制移动。
4) 程序判断玩家的移动,检测是否撞墙、走出地图边界、找到宝藏、碰到敌人。
5) 程序根据玩家的移动情况给出相应的提示,如撞墙、走出边界、找到宝藏或继续
寻找宝藏。
6) 敌人会随机移动并阻碍玩家的前进,玩家如果与敌人相撞,游戏失败。
7) 提供计分功能,记录玩家寻找宝藏的次数,并在找到宝藏后展示最终结果。
8) 玩家可以选择重新开始游戏或退出游戏。
要求:
1) 提供迷宫地图的大小自定义功能。可以设置为不同的行数和列数。
2) 提供难度级别选择功能。提供不同的难度级别,如简单、中等和困难,难度级别
会影响迷宫的复杂度和敌人的行为。
3) 敌人每次只能并且必须随机移动一个位置,但是敌人不能穿墙、不能走出边界、
不能触碰宝藏、不能与其他敌人相撞。
4) 提供游戏存档和读档功能。玩家可以在游戏进行中保存进度,并在下次继续游戏
时加载之前的存档。
问题描述:
设计一个迷宫寻宝游戏的程序,程序随机生成迷宫地图,并在地图上随机放置宝藏和敌人。玩家通过控制字符移动,尝试找到宝藏。玩家可以使用上、下、左、右四个方向键控制移动。程序判断玩家的移动,检测是否撞墙、走出地图边界、找到宝藏或碰到敌人。程序根据玩家的移动情况给出相应的提示,如撞墙、走出边界、找到宝藏或继续寻找宝藏。敌人会随机移动并阻碍玩家的前进,玩家如果与敌人相撞,游戏失败。提供计分功能,记录玩家寻找宝藏的次数,并在找到宝藏后展示最终结果。玩家可以选择重新开始游戏或退出游戏。
问题分析:
为了设计一个迷宫寻宝游戏的程序,我们需要考虑以下功能和要求:
1.迷宫地图的生成:需要在程序中设计生成迷宫地图的算法,包括随机放置墙壁、通道、宝藏和敌人。
2.玩家移动控制:程序需要根据玩家的输入控制玩家在迷宫中的移动,包括上、下、左、右四个方向的移动。
3.移动判断与提示:程序需要判断玩家的移动是否合法,例如是否撞墙、走出地图边界等,并给出相应的提示信息。
4.敌人移动与碰撞检测:程序需要设计敌人的移动规则,确保敌人随机移动并阻碍玩家前进,同时需要检测玩家与敌人是否相撞。
5.计分功能:程序需要记录玩家寻找宝藏的次数,并在找到宝藏后展示最终结果。
6.难度级别与存档功能:程序需要提供选择不同难度级别和存档功能,方便玩家根据自己的喜好进行游戏体验和保存进度。
【程序设计】
1.设计思想:
1.程序要求通过一个二维数组,设计一个随机生成的迷宫地图,迷宫的行列数、难度都可由用户自己定义。迷宫包括墙壁、通道、敌人、宝藏等几个要素,且要求通过键盘输入对玩家操控的人物进行定向移动,并对地图上的各个要素做出对应的行为。比如,对于墙壁要素,玩家和敌人都无法到达、通过;对于通路,玩家和敌人都可以按照既定方向自由通行,且通路上随机存在宝藏要素;对于宝藏和敌人要素,都是按照一定的规律规则进行随机生成,宝藏收集是玩家胜利的必要条件,通过积分记录玩家收集宝藏的个数,并在全部收集完成后取得胜利的条件,而触碰敌人与否则是玩家失败的必要条件——一旦玩家触碰了敌人,游戏将立即结束,告诉玩家游戏失败的结果及积分数(收集宝藏的个数),另外要注意,敌人具有上下左右随机移动的行为。
2.如何展现迷宫的动态情况是一个值得关注的问题。我们的解决方案是让用户的每一次输入都对二维数组本身的元素进行对应的修改,如玩家移动的行为在二维数组中的体现就是交换玩家和道路两个位置对应的元素,并重新记录玩家所在的位置;在比如对于宝藏要素,在迷宫中的体现是玩家“吃掉”了宝藏,宝藏从地图上消失,玩家的积分+1,而对于二维数组而言,则是玩家元素覆盖了宝藏原来的位置,将玩家原来的位置替换为道路元素,并设置一个静态常量用于记录积分。玩家的每一次移动都伴随着二维数组对应的变化,在玩家移动完成、敌人的随机移动完成后,进行清屏操作,并重新调用打印迷宫的函数,重新打印一遍迷宫,而在用户的视角中,迷宫只是单纯地闪了一下,不会影响游玩的流畅程度。
3.在游戏本身之外,程序还需具有相应的开始结束存档等机制。在程序最开始运行时,将对用户展示一个交互页面,提示用户通过特定的按键选择开始游戏、读取存档或结束游戏。值得注意的是,如果用户输入了以上三个选项对应按键的其他按键,将不会进行任意操作,而是让用户重新选择直到输入了正确的按键。
4.同时,如何使敌人随机移动也是一个难点问题。敌人要求在玩家每移动一次后朝上下左右方向随机移动一次,而且要求不能碰到墙壁、宝藏。同时,敌人随机移动的时机也值得商榷——在玩家移动后先进行判定再移动敌人,还是先移动敌人再进行判定,两者会产生截然不同的结果。对于敌人的随机移动,我们的思路如下——由于敌人最开始是随机生成,并未记录其位置信息,而且程序要求有读取存档的功能,若是将敌人的位置也写入存档文件中,程序对于敌人的处理将会变得异常复杂。所以我们决定将敌人移动的全部行为代码全部在函数moveEnemy()的定义中实现,实现思路如下——首先使用两个for循环查找数组中敌人对应的字符“!”,用if判断是否为敌人,当迭代至敌人元素时,进入一个while循环,循环条件为初始化非零变量,随后生成1-4之间的随机数,代表往上下左右四个方向随机移动,进入switch判断,如果对应方向是通路,则交换通路和敌人的位置,并将控制while循环的变量赋值为0,跳出while循环,继续迭代寻找下一个敌人元素;如果对应方向不是通路而是其他要素,重新进入while循环、生成随机数、判断是否为通路,直到找到通路为止。考虑到会出现敌人四个方向都被阻挡的情况(如上一个敌人移动导致),我们设置了一个变量,使得while循环在进行100次后会强制跳出。我们还考虑到敌人在向右或向下移动后,继续迭代会使得它们重新进入随机移动的判断中,所以我们设置了几个变量由于记录向下或向右移动的敌人的位置,在迭代到这些位置的时候程序会通过if判断跳过这些已经移动过的敌人。
5.在游戏本身之外,程序还需具有相应的开始结束存档等机制。在程序最开始运行时,将对用户展示一个交互页面,提示用户通过特定的按键选择开始游戏、读取存档或结束游戏。值得注意的是,如果用户输入了以上三个选项对应按键的其他按键,将不会进行任意操作,而是让用户重新选择直到输入了正确的按键。对于存档功能的实现方面,我们直接将二维数组的所有字符型元素存放在一个txt文件中,并在最后另起一行用于存放难度、积分等整形的数据,在用户游戏过程中可在任意时刻按下对应按键进行存档,写入txt文件,在用户重新打开程序时,可在初始交互页面选择读取存档,程序会打开存档文件,并对中的字符等进行读取操作,将其全部数据赋值给构建地图的二维数组以及对应的难度、积分等。同时,我们还希望用户在碰到不喜欢的对局时重新开始游戏,所以我们还设置了一个按键用于随时重新开始游戏,由于主函数中存在了较多的循环,方便起见,我们定义了一个宏常量GO_TO_BEGIN来表示goto begin语句,而begin标签位于main函数的最前面,每次调用GO_TO_BEGIN时会回到最开始的交互页面,这在while等循环较多的情况下大大便利了我们程序的编写,同时,也限制了无条件跳转语句goto的使用范围,将其限制为仅可使用跳转至begin标签。
2.设计表示:
【调试报告】
一、对于迷宫的设计,我们最初想到的是狭义上的迷宫,即存在入口和出口,且入口到出口的道路往往是唯一的。那种迷宫的观赏性较高,但存在两个问题,首先是程序设计的难度较高,经过查询资料发现向量容器是必不可少的,而这已经超出了我们的所学知识的范畴,而若直接照搬网上的代码,也失去了课程设计的初衷;另外,如果在那样的迷宫中设置随机移动的敌人,敌人往往会堵住必要的通道,大大影响玩家的游戏体验。于是我们设计了另一种游戏胜利的条件,即收集完所有的宝藏。迷宫生成也并非狭义而是广义上的迷宫,在迷宫的边界以内按照难度,随机生成固定数量的墙壁,难度越低墙壁越少,游戏的难度也就越小。同时测试发现,墙壁数量设置为边界内空格的五分之一,能保证一定难度的情况下尽可能地避免出现玩家、敌人或宝藏堵死的情况。
二、程序要求根据玩家的移动情况给出相应的提示,如撞墙、走出边界、找到宝藏或继续,而在测试中发现,如果按照要求进行游玩时,可能会出现误触而撞墙,最后导致游戏直接结束的情况。同时,如果玩家的每一次移动都伴随着对应的提示,将明显影响游戏的流畅程度。于是我们在最终设计的时候,对于撞墙的情况,程序不会作出任何响应,直到玩家作出正确的行为,即在道路上移动或触碰宝藏等,避免了误触的情况,也更符合此类游戏的实际情况。对于边界,则通过另一种符号进行表示,并在游戏过程中始终将其看作固定的墙壁。同时,在触碰敌人或宝藏时,直接表示为游戏结束或在固定位置提示积分+1,确保游戏的流畅度。
三、我们在编写随即移动敌人的函数时,采用了先迭代查找敌人位置,判断一个位置是否是敌人,而后进入while循环,生成四个随机数对应四个移动方向,直到这个方向为通路时,交换通路和敌人的元素,随后跳出while循环,继续迭代查找下一个敌人元素。在调式程序的时候我们发现了两个突出问题——1.在敌人四面都不是通路的情况下程序会进入死循环而后卡死。这是因为移动敌人的函数中由于始终没有找到通路,从而无限执行while循环,我们的解决方案是定义一个变量初始化为0,在每次调用while循环的时候都会+1,当这个变量大于100时,说明四个方向有极大的概率是没有通路的,所以我们此时会强制跳出while循环,问题得以解决。2.敌人按照逻辑,应该是只移动一个单位的距离,而在运行程序时我们发现敌人经常会移动不止一个距离,有时候会出现一次移动了五个单位以上距离的情况。在我们仔细研究后发现,是因为敌人在成功向右或向下移动后,重新进入迭代,在下一个位置仍然被判定为敌人,从而再一次进入while循环、生成随机数、随机移动,若再次向右或向下移动,最终会出现玩家移动一次敌人移动了五次以上的情况。于是我们设置了几个变量,用于储存向右移动或向下移动后敌人的位置信息,并再迭代判断是否为敌人时,若是这些位置时,直接判定为false,从而跳过这个元素,避免了敌人多次进入循环的情况。
四、在编写main函数时,由于main函数为了实现交互等功能,采用了较多的循环结构,使得在执行某些操作需要重新跳转到main函数开始位置时,让代码变得非常繁琐。因此我们想到了无条件跳转语句goto,但是众所周知,goto函数由于其独特性,往往会使得代码难以理解,甚至使程序陷入未知的严重错误。在权衡利弊之后我们决定还是要使用goto语句,只不过我们在最开始通过 #define GO_TO_BEGIN goto begin 语句定义了一个宏变量GO_TO_BEGIN,由于我们程序中只会通过GO_TO_BEGIN间接调用goto语句,这从而限制了goto语句的使用范围,避免出现某些未知的情况。而begin标签我们则设置在了main函数最开始的地方。
【源代码】
#include <iostream>
#include <fstream> //读写文件,用于存档读档
#include <conio.h> //键盘输入,kbhit() 函数
//测试代码
//#include <Windows.h>
//#include <ctime>
using namespace std;
const int M = 50; //控制最大行列数,同时便于函数编写
const int N = 50;
const char savedFile[] = "saved_game.txt";
#define GO_TO_BEGIN goto begin //无条件跳转至begin,同时限制了goto的功能
int row, col; //人的初始位置
char key = '0'; //用户输入的按键
static int d2 = 0; //敌人数量初始化
static int d3 = 0; //宝藏数量初始化
//生成迷宫,m和n分别表示迷宫的行数和列数
//difficulty代表难易程度,可以采用不同级别表示
void generateMap(char matrix[][N], int m, int n, int difficulty) {
int i, j;
srand(time(NULL)); //设置随机数种子
//初始化迷宫,用空格表示通道,用"#"表示边缘墙壁
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
//边界位置设置为#,由于打印迷宫时不会打印超出的部分,所以超出部分不影响
if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
matrix[i][j] = '#';
}
else {
matrix[i][j] = ' ';
}
}
}
//d用于控制难度系数,影响墙、宝藏、敌人的数量
int d1 = 0;
switch (difficulty) {
case 1: {
d1 = 9;
break;
}
case 2: {
d1 = 7;
break;
}
case 3: {
d1 = 5;
break;
}
}
//生成随机的迷宫内墙壁
for (i = 0; i < m * n / d1; i++) {
matrix[rand() % (m - 2) + 1][rand() % (n - 2) + 1] = '*';
}
//随机生成敌人
switch (difficulty) {
case 1: {
d2 = 2;
break;
}
case 2: {
d2 = 4;
break;
}
case 3: {
d2 = 6;
break;
}
}
//随机生成敌人
for (i = 0; i < d2; i++) {
matrix[rand() % (m - 2) + 1][rand() % (n - 2) + 1] = '!';
}
//生成随机的宝藏
switch (difficulty) {
case 1: {
d3 = 2;
break;
}
case 2: {
d3 = 4;
break;
}
case 3: {
d3 = 6;
break;
}
}
//随机生成宝藏
for (i = 0; i < d3; i++) {
matrix[rand() % (m - 2) + 1][rand() % (n - 2) + 1] = '$';
}
}
//打印迷宫
void displayMap(char matrix[][N], int m, int n) {
system("cls"); //清空屏幕
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
cout << matrix[i][j] << ' ';
}
cout << endl;
}
}
//游戏存档,将游戏的当前状态存储到saved_game.txt文件中
//如果游戏存档成功,则返回true;否则,返回false
bool saveGame(char matrix[][N], int m, int n, int dif, int ach) {
ofstream outfile("d://saved_game.txt", ios::out); // 打开文件流
if (!outfile) {
cerr << "存档文件打开失败!" << endl;
return false;
}
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
outfile << matrix[i][j];
}
outfile << '\n';
}
outfile << m << ' ' << n << ' ' << dif << ' ' << ach;
outfile.close(); // 关闭文件流
return true;
}
//读档游戏,读取saved_game.txt游戏存档文件,恢复游戏
//如果游戏读档成功,则返回true;否则,返回false
bool loadGame(char matrix[][N], int& m, int& n, int& dif, int& ach) {
ifstream file("d://saved_game.txt"); // 打开文本文件
if (file.is_open()) {
// 逐行读取包含空格的字符,并存储到二维数组中
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
file.get(matrix[i][j]); // 使用get()函数读取字符,包括可能的空格
}
file.ignore(1); // 忽略每行末尾的换行符
}
//创建一个字符串变量用于存放读取的整型数据
char tmp[20];
file >> tmp;
//一一读取
m = atoi(tmp);
file >> tmp;
n = atoi(tmp);
file >> tmp;
dif = atoi(tmp);
file >> tmp;
ach = atoi(tmp);
//测试代码
//file >> m >> n >> dif >> ach; //此代码无效!
//dif = 3;
//ach = 1;
//m = 13;
//n = 31;
file.close(); // 关闭文件
}
return true;
}
//判断游戏当前状态:找到宝藏返回1;与敌人相撞返回2;继续游戏返回3
int statusGame(char matrix[][N], int m, int n) {
switch (key) {
case 'w': // 向上移动
if (matrix[row - 1][col] == '$') {
return 1;
}
else if (matrix[row - 1][col] == '!') {
return 2;
}
else
break;
case 's': // 向下移动
if (matrix[row + 1][col] == '$') {
return 1;
}
else if (matrix[row + 1][col] == '!') {
return 2;
}
else
break;
case 'a': // 向左移动
if (matrix[row][col - 1] == '$') {
return 1;
}
else if (matrix[row][col - 1] == '!') {
return 2;
}
else
break;
case 'd': // 向右移动
if (matrix[row][col + 1] == '$') {
return 1;
}
else if (matrix[row][col + 1] == '!') {
return 2;
}
else
break;
}
return 3;
}
//判断位置(x, y)是否是墙,y表示行号,x表示列号
bool isWall(char matrix[][N], int x, int y) {
if (matrix[x][y] == '*') {
return true;
}
return false;
//测试代码
//switch (key) {
//case 'w': // 向上移动
// if (matrix[row - 1][col] == '*') {
// return true;
// }
// break;
//case 's': // 向下移动
// if (matrix[row + 1][col] == '*') {
// return true;
// }
// break;
//case 'a': // 向左移动
// if (matrix[row][col - 1] == '*') {
// return true;
// }
// break;
//case 'd': // 向右移动
// if (matrix[row][col + 1] == '*') {
// return true;
// }
//}
}
//判断位置(x, y)是否出界,y表示行号,x表示列号
bool isOutside(char matrix[][N], int x, int y) {
if (matrix[x][y] == '#') {
return true;
}
return false;
}
//判断位置(x, y)是否是敌人,y表示行号,x表示列号
bool isEnemy(char matrix[][N], int x, int y) {
if (matrix[x][y] == '!') {
return true;
}
return false;
}
//判断位置(x, y)是否是宝藏,y表示行号,x表示列号
bool isTreasure(char matrix[][N], int x, int y) {
if (matrix[x][y] == '$') {
return true;
}
return false;
}
//移动玩家的位置,如果移动成功,返回true;否则返回false
//dir表示输入的方向,(1,2,3,4)分别对应(上,下,左,右)
bool movePlayer(char matrix[][N], int m, int n, int dir) {
if (statusGame(matrix, m, n) == 1) {
//碰到宝藏时的实现方式
switch (key) {
case 'w': {// 向上移动
matrix[row][col] = ' ';
row--;
matrix[row][col] = '@';
break;
}
case 's': {// 向下移动
matrix[row][col] = ' ';
row++;
matrix[row][col] = '@';
break;
}
case 'a': {// 向左移动
matrix[row][col] = ' ';
col--;
matrix[row][col] = '@';
break;
}
case 'd': {// 向右移动
matrix[row][col] = ' ';
col++;
matrix[row][col] = '@';
break;
}
}
}
//正常移动的实现方式
else {
switch (key) {
case 'w': // 向上移动
if (matrix[row - 1][col] == ' ') {
dir = 1;
matrix[row][col] = ' ';
row--;
matrix[row][col] = '@';
}
break;
case 's': // 向下移动
if (matrix[row + 1][col] == ' ') {
dir = 2;
matrix[row][col] = ' ';
row++;
matrix[row][col] = '@';
}
break;
case 'a': // 向左移动
if (matrix[row][col - 1] == ' ') {
dir = 3;
matrix[row][col] = ' ';
col--;
matrix[row][col] = '@';
}
break;
case 'd': // 向右移动
if (matrix[row][col + 1] == ' ') {
dir = 4;
matrix[row][col] = ' ';
col++;
matrix[row][col] = '@';
}
break;
}
}
if (matrix[row][col] != '@')
return false;
return true;
}
//随机移动所有敌人的位置
void moveEnemy(char matrix[][N], int m, int n) {
int i = 0;
int j = 0;
int c = 0; //用于修正迭代的问题
int d = 0;
int e = 0;
while (1) {
//迭代找到所有的敌人(!)
for (i = 1; i < m - 1; i++) {
for (j = 1; j < n - 1; j++) {
if (i == c && j == d) {
c = 0;
d = 0;
continue; //避免敌人向下移动时重新进入迭代
}
if (j == e) {
e = -1;
continue; //避免敌人向右移动时重新进入迭代
}
//迭代至敌人时
if (matrix[i][j] == '!') {
int a = 1;
int b = 0;
while (a) {
switch (rand() % 4 + 1) { //生成1到4的随机数
//随机上下左右移动
case 1: // 向上移动
if (matrix[i - 1][j] == ' ') {
//交换敌人和通路,表示敌人移动一次
matrix[i][j] = ' ';
matrix[i - 1][j] = '!';
a = 0; //移动成功,跳出while循环
break;
}
//如果目标位置不是空格
else
//跳出switch循环并重新进入,继续随机选择,直到成功移动
break;
case 2: // 向下移动
if (matrix[i + 1][j] == ' ') {
matrix[i][j] = ' ';
//i--;
matrix[i + 1][j] = '!';
a = 0;
c = i + 1; //记录位置,避免再次进入迭代重复移动
d = j;
break;
}
else
break;
case 3: // 向左移动
if (matrix[i][j - 1] == ' ') {
matrix[i][j] = ' ';
//i--;
matrix[i][j - 1] = '!';
a = 0;
break;
}
else
break;
case 4: // 向右移动
if (matrix[i][j + 1] == ' ') {
matrix[i][j] = ' ';
//i--;
matrix[i][j + 1] = '!';
a = 0;
e = j + 1; //记录位置,避免再次进入迭代重复移动
break;
}
else
break;
}
b++;
if (b == 100) //避免因为某一个敌人无处可去而陷入死循环
a = 0; //此时跳出while循环
}
}
}
}
break;
}
}
int main() {
//标签,用于配合goto语句
begin:
char matrix[M][N]; //组成迷宫的二维数组
int m = 0, n = 0, difficulty = 0; //迷宫的行列数和难度
int ach = 0; //宝藏计分
int select; //存放用户的选择
//打印交互页面
cout << "**********************" << endl;
cout << "***** 1.开始游戏 *****" << endl;
cout << "***** 2.读取存档 *****" << endl;
cout << "***** 3.结束游戏 *****" << endl;
cout << "**********************" << endl;
cout << "请选择:";
cin >> select;
//对游戏的运行进行判断选择
if (select == 1) {
cout << "请输入迷宫的行数和列数:";
cin >> m >> n;
//测试代码
//m = 20;
//n = 20;
cout << "迷宫的难易程度:" << endl <<
" 1: 简单" << endl <<
" 2: 中等" << endl <<
" 3: 困难" << endl <<
"请选择本次游戏的难度:";
cin >> difficulty;
//difficulty = 2;
generateMap(matrix, m, n, difficulty);
row = 1; //人物出发点位于迷宫 第二行
col = rand() % (n - 2) + 1; // 第二列 到 倒数第二列
matrix[row][col] = '@'; //初始化人物的位置
cout << endl << "---------------按任意键开始游戏!---------------" << endl << endl;
while (1) {
while (!_kbhit()) {
// 循环等待键盘输入
}
if (_kbhit()) { // 如果有键盘输入
key = _getch();
//输入Esc键则直接退出游戏
if (key == 27) { // Esc键
return 0; // 退出游戏
}
//输入L键则存档
else if (key == 'L' || key == 'l') { // L键
saveGame(matrix, m, n, difficulty, ach); // 存档
system("cls"); //清空屏幕
cout << "存档成功";
return 0;
}
//输入K键则重新开始
else if (key == 'k' || key == 'K') {
system("cls");
GO_TO_BEGIN;
}
//输入其他键位
int A = statusGame(matrix, m, n);
movePlayer(matrix, m, n, 0);
displayMap(matrix, m, n);
switch (A) {
case 1: {
ach++;
break;
}
case 2: {
system("cls");
cout << "触碰怪物,游戏结束!" << endl;
cout << "你的最终分数为 " << ach << " 分!" << endl;
cout << "————————————————" << endl;
char YN = 0;
cout << "是否要重新开始游戏(Y/N):";
cin >> YN;
if (YN == 'y' || YN == 'Y')
GO_TO_BEGIN;
else
return 0;
}
case 3:
break;
}
if (ach == d3) {
system("cls");
cout << " ********** " << endl;
cout << " *** *** " << endl;
cout << "* WIN! *" << endl;
cout << " *** *** " << endl;
cout << " ********** " << endl;
cout << "泰裤辣!" << "你在" << d2 << "个敌人的围追堵截下收集了全部" << d3 << "个宝藏!" << endl;
return 0;
}
moveEnemy(matrix, m, n);
}
cout << "请输入移动方向(WSAD控制方向):" << endl;
cout << "你目前的分数是:" << ach << endl;
cout << "按下esc键退出游戏" << endl;
cout << "按下L键存档游戏" << endl;
cout << "按下K键重新开始" << endl;
}
}
//即选择读取存档
else if (select == 2) {
bool loadSuccess = loadGame(matrix, m, n, difficulty, ach);
if (loadSuccess) {
cout << "存档载入成功!" << endl;//读档成功
int i = 0;
int j = 0;
//迭代查找存档中人物的位置,并记录
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
if (matrix[i][j] == '@') {
row = i;
col = j; //存档中人物的位置
}
}
}
//根据读取到的难度得出敌人数和宝藏数的初始值
switch (difficulty) {
case 1: {
d2 = 2;
d3 = 2;
break;
}
case 2: {
d2 = 2;
d3 = 4;
break;
}
case 3: {
d2 = 2;
d3 = 6;
break;
}
}
cout << endl << "---------------按任意键开始游戏!---------------" << endl << endl;
//以下代码同上
while (1) {
while (!_kbhit()) {
// 循环等待键盘输入
}
if (_kbhit()) { // 如果有键盘输入
key = _getch();
if (key == 27) { // Esc键
return 0; // 退出游戏
}
else if (key == 'L' || key == 'l') { // L键
saveGame(matrix, m, n, difficulty, ach); // 存档
system("cls"); //清空屏幕
cout << "存档成功";
return 0;
}
else if (key == 'k' || key == 'K') {
system("cls");
GO_TO_BEGIN;
}
int A = statusGame(matrix, m, n);
movePlayer(matrix, m, n, 0);
displayMap(matrix, m, n);
switch (A) {
case 1: {
ach++;
break;
}
case 2: {
system("cls");
cout << "触碰怪物,游戏结束!" << endl;
cout << "你的最终分数为 " << ach << " 分!" << endl;
cout << "————————————————" << endl;
char YN = 0;
cout << "是否要重新开始游戏(Y/N):";
cin >> YN;
if (YN == 'y' || YN == 'Y') {
system("cls");
GO_TO_BEGIN;
}
else
return 0;
}
case 3:
break;
}
if (ach == d3) {
system("cls");
cout << " ********** " << endl;
cout << " *** *** " << endl;
cout << "* WIN! *" << endl;
cout << " *** *** " << endl;
cout << " ********** " << endl;
cout << "泰裤辣!" << "你在" << d2 << "个敌人的围追堵截下收集了全部" << d3 << "个宝藏!" << endl;
return 0;
}
moveEnemy(matrix, m, n);
}
cout << "请输入移动方向(WSAD控制方向):" << endl;
cout << "你目前的分数是:" << ach << endl;
cout << "按下esc键退出游戏" << endl;
cout << "按下L键存档游戏" << endl;
cout << "按下K键重新开始" << endl;
}
}
//读档失败的情况
else {
system("cls");
cout << "存档载入失败!" << endl;//读档失败
system("pause");
system("cls");
GO_TO_BEGIN;
}
}
//选择退出游戏,直接return
else if (select == 3) {
return 0;
}
//输入其他按键,清屏并回到初始位置重新选择
else {
system("cls");
GO_TO_BEGIN;
}
}
【运行结果展示】
【小结】
该系列游戏的设计虽然风格比较单调,知识纯粹的控制台可视化,并且应用了饱受code界诟病的go_to语句,但限于笔者水平,是业已能够开发的较完善层次(笔者开发时正处大一懵懂期),欢迎更多大佬前来批评指正,也欢迎更多小白来借鉴引用(code里的注释拉满了),希望China的coding质量越来越高!也希望open coding越做越好!