C++设计迷宫游戏

C++三维迷宫游戏开发:从迷宫生成到剧情模式设计 在C++小游戏开发中,选择合适的数据结构与算法,是构建沉浸式体验的基础。通过多维数组对迷宫地图分层存储,配合深度优先搜索(递归回溯)随机生成连通路径,再借助有限状态机来驱动任务进度与剧情事件,能够有效提升游戏的可玩性与工程可维护性。这种设计不仅适用于控制台环境下的三维迷宫项目,也是许多游戏课程设计中的高频考点。第一人称视角的渲染则可采用射线投射方法,用距离映射墙高,在字符界面中模拟纵深空间。围绕一次从v1.0到v2.0的升级实践,本文展示了如何在三维迷宫中融入剧情模式:事件点作为独立表级联交互、对话框分页显 阅读详情

【需求规格说明】

问题:设计一个迷宫寻宝游戏的程序

实现以下功能:

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越做越好!

c++课程设计之迷宫游戏 第一章 任务概述 1.1背景 1.2总体任务要求 第二章 需求分析 2.1总体需求概述 2.2功能需求 2.3非功能需求 第三章 概要设计 3.1总体架构设计 3.2关键流程设计 第四章 详细设计 4.1界面详细设计 4.2数据结构详细设计 一、任务概述 1.1背景 以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,... 阅读详情

相关推荐

c++基础项目,迷宫小游戏的设计与实现

#include <iostream> #include<stdio.h> #include<windows.h> #include<conio.h> #include<time.h> #include<math.h> #include <fstream> #include <cstdlib> #define WALL 0 //墙 #define ROAD 1 //路径 #define PLAYER 2//...

qq_53370066的博客 1529

C++ 迷宫游戏

介绍 本程序是根据广度优先遍历算法的思想设计的一款迷宫游戏,游戏设计了两种模式一种自动游戏模式,一种手动模式。因为项目在 Linux 开发,需要在 Windows 开发的,请查看源代码中需要修改地方的备注。 代码 #include &amp;amp;lt;iostream&amp;amp;gt; #include &amp;amp;lt;cstdlib&amp;amp;gt; //标准库 #include &amp;amp;lt;unistd.h&amp;

麦迪儿的博客 1万+

C++打造迷宫游戏,直接上代码

C++ 迷宫游戏实现代码 题目: 通过让游戏角色自动寻找迷宫出口,走出迷宫,来练习C++面向对象之封装的基础知识。迷宫图如下所示,其中X表示墙。 1、程序分析 走出去的原理:遵循右手规则或左手规则。右手扶墙走,就会走出迷宫,反之,亦然。 step1 创建迷宫类,打印出迷宫地图。 step2 创建走迷宫的人的类。 2、程序实现 MazeMap.h #...

wyh15895833492的博客 4562

c++深搜1-迷宫类问题

深搜-迷宫类问题

Mark1277的博客 4785

C++实现一个老鼠走迷宫游戏

代码 由于C++面向对象的编程方式,注重于数据的处理,所以一个类的设计显得尤为重要。 这里我就设计了一个迷宫类,其属性有迷宫大小,空格(可行路径)的数目,入口坐标,出口坐标,以及主角老鼠的坐标,以及bool变量pass,表示判断此次生成的迷宫从入口到出口是否有通关路径。 private里的函数有构造迷宫(通过rand系函数随机生成路径,’#’代表路障,’ ‘代表可通过路径,’*’代表老鼠...

Canger_的博客 7407

c++迷宫游戏

但学习不会随着课设的结束而结束,课程也给我指明了未来努力的方向.课程中最大的困难还是一些难以查出的错误,编译时查不出的错误,其被发现时很可能只是位置的错误,仅隔数行,这些微小的信息却极大地影响了整体的效果.这不仅存在于一个程序之中,因而我对于生活中的细节也有了改观,对于整体和局部的观念也有了更多的见解.在老鼠闯关只能在地图显示是路的地方行走,不能穿墙,有计时功能,当时间结束时若没有到达指定地点,显示game over,查看排行榜,游戏结束,若成功到达指定位置,进去下一关,直到所有关结束,程序结束;

m0_38073539的博客 1765

数据结构与算法课程设计——C++迷宫游戏

问题描述 程序开始运行时显示一个迷宫地图,迷宫中央有一只老鼠,迷宫的右下方有一个粮仓。游戏的任务是使用键盘上的方向健操纵老鼠在规定的时间内走到粮仓处。 基本要求 (1) 老鼠形象可以辨认,可用键盘操纵老鼠上下左右移动 (2) 迷宫的墙足够结实,老鼠不能穿墙而过 (3) 正确检测结果,若老鼠在规定时间内走到粮仓处,提示成功,并给出一条路径,否则提示失败 (4) 添加编辑迷宫功能,可修改当前迷宫,修改内容:墙变路、路变墙 提高要求 (1) 增加闯关和计分功能 (2) 找出走出迷宫的所有路径及最短路径 源代码 注

Mr_BigG的博客 2万+

C++实现设计一个迷宫寻宝游戏

提供不同的难度级别,如简单、中等和困难,难度级别会影响迷宫的复杂度和敌人的行为。3)敌人每次只能并且必须随机移动一个位置,但是敌人不能穿墙、不能走出边界不能触碰宝藏、不能与其他敌人相撞。4)提供游戏存档和读档功能。5)程序根据玩家的移动情况给出相应的提示,如撞墙、走出边界、找到宝藏或继续寻找宝藏。4)程序判断玩家的移动,检测是否撞墙、走出地图边界、找到宝藏、碰到敌人。7)提供计分功能,记录玩家寻找宝藏的次数,并在找到宝藏后展示最终结果。6)敌人会随机移动并阻碍玩家的前进,玩家如果与敌人相撞,游戏失败。

