文章目录
前言
这是一位萌新对自己编程能力的一种实践,也是他热情与奋斗的体现。
它的玩法基本完善,是一个迷宫游戏,包含二维和三维迷宫的功能,具有地图生成、保存/加载、颜色设置、动态障碍物等特性。(个人认为还有改进空间,如DIY功能还未实现,以及切换操作键位等)
作者邮箱真会回复!
正文
从最初的1.0.0,到如今的1.1.4,经历了大概半个月的时间(有些代码还是AI帮我解决问题的)
目前代码属于C++11支持,可以在DEVC++5.11和visual studio上运行。
接下来还会不断更新。。。。。。一些小版本就不再展示了,等到功能焕然一新,会发第二版的游戏。一些小的建议或反馈可以发送给作者,我都会采纳的。希望大家多多支持!
以下是《小时迷宫》的完整使用说明,涵盖核心玩法、功能操作和实用技巧:
一、游戏基础信息
-
目标:操控角色(
o
)从起点抵达终点($
),避开动态/静态障碍。
-
适用平台:Windows(支持控制台运行)
-
存档路径:
D:\Labyrinth_Shi\
(自动创建文件夹)
二、核心玩法详解
1. 基础操作
模式 | 按键 | 功能 |
---|---|---|
2D | W/A/S/D | 上/左/下/右移动 |
3D | W/A/S/D | 平面移动 |
3D | U/N | 垂直上升/下降 |
3D | X/Y/Z | 切换视图(XY / YZ / Z*X) |
通用 | 空格键 | 暂停游戏(弹出菜单) |
2. 障碍类型
符号 | 名称 | 特性 | 应对策略 |
---|---|---|---|
x | 静态墙 | 永久阻挡,触碰即死 | 绝对避开 |
^ | 动态刺 | 周期性凸起(危险) | 观察节奏,缩回时通过 |
_ | 休眠刺 | 周期性缩回(安全) | 快速穿越 |
3. 胜利条件
- 2D模式:到达地图右下角(坐标
H,W
) - 3D模式:到达三维顶点(坐标
H3D,W3D,L3D
)
三、功能设置指南
1. 游戏设置(主菜单 → 设置)
选项 | 功能说明 | 推荐配置 |
---|---|---|
颜色自定义 | 调整角色/墙/刺/终点的显示颜色 | 高对比度配色(如红墙黄终点) |
地图尺寸 | 2D支持10x10~37x133,3D支持35x35x35 | 新手建议10x10小地图 |
重置默认 | 恢复初始颜色和地图大小 | 卡关时使用 |
2. 存档管理
功能 | 操作路径 | 说明 |
---|---|---|
保存 | 暂停菜单 → 按1 | 存档至D:\Labyrinth_Shi\ 自定义命名 |
加载 | 主菜单 → d 键 | 选择.2DMap 或.3DMap 文件 |
重玩 | 死亡/胜利后按y | 重置当前地图(保留配置) |
3. 暂停菜单
在进行游戏时按下空格即可暂停游戏
按键 | 功能 | 使用场景 |
---|---|---|
0 | 直接退出游戏 | 紧急退出 |
1 | 保存进度并退出 | 临时中断时保留成果 |
其他 | 返回游戏 | 观察环境后继续 |
四、进阶技巧
-
动态刺规律
- 周期 = 地图数据中的
cycle
值(如cycle=5
表示5秒一切换) - 通过多次死亡记忆关键位置刺的节奏。
- 周期 = 地图数据中的
-
3D视图联动
- 在XY视图中上升(
U
)后,立即切换YZ视图确认高度位置。
- 在XY视图中上升(
-
开发者模式
- 修改
MAP[x][y].canto
值可编辑地图(需编程基础)。
- 修改
五、常见问题解答
-
Q:游戏卡顿怎么办?
A:关闭其他程序,或调小地图尺寸(设置 → 地图大小)。 -
Q:存档文件误删如何恢复?
A:检查回收站,或重新生成同名地图(随机地图无法复原)。 -
Q:3D模式迷路怎么破?
A:频繁切换视图,注意控制台底部坐标提示。
六、联系开发者
- 反馈渠道:发送邮件至
syc20120920@163.com
- 建议格式:
问题描述:[具体操作+现象] 期望效果:[如果是建议] 设备信息:[如Windows 10/11]
掌握这些技巧,您已经超越90%的新手玩家!现在就去挑战35层超大地图吧! 🚩
游戏代码:
/*
* 抵制不良游戏,拒绝盗版游戏。
* 注意自我保护,谨防受骗上当。
* 适度游戏益脑,沉迷游戏伤身。
* 合理安排时间,享受健康生活。
*/
// 跨平台头文件兼容声明
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#define NOMINMAX
#endif
#ifdef _WIN32
#include <windows.h> // 控制台颜色与输入API
#include <conio.h> // 非阻塞式键盘输入
#endif
#include<string>
#include<fstream>
#include<cstring>
#include<iostream>
#include<vector>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<stdexcept>
#include<exception>
using namespace std;
// ---------- 全局配置 ----------
const string path = "D:\\Labyrinth_Shi"; // 地图保存文件夹固定路径
const string m2d = ".2DMap"; // 二维地图
const string m3d = ".3DMap"; // 三维地图
#define Wrong "错误!请重试\n" // 错误提示语1
#define version "1.1.4" // 版本号(为后续开发做准备)
#define Backwrong "错误!返回中\n" // 错误提示语2
#define SWlen 8 // 加载界面词条数量
const string SW[SWlen] = { // 加载界面随机提示语
"欢迎游玩小时迷宫",
"3D地图......你不晕就好!",
"小贴士:有些刺会摆烂",
"WSAD控制上下左右",
"可以向作者的163邮箱发送消息提供意见(syc20120920@163.com)",
"O(∩_∩)O哈哈~",
"准备好你的迷宫之旅了吗",
"按空格暂停游戏"
};
// ---------- 数据结构定义 ----------
struct Die { // 障碍物属性结构体
int how; // 伤害类型(0:静态障碍 / 1:动态伤害)
string way; // 障碍物名称描述
}
CD[101]; // 预设101种障碍类型(索引0未使用)
int X = 1, Y = 1; // 玩家坐标(初始位置1,1)
int X3D = 1, Y3D = 1, Z3D = 1; // 三维玩家坐标
int H = 29, W = 100; // 地图大小
int H3D = 35, W3D = 35, L3D = 35; // 三维地图大小
int Cwall = 4, Cplayer = 10, Cstab = 1, Cwin = 14; // 墙,玩家,刺,终点等的颜色(供自定义用)
struct _CTRLO {
bool flag;
string File_uffix;
};
struct _MAP { // 地图单元格属性
int canto; // 当前状态(0:可通行 / 1:障碍物)
int cycle; // 动态障碍物变化周期(0:静态)
}
MAP[38][134], // (二维)主地图(最大37行x133列,索引从1开始)
MAP3D[36][36][36], // 三维地图 (最大35x35x35,索引从1开始)
ctrlcv[101][101], // 地图剪贴板(用于游戏重玩)
ctrlcv3D[36][36][36]; // 三维地图剪贴板
// ---------- 函数声明 ----------
int GETCH(void);// GETCH;
void update3D(); // 三维动态更新
void paint3D(); // 三维地图渲染引擎
void CTRLC3D(); // 三维地图复制(类似Ctrl+C)
void CTRLV3D(); // 三维地图粘贴(类似Ctrl+V)
void GAME3D(); // 三维地图主逻辑
void randrestart3D(); // 三维随机地图生成器
_CTRLO CTRLO(); // 打开保存游戏 (包括二维和三维)
void CTRLS(const string& File_uffix); // 游戏保存本地 (包括二维和三维)
void GameStop(string File_uffix); // 游戏暂停
void MAIN(); // 游戏主循环
void ChangeMapsize(); // 切换地图大小
void toggleIME(); // 切换输入法
void printtitle(string title); // 打印自定义标题
void paint(); // 地图渲染引擎
void winnerprint(); // 胜利动画
void randrestart(); // 随机地图生成器
void Color(int ForgC, int BackC); // 控制台颜色设置
void KO(Die way); // 死亡处理及动画
void GAME1(); // 游戏主逻辑
int GetTerminalColumns();// 获取屏幕宽度
void CTRLC(); // 地图复制(类似Ctrl+C)
void CTRLV(); // 地图粘贴(类似Ctrl+V)
void WAIT(const string* SW, int len); // 加载界面动画
int Suiji(int many); // 封装随机数生成
void Changelog(); // 更新日志
void Settings(); // 设置
void Notice(); // 公告
void Howplay(int Hchose); // 玩法详解
void update(); // 动态更新
void Colorsettings(); // 颜色自定义
void CSC(string which, int& what); // 颜色自定义附属函数
// ---------- 主程序 ----------
int main() {
toggleIME(); // 将输入法改为英文
// 初始化基础障碍类型
CD[1] = { 0, "墙" }; // 索引1:静态墙壁
CD[2] = { 0, "刺" }; // 索引2:动态尖刺
srand((unsigned)time(NULL)); // 随机数种子
// 创建用来存迷宫的文件夹
bool flag = CreateDirectoryA(path.c_str(), NULL);
// 主界面循环
MAIN();
return 0;
}
// ---------- 功能实现 ----------
// getch;
int GETCH(void) {
#ifdef _MSC_VER
return _getch();
#elif defined(__MINGW32__) || defined(__MINGW64__)
return getch();
#endif
}
// 获取终端列数(Windows 实现)
int GetTerminalColumns() {
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
}
// 打印自适应标题
void printtitle(string title) {
system("cls");
int cols = GetTerminalColumns();
// 生成自适应分隔线(全屏横线)
cout << setfill('-') // 设置填充字符为 -
<< setw(cols) << "" // 输出宽度为终屏列数的空字符串(自动填充-)
<< "\n\n"; // 换两行
// 计算标题居中位置(带冒号)
title += ":"; // 添加标题后的冒号
int title_len = title.length();
int left_pad = max(0, (cols - title_len) / 2); // 防止负数
// 输出居中标题
cout << setfill(' ') // 重置填充为空格
<< setw(left_pad) << "" // 左侧填充空格
<< title // 输出标题(已包含冒号)
<< "\n\n"; // 换两行
// 再次输出分隔线
cout << setfill('-')
<< setw(cols) << ""
<< "\n\n";
}
// 控制台颜色设置(Windows API封装)
/*
值 属性
0 黑
1 蓝
2 绿
3 海蓝
4 红
5 紫红
6 黄/棕色
7 白/灰色
8 暗灰
9 亮蓝
A (十进制10) 亮绿
B (十进制11) 亮海蓝
C (十进制12) 亮红
D (十进制13) 亮紫红
E (十进制14) 亮黄/黄色
F (十进制15) 亮白
*/
void Color(int ForgC, int BackC) {
WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
}
// 封装随机数生成(范围1-many)
int Suiji(int many) {
return rand() % many + 1;
}
// 加载动画(模拟进度条+随机提示)
void WAIT(const string* SW, int len) {
system("cls"); //为了防止在其他函数中忘记清屏
int ans = 0;
Color(3, 0); // 设置青蓝色文本
int xx = rand() % len;
string s = SW[xx];
while (ans < 100) { // 进度模拟
printf("加载中......\n\n%d%%\n\n", ans);
int x = rand() % len;
if (x <= len / 10) s = SW[rand() % len]; // 随机更换提示
printf("%s", s.c_str());
Sleep(Suiji(10) * 100); // 随机延迟(100-1000ms)
ans += Suiji(20); // 随机进度增量(1-20)
system("cls");
}
}
// 游戏玩法(Hchose表示引用方式,0表示设置引用,1表示游戏引用
void Howplay(int Hchose) {
string ss;
if (Hchose == 0)ss = "返回主界面";
else if (Hchose == 1)ss = "确认";
Color(14, 0);
printtitle("游戏玩法");
printf("以下是《小时迷宫》的详细玩法指南,帮助您更好地理解游戏机制:\n\
**基础操作**\n\
- **移动控制** \n\
- **2D模式**:`W`上 `S`下 `A`左 `D`右 \n\
- **3D模式**: \n\
- 平面移动:`W`上 `S`下 `A`左 `D`右 \n\
- 垂直移动:`U`上升一层 `N`下降一层 \n\
- **视图切换**: \n\
- `X`键:显示X*Y平面(俯视图) \n\
- `Y`键:显示Y*Z平面(侧视图) \n\
- `Z`键:显示Z*X平面(前视图) \n\
- **通用功能**:`空格键`暂停游戏(可保存进度或退出)\n\
\n\
---\n\
\n\
**游戏目标**\n\
- **核心任务**:操控角色(`o`)从起点(地图左上角)移动到终点(`$`),避开所有障碍物。\n\
- **胜利条件**:到达终点即触发胜利动画。\n\
\n\
---\n\
\n\
**地图元素解析**\n\
| 符号 | 颜色 | 说明 |\n\
|------|---------------|----------------------------------------------------------------------|\n\
| `o` | 玩家自定义色 | 你的角色,初始位置在(1,1)(2D)或(1,1,1)(3D)。 |\n\
| `$` | 亮黄色 | 终点,位于地图右下角(2D)或最大坐标点(3D)。 |\n\
| `x` | 红色 | **静态墙**:触碰直接死亡。 |\n\
| `^` | 蓝色 | **动态刺(凸起)**:周期性出现,触碰时若为凸起状态则死亡。 |\n\
| `_` | 蓝色 | **动态刺(缩回)**:安全时段可通过。 |\n\
\n\
---\n\
\n\
**动态障碍机制**\n\
\n\
- **周期性变化**:动态刺(`^`和`_`)会按固定周期切换状态(如每3秒凸起→缩回)。 \n\
\n\
- **策略提示**: \n\
1. 观察刺的变化节奏,等待缩回时快速通过。 \n\
2. 3D模式中,可通过切换视图观察不同平面的刺状态。\n\
\n\
---\n\
\n\
**2D与3D模式差异**\n\
| 特性 | 2D模式 | 3D模式 |\n\
|---------------|---------------------------|-------------------------------------|\n\
| **移动维度** | 仅平面(X,Y) | 三维空间(X,Y,Z) |\n\
| **视图** | 单一平面 | 支持X*Y、Y*Z、Z*X三种视图切换 |\n\
| **难度要点** | 路径规划+动态刺躲避 | 空间导航+多平面障碍协同躲避 |\n\
\n\
---\n\
\n\
**新手技巧**\n\
1. **先熟悉2D模式**:掌握基础移动和刺的节奏后再挑战3D。\n\
2. **善用暂停**:按空格观察周围环境,规划路线。\n\
3. **颜色记忆**:牢记红色(墙)必死,蓝色(刺)需等待时机。\n\
4. **3D导航**: \n\
- 切换视图时,注意坐标提示(如`坐标:(3,5,2)`)。\n\
- 上升/下降(`U/N`)后,立刻切换视图确认位置。 \n\
\n\
---\n\
\n\
**常见问题解答**\n\
- **Q:为什么有时刺明明是缩回的,走过去还是死了?**\n\
A:是因为刺是会一直变化的,当你走到刺上时他可能刚好变成突出状态。\n\
- **Q:3D模式找不到终点怎么办?** \n\
A:终点在最大坐标(如35,35,35),通过视图切换锁定大致方向。 \n\
\n\
---\n\
\n\
**开发者建议**\n\
- 如果卡关,可在设置中调整地图尺寸(如选择10x10小地图练习)。\n\
- 自定义颜色(设置→颜色自定义)可增强视觉区分度。 \n\
\n\
---\n\
\n\
希望这份指南能让您的迷宫之旅更顺利!如果仍有疑问,欢迎通过游戏内邮箱反馈。祝您早日通关! (按任意键%s)", ss.c_str());
char Hch;
Hch = GETCH();
system("cls");
return;
}
// 胜利界面及动画
void winnerprint() {
Color(14, 0); // 黄色
printf("无敌了!!!\n");
printf(" ^^^^^^^^^^\n\
/ \\\n\
( _ _ )\n\
\\ ^ /\n\
-----\n\
| /\n\
/ |--------\n\
/ |\n\
\\ |\n\
\\ |\n\
\\ |\n\
|\n\
/ \\\n\
/ \\\n\
/ \\\n\
/ \\");
}
// 切换输入法
void toggleIME() {
// 模拟按下Shift键切换中英文(适用于微软拼音)
keybd_event(VK_SHIFT, 0, 0, 0); // 按下Shift
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); // 释放Shift
}
// 公告
void Notice() {
system("cls");
printtitle("公告");
printf("欢迎您玩小时迷宫!作者能力有限,游戏可能会有bug。\
如果您发现了bug,可以将反馈意见发送至作者163邮箱(syc20120920@163.com)\
作者在了解信息后会尽快修复,并将新版本发布。谢谢\n\n下一阶段(1.2.0)\
将完成完整的地图自定义功能,敬请期待\n\n(按任意键返回主页面)");
char Nch;
Nch = GETCH();
system("cls");
return;
}
// 死亡处理及ASCII艺术
void KO(Die way) {
system("cls");
if (way.how == 0) { // 静态障碍死亡
Color(6, 0); // 橙色
printf("你一头创死在%s上\n", (way.way).c_str());
// ASCII艺术图形
printf(" _____________\n\
( x x )\n\
\\ - /\n\
-----\n\
| / 菜就多练\n\
/ |--------\n\
/ |\n\
\\ |\n\
\\ |\n\
\\ |\n\
|\n\
/ \\\n\
/ \\\n\
/ \\\n\
/ \\");
}
}
// 加载本地地图文件
_CTRLO CTRLO() {
_CTRLO _ctrlo;
_ctrlo.File_uffix = "Nothing";
_ctrlo.flag = false;
vector < string > savedFiles; // 存储可加载的文件列表
WIN32_FIND_DATAA fileData;
HANDLE hFind = FindFirstFileA((path + "\\*").c_str(), &fileData);
// 获取存档目录下的所有文件
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
savedFiles.push_back(fileData.cFileName);
}
} while (FindNextFileA(hFind, &fileData));
FindClose(hFind);
}
// 显示加载界面
system("cls");
printtitle("加载地图");
if (savedFiles.empty()) {
printf("没有找到存档文件!\n");
Sleep(2000);
return _ctrlo;
}
// 显示文件列表
printf("可加载的地图文件:\n");
for (size_t i = 0; i < savedFiles.size(); ++i) {
printf("%2zu. %s\n", i + 1, savedFiles[i].c_str());
}
// 用户选择文件
printf("\n输入要加载的文件编号 (0取消): ");
size_t choice;
if (!(cin >> choice) || choice < 0 || choice > savedFiles.size()) {
cin.clear();
cin.ignore(numeric_limits < streamsize > ::max(), '\n');
printf("%s", Wrong);
Sleep(1000);
return _ctrlo;
}
else if (choice == 0) return _ctrlo;
// 构建完整路径
string filename = path + "\\" + savedFiles[choice - 1];
ifstream inFile(filename);
if (!inFile.is_open()) {
printf("无法打开文件: %s\n", filename.c_str());
Sleep(2000);
return _ctrlo;
}
try {
// 读取文件头
string fileType;
inFile >> fileType;
_ctrlo.File_uffix = fileType;
if (fileType == m2d) {
int savedH, savedW;
inFile >> savedH >> savedW;
// 验证地图尺寸
if (savedH < 2 || savedH > 37 || savedW < 2 || savedW > 133) {
throw runtime_error("地图尺寸非法");
}
// 读取颜色配置
int savedCwall, savedCplayer, savedCstab, savedCwin;
inFile >> savedCwall >> savedCplayer >> savedCstab >> savedCwin;
// 临时存储地图数据
vector < vector < _MAP >> tmpMap(savedH + 1, vector < _MAP >(savedW + 1));
// 读取地图内容
for (int h = 1; h <= savedH; ++h) {
for (int w = 1; w <= savedW; ++w) {
if (!(inFile >> tmpMap[h][w].canto >> tmpMap[h][w].cycle)) {
throw runtime_error("地图数据损坏");
}
// 验证数据有效性
if (tmpMap[h][w].canto < 0 || tmpMap[h][w].cycle < 0 || tmpMap[h][w].cycle > 100) {
throw runtime_error("地图数据非法");
}
}
}
// 应用加载的配置
H = savedH;
W = savedW;
Cwall = savedCwall;
Cplayer = savedCplayer;
Cstab = savedCstab;
Cwin = savedCwin;
// 复制到全局地图
for (int h = 1; h <= H; ++h) {
for (int w = 1; w <= W; ++w) {
MAP[h][w] = tmpMap[h][w];
}
}
}
else if (fileType == m3d) {
int savedH, savedW, savedL;
inFile >> savedH >> savedW >> savedL;
// 验证地图尺寸
if (savedH < 2 || savedH > 35 || savedW < 2 || savedW > 35 || savedL < 2 || savedL > 35) {
throw runtime_error("地图尺寸非法");
}
// 读取颜色配置
int savedCwall, savedCplayer, savedCstab, savedCwin;
inFile >> savedCwall >> savedCplayer >> savedCstab >> savedCwin;
// 临时存储地图数据
vector < vector < vector < _MAP > > > tmpMap(savedH + 1, vector < vector < _MAP > >(savedW + 1, vector < _MAP >(savedL + 1)));
// 读取地图内容
for (int h = 1; h <= savedH; ++h) {
for (int w = 1; w <= savedW; ++w) {
for (int l = 1; l <= savedL; ++l) {
if (!(inFile >> tmpMap[h][w][l].canto >> tmpMap[h][w][l].cycle)) {
throw runtime_error("地图数据损坏");
}
// 验证数据有效性
if (tmpMap[h][w][l].canto < 0 || tmpMap[h][w][l].cycle < 0 || tmpMap[h][w][l].cycle > 100) {
throw runtime_error("地图数据非法");
}
}
}
}
// 应用加载的配置
H3D = savedH;
W3D = savedW;
L3D = savedL;
Cwall = savedCwall;
Cplayer = savedCplayer;
Cstab = savedCstab;
Cwin = savedCwin;
// 复制到全局地图
for (int h = 1; h <= H3D; ++h) {
for (int w = 1; w <= W3D; ++w) {
for (int l = 1; l <= L3D; ++l) {
MAP3D[h][w][l] = tmpMap[h][w][l];
}
}
}
}
else throw runtime_error("文件格式不支持");
system("cls");
printf("地图加载成功!\n");
Sleep(1000);
}
catch (const exception& e) {
// 异常处理
inFile.close();
system("cls");
printf("加载失败: %s\n", e.what());
printf("按任意键返回...");
_getch();
return _ctrlo;
}
catch (...) {
cerr << "发生未知错误" << endl;
exit(1);
}
_ctrlo.flag = true;
return _ctrlo;
}
// 游戏主循环
void MAIN() {
while (1) {
Color(11, 0); // 设置初始文本颜色(亮青色)
string SSTART;
printtitle("首页");
printf("欢迎来到小时迷宫(%s)版本!选择游戏方式:\n\n a:2D随机迷宫; b:陨石模式; c:设置; d:打开已保存地图; e:3D随机迷宫 0:退出\n\n", version);
SSTART = GETCH();
system("cls");
if (SSTART == "a") { // 随机迷宫模式
randrestart(); // 生成新地图
CTRLC(); // 备份初始地图状态
Howplay(1);
//WAIT(SW, SWlen); // 加载动画
g: // 游戏循环重入点
GAME1(); // 启动游戏
// 重玩选择
printf("是否重玩?\n\ny:yes n:no\n\n");
SSTART = GETCH();
if (SSTART == "y") {
system("cls");
CTRLV(); // 恢复初始地图
goto g; // 重新进入游戏
}
}
else if (SSTART == "b") { // 预留模式
printf("本内容将在(1.5.0)版本开启");
Sleep(1000);
}
else if (SSTART == "c") {
//WAIT(SW,SWlen);
Settings();
}
else if (SSTART == "d") {
_CTRLO ctrlo_check = CTRLO();
if (ctrlo_check.flag) {
if (ctrlo_check.File_uffix == m2d) {
X = Y = 1;
CTRLC();
Howplay(1);
go: GAME1();
// 重玩选择
printf("是否重玩?\n\ny:yes n:no\n\n");
SSTART = GETCH();
if (SSTART == "y") {
system("cls");
CTRLV(); // 恢复初始地图
goto go; // 重新进入游戏
}
}
else if (ctrlo_check.File_uffix == m3d) {
X3D = Y3D = Z3D = 1;
CTRLC3D();
Howplay(1);
//WAIT(SW, SWlen);
go3D: GAME3D();
// 重玩选择
printf("是否重玩?\n\ny:yes n:no\n\n");
SSTART = GETCH();
if (SSTART == "y") {
system("cls");
CTRLV3D(); // 恢复初始地图
goto go3D; // 重新进入游戏
}
}
else {
printf("不支持的文件格式\n");
Sleep(1000);
system("cls");
}
}
}
else if (SSTART == "e") {
randrestart3D(); // 生成新地图
CTRLC3D(); // 备份初始地图状态
Howplay(1);
//WAIT(SW, SWlen); // 加载动画
g3D: // 游戏循环重入点
GAME3D(); // 启动游戏
// 重玩选择
printf("是否重玩?\n\ny:yes n:no\n\n");
SSTART = GETCH();
if (SSTART == "y") {
system("cls");
CTRLV3D(); // 恢复初始地图
goto g3D; // 重新进入游戏
}
}
else if (SSTART == "0") exit(0);
else { // 错误处理
printf("%s", Wrong);
Sleep(1000);
}
}
return;
}
// 好难!保存地图到本地
void CTRLS(const string& File_uffix) {
string mapname;
string pathway;
printtitle("保存地图到本地");
printf("输入保存文件名 (不能包含 \\/:*?\"<>|):\n\n");
getline(cin, mapname);
// 文件名合法性检查
const string illegalChars = "\\/:*?\"<>|";
for (auto& c : mapname) {
if (illegalChars.find(c) != string::npos) {
printf("错误!文件名包含非法字符\n");
Sleep(1000);
system("cls");
return;
}
}
if (mapname.empty()) {
printf("错误!文件名不能为空\n");
Sleep(1000);
system("cls");
return;
}
if (mapname.size() > 50) {
printf("错误!文件名过长(最大50字符)\n");
Sleep(1000);
system("cls");
return;
}
pathway = path + "\\" + mapname + File_uffix;
try {
// 使用C++文件流代替freopen
ofstream outFile(pathway, ios::trunc);
if (!outFile.is_open()) {
throw runtime_error("无法打开文件");
}
// 写入文件头
outFile << File_uffix << "\n";
if (File_uffix == m2d) outFile << H << " " << W << "\n";
else if (File_uffix == m3d) outFile << H3D << " " << W3D << " " << L3D << "\n";
else throw runtime_error("文件格式错误");
outFile << Cwall << " " << Cplayer << " " << Cstab << " " << Cwin << "\n";
// 写入地图数据
if (File_uffix == m2d) {
for (int h = 1; h <= H; ++h) {
for (int w = 1; w <= W; ++w) {
outFile << MAP[h][w].canto << " " << MAP[h][w].cycle;
if (w != W) outFile << " "; // 行末不加空格
}
outFile << "\n"; // 使用换行符保持跨平台兼容性
}
}
else if (File_uffix == m3d) {
for (int h = 1; h <= H3D; ++h) {
for (int w = 1; w <= W3D; ++w) {
for (int l = 1; l <= L3D; ++l) {
outFile << MAP3D[h][w][l].canto << " " << MAP3D[h][w][l].cycle;
if (l != L3D) outFile << " ";
}
outFile << "\n";
}
outFile << "\n";
}
}
// 显式关闭文件流
outFile.close();
// 验证文件完整性
ifstream inFile(pathway);
string suffix_check;
if (!(inFile >> suffix_check) || suffix_check != File_uffix) {
throw runtime_error("文件头验证失败");
}
// ...(其他验证逻辑,根据需要添加)
// 恢复控制台输出
system("cls");
printf("地图已成功保存至:\n%s\n", pathway.c_str());
Sleep(2000);
}
catch (const exception& e) {
// 确保恢复控制台输出
freopen("CON", "w", stdout);
freopen("CON", "r", stdin);
cerr << "保存失败: " << e.what() << endl;
printf("按任意键返回...");
GETCH();
system("cls");
}
catch (...) {
cerr << "发生未知错误" << endl;
exit(1);
}
}
// 切换地图大小
void ChangeMapsize() {
while (1) {
system("cls");
printf("选择地图尺寸\n\n1:(原版大地图)29:100\n\n2:(小小地图)10:10\n\n3:(小地图)20:20\n\n4:自定义\n\n【新!】5:(超大地图)37:133\n\n0:退出\n\n");
char CMSch;
CMSch = GETCH();
system("cls");
if (CMSch == '1') {
H = 29;
W = 100;
printf("地图修改成功!");
Sleep(1000);
break;
}
else if (CMSch == '2') {
H = 10;
W = 10;
printf("地图修改成功!");
Sleep(1000);
break;
}
else if (CMSch == '3') {
H = 20;
W = 20;
printf("地图修改成功!");
Sleep(1000);
break;
}
else if (CMSch == '4') {
printf("输入地图的宽度(2~37)和长度(2~133)\n\n");
int CMShch, CMSwch;
int checkCMSch = scanf("%d%d", &CMShch, &CMSwch);
if (!((CMShch < 2 || CMShch > 37) || (CMSwch < 2 || CMSwch > 133)) && checkCMSch == 2) { // 判断是否在范围内
H = CMShch;
W = CMSwch;
printf("地图修改成功!");
Sleep(1000);
break;
}
else {
printf("%s", Backwrong);
Sleep(1000);
break;
}
}
else if (CMSch == '5') {
H = 37;
W = 133;
printf("地图修改成功!");
Sleep(1000);
break;
}
else if (CMSch == '0') break;
else {
printf("%s", Wrong);
Sleep(1000);
system("cls");
}
}
return;
}
// 设置界面
void Settings() {
while (1) {
Color(10, 0);
printtitle("设置");
printf("输入选项:\n\n1:更新日志;\n2:公告;\n3:玩法详解;\n4:颜色自定义\n5:地图大小设置\n0:退出");
string SIS;
SIS = GETCH();
system("cls");
if (SIS == "1") Changelog();
else if (SIS == "2") Notice();
else if (SIS == "3") Howplay(0);
else if (SIS == "4") Colorsettings();
else if (SIS == "5") ChangeMapsize();
else if (SIS == "0") break;
else {
printf("%s", Wrong);
Sleep(1000);
system("cls");
}
}
}
// 颜色自定义附属函数
void CSC(string which, int& what) {
printf("输入%s颜色(1~15)\n", which.c_str());
int CSCch;
int checkCSCch = scanf("%d", &CSCch);
system("cls");
if (CSCch > 0 && CSCch < 16 && checkCSCch == 1) what = CSCch; // 判断是否在范围内
else {
printf("错误!");
Sleep(1000);
system("cls");
}
}
// 颜色自定义
void Colorsettings() {
while (1) {
system("cls");
printf("输入选项:\n1:自定义颜色;\n2:恢复默认;\n0:退出\n");
char Cch;
Cch = GETCH();
system("cls");
if (Cch == '1') {
CSC("玩家", Cplayer);
CSC("墙的", Cwall);
CSC("终点", Cwin);
CSC("刺的", Cstab);
break;
}
else if (Cch == '2') {
Cwall = 4;
Cplayer = 10;
Cwin = 14;
Cstab = 1;
break;
}
else if (Cch == '0') break;
else {
printf("%s", Wrong);
Sleep(1000);
system("cls");
}
}
}
// 游戏暂停
void GameStop(string File_uffix) {
system("cls");
Color(13, 0);
printtitle("游戏暂停");
printf("按0直接退出游戏,按1保存游戏状态到本地并退出,按其他键返回\n");
char GSch;
GSch = GETCH();
if (GSch == '0') exit(0);
else if (GSch == '1') CTRLS((File_uffix == m2d) ? m2d : m3d);
cerr << 0;
system("cls");
}
// 更新日志(内容取决于版本号)
void Changelog() {
system("cls");
printf("%s版本更新内容:\n\n", version);
printf("1.修复已知问题,提升系统稳定性\n\n2:提升代码兼容性\n\n3:更新游戏玩法\n\n(按任意键返回主页面)\n");
char Vch;
Vch = GETCH(); // 按任意键返回主页面
system("cls");
return;
}
// 地图状态复制(保存到剪贴板)
void CTRLC() {
for (int i = 1; i <= H; i++)
for (int j = 1; j <= W; j++)
ctrlcv[i][j] = MAP[i][j];
}
// 3D地图状态粘贴(从剪贴板恢复)
void CTRLV3D() {
for (int i = 1; i <= 35; i++)
for (int j = 1; j <= 35; j++)
for (int k = 1; k <= 35; k++)
MAP3D[i][j][k] = ctrlcv3D[i][j][k];
}
// 3D地图状态复制(保存到剪贴板)
void CTRLC3D() {
for (int i = 1; i <= 35; i++)
for (int j = 1; j <= 35; j++)
for (int k = 1; k <= 35; k++)
ctrlcv3D[i][j][k] = MAP3D[i][j][k];
}
// 地图状态粘贴(从剪贴板恢复)
void CTRLV() {
for (int i = 1; i <= H; i++)
for (int j = 1; j <= W; j++)
MAP[i][j] = ctrlcv[i][j];
}
// 地图渲染核心
void paint() {
for (int i = 1; i <= H; i++) {
for (int j = 1; j <= W; j++) {
// 终点标识
if (i == H && j == W) {
Color(Cwin, 0);
printf("$");
}
// 玩家标识
else if (i == X && j == Y) {
Color(Cplayer, 0);
printf("o");
}
// 可通行区域
else if (MAP[i][j].canto == 0) {
if (MAP[i][j].cycle == 0) printf(" "); // 普通道路
else { // 动态障碍
Color(Cstab, 0);
printf("_");
}
}
// 障碍物区域
else {
if (MAP[i][j].cycle == 0) { // 静态障碍
Color(Cwall, 0);
printf("x");
}
else { // 动态障碍
Color(Cstab, 0);
printf("^");
}
}
}
if (i != H) cout << endl;
}
}
// 地3D图渲染核心
void paint3D(char view) {
Color(11, 0);
if (view == 'x') {
for (int i = 1; i <= H3D; i++) {
for (int j = 1; j <= W3D; j++) {
// 终点标识
if (i == H3D && j == W3D && Z3D == L3D) {
Color(Cwin, 0);
printf("$");
}
// 玩家标识
else if (i == X3D && j == Y3D) {
Color(Cplayer, 0);
printf("o");
}
// 可通行区域
else if (MAP3D[i][j][Z3D].canto == 0) {
if (MAP3D[i][j][Z3D].cycle == 0) printf(" "); // 普通道路
else { // 动态障碍
Color(Cstab, 0);
printf("_");
}
}
// 障碍物区域
else {
if (MAP3D[i][j][Z3D].cycle == 0) { // 静态障碍
Color(Cwall, 0);
printf("x");
}
else { // 动态障碍
Color(Cstab, 0);
printf("^");
}
}
}
if (i != H3D) cout << endl;
}
cout << "目前视图:x*y 坐标:(" << X3D << "," << Y3D << "," << Z3D << ")";
}
else if (view == 'y') {
for (int i = 1; i <= W3D; i++) {
for (int j = 1; j <= L3D; j++) {
// 终点标识
if (i == W3D && j == L3D && X3D == H3D) {
Color(Cwin, 0);
printf("$");
}
// 玩家标识
else if (i == Y3D && j == Z3D) {
Color(Cplayer, 0);
printf("o");
}
// 可通行区域
else if (MAP3D[X3D][i][j].canto == 0) {
if (MAP3D[X3D][i][j].cycle == 0) printf(" "); // 普通道路
else { // 动态障碍
Color(Cstab, 0);
printf("_");
}
}
// 障碍物区域
else {
if (MAP3D[X3D][i][j].cycle == 0) { // 静态障碍
Color(Cwall, 0);
printf("x");
}
else { // 动态障碍
Color(Cstab, 0);
printf("^");
}
}
}
if (i != W3D) cout << endl;
}
cout << "目前视图:y*z 坐标:(" << X3D << "," << Y3D << "," << Z3D << ")";
}
else {
for (int i = 1; i <= L3D; i++) {
for (int j = 1; j <= H3D; j++) {
// 终点标识
if (i == L3D && j == H3D && Y3D == W3D) {
Color(Cwin, 0);
printf("$");
}
// 玩家标识
else if (i == Z3D && j == X3D) {
Color(Cplayer, 0);
printf("o");
}
// 可通行区域
else if (MAP3D[j][Y3D][i].canto == 0) {
if (MAP3D[j][Y3D][i].cycle == 0) printf(" "); // 普通道路
else { // 动态障碍
Color(Cstab, 0);
printf("_");
}
}
// 障碍物区域
else {
if (MAP3D[j][Y3D][i].cycle == 0) { // 静态障碍
Color(Cwall, 0);
printf("x");
}
else { // 动态障碍
Color(Cstab, 0);
printf("^");
}
}
}
if (i != L3D) cout << endl;
}
cout << "目前视图:z*x 坐标:(" << X3D << "," << Y3D << "," << Z3D << ")";
}
}
// 动态元素更新
void update() {
for (int updatei = 1; updatei <= H; updatei++) {
for (int updatej = 1; updatej <= W; updatej++) {
if (MAP[updatei][updatej].cycle != 0) {
MAP[updatei][updatej].canto++;
MAP[updatei][updatej].canto %= MAP[updatei][updatej].cycle; // 周期性切换状态
}
}
}
}
// 3D动态元素更新
void update3D() {
for (int update3Di = 1; update3Di <= H3D; update3Di++) {
for (int update3Dj = 1; update3Dj <= W3D; update3Dj++) {
for (int update3Dk = 1; update3Dk <= L3D; update3Dk++) {
if (MAP3D[update3Di][update3Dj][update3Dk].cycle != 0) {
MAP3D[update3Di][update3Dj][update3Dk].canto++;
MAP3D[update3Di][update3Dj][update3Dk].canto %= MAP3D[update3Di][update3Dj][update3Dk].cycle; // 周期性切换状态
}
}
}
}
}
// 随机地图生成算法
void randrestart() {
for (int i = 1; i <= H; i++) {
for (int j = 1; j <= W; j++) {
// 保留起点和终点
if (!((i == X && j == Y) || (i == H && j == W))) {
int flag1 = rand() % 2, flag2 = rand() % 2;
MAP[i][j].canto = (flag1 && flag2); // 25%概率生成障碍
// 动态障碍生成逻辑
if (MAP[i][j].canto == 1) {
int flagt = rand() % 6; // 16.7%概率变为动态
if (flagt == 1) {
int tf = rand() % 6 + 1; // 变化周期1-6
MAP[i][j].cycle = tf;
MAP[i][j].canto = tf / 2; // 初始相位
}
else {
MAP[i][j].cycle = 0;
}
}
}
if (!((i != X || j != Y) && (i != H || j != W))) MAP[i][j].canto = 0;
}
}
}
// 随机3D地图生成算法
void randrestart3D() {
for (int i = 1; i <= H3D; i++) {
for (int j = 1; j <= W3D; j++) {
for (int k = 1; k <= L3D; k++) {
// 保留起点和终点
if (!((i == X3D && j == Y3D && k == Z3D) || (i == H3D && j == W3D && k == L3D))) {
int flag1 = rand() % 2, flag2 = rand() % 2;
MAP3D[i][j][k].canto = (flag1 && flag2); // 25%概率生成障碍
// 动态障碍生成逻辑
if (MAP3D[i][j][k].canto == 1) {
int flagt = rand() % 6; // 16.7%概率变为动态
if (flagt == 1) {
int tf = rand() % 6 + 1; // 变化周期1-6
MAP3D[i][j][k].cycle = tf;
MAP3D[i][j][k].canto = tf / 2; // 初始相位
}
else {
MAP3D[i][j][k].cycle = 0;
}
}
}
if (!((i != X3D || j != Y3D || k != Z3D) && (i != H3D || j != W3D || k != L3D))) MAP3D[i][j][k].canto = 0;
}
}
}
}
// 游戏主循环
void GAME1() {
char ch; // 用于判断上下左右
X = 1;
Y = 1; // 重置玩家位置
while (1) {
// 胜利条件检测(终点在H行W列)
if (X == H && Y == W) { // 注意:终点坐标可能需要调整
winnerprint();
break;
}
paint(); // 渲染当前帧
update(); // 动态元素更新
ch = GETCH(); // 获取键盘输入
// 移动处理与碰撞检测
if (ch == 'w') { // 上移
X--;
if (!(MAP[X][Y].canto == 0 && X != 0)) {
KO(MAP[X][Y].cycle == 0 ? CD[1] : CD[2]); // 根据障碍类型选择反馈
break;
}
}
// 其他方向处理同理(略)
else if (ch == 'd') {
Y++;
if (!(MAP[X][Y].canto == 0 && Y != W + 1)) {
KO(MAP[X][Y].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == 's') {
X++;
if (!(MAP[X][Y].canto == 0 && X != H + 1)) {
KO(MAP[X][Y].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == 'a') {
Y--;
if (!(MAP[X][Y].canto == 0 && Y != 0)) {
KO(MAP[X][Y].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == ' ') {
GameStop(m2d); // 游戏暂停
}
system("cls");
}
return;
}
// 游戏3D主循环
void GAME3D() {
char ch; // 用于判断上下左右
X3D = 1;
Y3D = 1;
Z3D = 1; // 重置玩家位置
char view = 'x';
while (1) {
// 胜利条件检测(终点在H3D行W3D列L3D层)
if (X3D == H3D && Y3D == W3D && Z3D == L3D) { // 注意:终点坐标可能需要调整
winnerprint();
break;
}
paint3D(view); // 渲染当前帧
update3D(); // 动态元素更新
ch = GETCH(); // 获取键盘输入
// 视图切换
if (ch == 'x' || ch == 'y' || ch == 'z') {
view = ch;
}
// 移动处理与碰撞检测
else if (ch == 'u') { // 上层
Z3D++;
if (!(MAP3D[X3D][Y3D][Z3D].canto == 0 && Z3D != L3D + 1)) {
KO(MAP3D[X3D][Y3D][Z3D].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == 'n') { // 下层
Z3D--;
if (!(MAP3D[X3D][Y3D][Z3D].canto == 0 && Z3D != 0)) {
KO(MAP3D[X3D][Y3D][Z3D].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == 'w') { // 上移
X3D--;
if (!(MAP3D[X3D][Y3D][Z3D].canto == 0 && X3D != 0)) {
KO(MAP3D[X3D][Y3D][Z3D].cycle == 0 ? CD[1] : CD[2]); // 根据障碍类型选择反馈
break;
}
}
// 其他方向处理同理(略)
else if (ch == 'd') {
Y3D++;
if (!(MAP3D[X3D][Y3D][Z3D].canto == 0 && Y3D != W3D + 1)) {
KO(MAP3D[X3D][Y3D][Z3D].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == 's') {
X3D++;
if (!(MAP3D[X3D][Y3D][Z3D].canto == 0 && X3D != H3D + 1)) {
KO(MAP3D[X3D][Y3D][Z3D].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == 'a') {
Y3D--;
if (!(MAP3D[X3D][Y3D][Z3D].canto == 0 && Y3D != 0)) {
KO(MAP3D[X3D][Y3D][Z3D].cycle == 0 ? CD[1] : CD[2]);
break;
}
}
else if (ch == ' ') {
GameStop(m3d); // 游戏暂停
}
system("cls");
}
return;
}
总结
祝大家玩得开心!