走向CTO的路上... 1228

【重庆工程学院】C/C++迷宫游戏设计[2024-12-22]

所以,在解决迷宫问题的算法中要我们要应用“栈”的思想,假设“当前位置”指的是在探索过程中某一时刻游戏对象所在的位置,在解决迷宫问题中一条路径的算法的基本思想是:对象所在的当前位置,放入“当前路径”,并继续朝“下一位置”探索,即切换到“下一个位置”为“当前位置”并且隐藏掉上一个位置的坐标点,如此重复直至到达出口;选择手动或者自动生成一个n×m的迷宫,将迷宫的左上角作入口,右下角作出口,设“0”为通路,“1”为墙,即无法穿越。(一) 迷宫是一个N*M的方正,则可以用二维数组map[N][M]来表示。

code helper 965

C++迷宫游戏项目实战:从设计到实现

在面向对象编程中,类是创建对象的模板或蓝图。游戏中的每一个元素通常都对应一个类,该类定义了对象的属性和方法。public:// 属性int health;int mana;// 方法die();// 默认死亡逻辑// 构造函数在上述示例中,我们定义了一个名为的类,其中包含了两个属性health和mana,以及两个方法takeDamage和die。构造函数用于初始化对象状态。代码逻辑解读:- 类包含基本的游戏元素属性,如生命值和法力值。

weixin_28793831的博客 799

实战指南:如何用Kamailio+FreeSWITCH搭建高并发企业通信系统(附配置模板)

本文提供了一份实战指南,详细介绍了如何利用Kamailio与FreeSWITCH构建高并发企业通信系统。通过将Kamailio作为高性能SIP信令平面处理路由与负载均衡,FreeSWITCH作为媒体与应用平面负责通话与业务逻辑,实现信令与媒体分离的电信级架构。文章深入解析了架构设计、核心配置、集群部署与性能优化,并附有配置模板,旨在帮助企业构建可水平扩展、高可用的通信解决方案。

dell8的博客 364

C++课程设计项目:基于 Qt 制作的一个迷宫小游戏

深度优先 广度优先:C++课程设计项目:基于 Qt 制作的一个迷宫小游戏

qq1309399183的博客 319

从打印攻击到视频重放:手把手用OULU-NPU训练你的第一个活体检测模型

本文详细介绍了如何使用OULU-NPU数据集训练活体检测模型,以应对打印攻击和视频重放等安全威胁。通过PyTorch框架,从环境准备、数据加载、预处理到模型架构设计,手把手教你构建一个高效的双流网络,结合CNN和LSTM技术,提升模型在多种攻击场景下的检测准确率。

weixin_29092031的博客 385

游戏开发新视角:用Dev-C++打造交互式迷宫游戏的用户体验设计

本文探讨了使用Dev-C++开发交互式迷宫游戏的用户体验设计,重点介绍了核心交互设计、控制台界面优化、迷宫生成算法及增强沉浸感的技巧。通过即时反馈机制、渐进式难度曲线和视觉引导系统,提升游戏体验。适合初学者通过走迷宫小游戏锻炼编程思维。

weixin_29019241的博客 366

VC Spyglass CDC验证避坑指南:如何正确配置同步复位信号(实验二重点解析)

本文深入解析VC Spyglass CDC验证中同步复位信号的正确配置方法,通过实验二案例详细展示错误配置的典型表现及修正过程。文章提供同步复位的最佳实践方案,包括约束文件修改指南、验证流程优化建议和高级调试技巧,帮助工程师有效避免CDC验证中的常见陷阱。

rock5的博客 678

东方财富个股实时行情爬虫实战:从入门到精通,手把手教你构建股票数据采集系统

在量化投资、股市分析和数据挖掘等领域,获取实时、准确的股票行情数据是第一步也是至关重要的一步。东方财富网作为国内最大的财经门户网站之一,提供了丰富的股票数据和实时行情接口。本文将带你从零开始,构建一个完整的东方财富个股实时行情爬虫系统,涵盖股票代码遍历、JSON接口分析、反爬虫策略应对、数据持久化存储等核心技术点。目录前言一、项目背景与目标1.1 为什么要爬取东方财富数据?1.2 项目目标1.3 技术栈二、接口分析与逆向工程2.1 寻找真实数据接口2.2 简化接口2.3 字段含义对照表三、股票代码获取。

2201_76125261的博客 145

C++课程设计项目_基于 Qt 制作的一个迷宫小游戏

C++课程设计项目_基于 Qt 制作的一个迷宫小游戏

QQ_1309399183的博客 214

网格质量评价

CFD中评价网格质量的方法

B_etter_Man的博客 1万+

基于C++的智能迷宫游戏系统设计与实现

本文设计并实现了一个智能迷宫游戏系统,该系统能够自动生成随机复杂的有解迷宫,并提供多种路径规划算法寻找最优路径。系统采用模块化设计,包含用户登录、迷宫生成、自动寻路、信息展示等功能模块。在算法层面,实现了深度优先递归回溯、随机普利姆等迷宫生成算法,以及宽度优先搜索、深度优先搜索等路径规划算法。系统通过可视化界面动态展示算法执行过程,并提供执行信息反馈。研究对不同算法的性能进行了分析比较,总结了各算法的适用场景。该系统不仅具有游戏功能,还可作为算法教学演示工具,为人工智能路径规划研究提供了实践参考。

毕业作品网站 1309

大数据安全 | 期末复习(上)| 补档

大数据定义:无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

知识库搭建ing 2588

串口、COM、UART、TTL、USB、RS-232、RS-485、I2C、SPI、CAN、1-WIRE

一文搞定,赶紧收藏吧

记得诚 3万+

Sound Maze:基于SFML与C++14的音频迷宫游戏设计与实现

在游戏开发中,视觉反馈往往被默认为核心,但音频导航同样能构建完整的交互体验。空间音频技术通过声源定位与距离衰减,让玩家仅凭双耳即可感知方向与远近,这为无障碍游戏设计和创新玩法开辟了新的路径。SFML作为轻量级C++多媒体库,其音频模块封装了OpenAL,以简洁的接口实现立体声定位,特别适合验证音频游戏的最小可行方案。借助C++14的现代语法与稳定的工具链支持,开发者可以高效实现递归回溯迷宫生成、碰撞反馈和动态音效更新等核心逻辑。Sound Maze项目正是一个典型的实践样本,展示了如何利用SFML和C++1

weixin_28192383的博客 219

执行HDevelop项目

这一节,我们讲述的是如何用HDevEngine加载和执行一个HDevelop项目。代码部分来源于示例程序exec_program(源文件exec_program.cpp),检测塑料零件边界上的毛刺。1.Step 1:初始化首先,我们包含HALCON/C++和HDevEngine头文件以及命名空间。注意到在这个示例程序中,HDevEngine头文件已经包含在my_hdevoperatorimpl中,所

Z's Palace 2994

c 实现走迷宫流程图_用c++编写一个迷宫游戏

这段时间,熟悉了c++ class后,我决定可以开始写一个走迷宫游戏了。准备开始首先是流程:1.获得用户名称。2.让用户自定义迷宫地图。3.生成地图。4.接受用户输入,移动小人。5.判断是否到达目的地。流程图:我们将所有文件放入Mazeman-text文件夹中,下面分析一下文件结构:接下来就是着手实现了。实现MAN类库打开man.h文件夹,将基本内容写好#ifndefMAN_H#defineM...

weixin_42467661的博客 885

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

python迷宫小游戏代码_C++课程设计迷宫小游戏

温馨提示程序语言:C、C++、C#、Python(红色字体表示本课设使用的程序设计语言)图形功能选项:Win32控制台程序(黑框、文本界面)、Win32程序、MFC、WinForm、DirectX10(黑体标明表示本课设的程序图形类别,默认为非图形界面Win32控制台程序)数据结构:基础类型、数组、链表、双向链表、搜索树(非平衡二叉树)、平衡二叉树、链表与平衡二叉树相结合、堆栈、队列、串、图(黑体...

weixin_39956558的博客 476

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: 交通地理信息系统实习教程(一)
下一篇: ArcGIS Pro完成构建校园地图操作指南
CUGLin
博客等级 码龄4年 585粉丝 35原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值