当眼瞎的你走进昏暗的迷宫时……
当然不是眼瞎啦……
声明
保证 GenAI 在文章内无贡献。
保证作者在代码等内的贡献远大于 GenAI。
GenAI 贡献:
将 PDF 一个矩阵内的所有数字提取成二位数组。
一个一个字手搓的,看完点个赞再走吧 qwq
前言
发现现有的迷宫小游戏基本都是这样的:
或是这样的:
前者可以看到全图,相当于上帝模式,不好玩。
后者虽然只能看到周围,但也不真实,如可以看到墙对面。
而现实中的迷宫……
无法像前两种那样透视,或拥有上帝视角。
所以我尝试制作一个更真实的迷宫游戏。
Step1:全视野
更简单,更好玩!
做出的第一个版本,后面的版本都是由此版本修改而来
机制
这里先介绍机制,不(太)涉及游戏内容,但可以不建议跳过
格子
每个格子都是以下类型之一:
- 空地:白色,可以通行。
- 起点:蓝色。
- 终点:绿色。
- 墙:深灰,不可通行,会阻挡视线。
- 迷雾:灰色,非格子类型,是显示时用来表示看不到的。
- 玩家:红色,非格子类型,是玩家位置,在视野中心。
视野机制
在昏暗的迷宫中,你无法看到比较远的地方所以视野上限设为
显示时无法看到所在位置,只能看到周围情况。
被看见
站在当前点时到目标点的视线没有被完全阻挡。
- 看不见:连目标的一个小角都看不见。可能是视线被墙阻挡或在视野范围之外。显示为迷雾。
- 看得见:能看到一个小角就算看见,显示真实样貌。
红圈
就是编号为
显然一定可以看见。
橙圈
就是编号为
如果它相邻的一或两个红格子中有至少一个不是墙,就可以被看见。
如
如
黄圈
相对复杂。
- 在整轴上的点:即
13 ,16 ,19 ,22 。若前面前面的两个都不是墙,就能被看到。 - 侧面的点:即
13 到24 中的其他点。可能阻挡他们的点分为以下两组,若两组中任意一组为空,则这个点可以被看到。- 整轴点:它旁边的两个整轴点。如
18 号旁边的整轴点有3 号和9 号。若这两点都不是墙,则这组为空。 - 侧点:和它相邻的另一点。如
18 号的侧点是8 号点。若这个点不是墙,则这组为空。
- 整轴点:它旁边的两个整轴点。如
效果
地图
最外圈是围墙,地图中有一个起点,一个终点,和若干墙与空地。
示例:
游戏内容
玩法
基础迷宫,用
墙无法穿过。
到达终点就算结束。
内置一个练手小地图(就是上面那个)。
可以自制地图,详见代码部分。
代码
代码不是最终版,所以暂时不做解释。
:::success[代码]
#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>
using namespace std;
long long sfyh[25]={0,0,1,0,-1,0,1,2,1,0,-1,-2,-1,0,1,2,3,2,1,0,-1,-2,-3,-2,-1};
long long sfyl[25]={0,1,0,-1,0,2,1,0,-1,-2,-1,0,1,3,2,1,0,-1,-2,-3,-2,-1,0,1,2};
long long sfmx[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,3,0,0,4,0,0};
long long sfmy[25]={0,0,0,0,0,1,0,2,0,3,0,4,0,5,0,0,7,0,0,9,0,0,11,0,0};
long long sfox[25]={0,0,0,0,0,0,1,0,2,0,3,0,1,1,6,6,2,8,8,3,10,10,4,12,12};
long long sfoy[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,2,3,0,3,4,0,4,1};
long long sfoz[25]={0,0,0,0,0,1,2,2,3,3,4,4,4,5,5,7,7,7,9,9,9,11,11,11,5};
long long sfwz[8][8]={
{-1,-1,-1,-1,-1,-1,-1,-1},
{-1,-1,-1,-1,22,-1,-1,-1},
{-1,-1,-1,21,11,23,-1,-1},
{-1,-1,20,10, 4,12,24,-1},
{-1,19, 9, 3, 0, 1, 5,13},
{-1,-1,18, 8, 2, 6,14,-1},
{-1,-1,-1,17, 7,15,-1,-1},
{-1,-1,-1,-1,16,-1,-1,-1}
};
long long mymp[14][14]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,1,1,1,1,0,1,0,1,0,1,0},
{0,1,0,2,1,0,0,0,1,0,1,0,1,0},
{0,1,0,1,1,0,1,1,1,1,1,0,1,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0},
{0,1,1,1,1,1,1,0,1,0,1,1,1,0},
{0,1,0,0,3,1,1,0,1,0,0,0,1,0},
{0,1,0,1,1,1,0,0,0,0,1,0,1,0},
{0,1,0,1,0,1,1,1,1,0,1,0,1,0},
{0,1,0,0,0,0,0,0,0,0,1,0,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
void Color(long long a)
{
if(a==-1)SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),112); //迷雾:灰
if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),240); //路段:白
if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),128); //墙体:灰
if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),144); //入口:蓝
if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),160); //出口:绿
if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),192); //人物:红
if(a==9) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7); //重置:黑
}
bool icse[25];
bool checkn(long long h,long long l,long long x)
{
long long nh=h+sfyh[x],nl=l+sfyl[x];
if(icse[x]==false || mymp[nh][nl]==1)
{
return true;
}
return false;
}
void drawmym(long long h,long long l)
{
long long x,nh,nl;
icse[0]=true;
for(long long i=1;i<25;i++)
{
icse[i]=true;
nh=h+sfyh[i];
nl=l+sfyl[i];
if(checkn(h,l,sfmx[i])==true || checkn(h,l,sfmy[i])==true || (checkn(h,l,sfox[i])==true && (checkn(h,l,sfoy[i])==true || checkn(h,l,sfoz[i])==true)))
{
icse[i]=false;
}
}
for(long long i=-3;i<=3;i++)
{
for(long long j=-3;j<=3;j++)
{
nh=h+i;
nl=l+j;
x=sfwz[i+4][j+4];
if(x==-1 || icse[x]==false)
{
Color(-1);
cout<<" ";
}else if(x==0)
{
Color(5);
cout<<" ";
}else
{
x=mymp[nh][nl];
Color(x);
cout<<" ";
}
}
Color(9);
cout<<endl;
}
return;
}
int main()
{
long long h=4,l=3,nh,nl,zh=8,zl=4;
char ch;
drawmym(h,l);
while(true)
{
if(h==zh && l==zl)
{
cout<<"You Win!";
return 0;
}
ch=getch();
nh=h;
nl=l;
if(ch=='w' || ch=='W')
{
nh=h-1;
nl=l;
}
if(ch=='a' || ch=='A')
{
nh=h;
nl=l-1;
}
if(ch=='s' || ch=='S')
{
nh=h+1;
nl=l;
}
if(ch=='d' || ch=='D')
{
nh=h;
nl=l+1;
}
if(mymp[nh][nl]==1)
{
continue;
}
system("cls");
h=nh;
l=nl;
drawmym(h,l);
}
return 0;
}
:::
Step2:单边视野
更复杂,更真实!
Step
原因很简单:在你面向前方时,无法看到后面的场景。在迷宫里,你也无法确定你面向那个方向。
机制
只介绍更改或增加的部分。
视野机制
还是这张图:
新增朝向,初始时默认向正前(即图里的上)。
面向前方时,你只能看到编号为
即,可以看到图里的前
新增转向,具体方法详见操作。
面对左边时,只能看到左边的
即
向右和向后同理。
难度
分为三档,分别是:
- Easy,指简单。视野上限为
3 格,即可看见机制中给出的视野图中的黄圈和以内格子。 - Normal,指普通。视野上限为
2 格,即可看见机制中给出的视野图中的橙圈和以内格子。 - Hard,指困难。视野上限为
1 格,即可看见机制中给出的视野图中的黄红圈和以内格子。
游戏内容
操作
用
用
到达终点就算结束。
难度
开始是可以选择难度,用
详见机制和代码部分。
代码
没有单独写的代码,直接看最终代码部分。
代码
由于 Step
:::success[代码]
#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>
using namespace std;
long long yh[5]={0,-1,0,1,0},yl[5]={0,0,-1,0,1};
long long sfyh[25]={0,0,1,0,-1,0,1,2,1,0,-1,-2,-1,0,1,2,3,2,1,0,-1,-2,-3,-2,-1};
long long sfyl[25]={0,1,0,-1,0,2,1,0,-1,-2,-1,0,1,3,2,1,0,-1,-2,-3,-2,-1,0,1,2};
long long sfmx[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,3,0,0,4,0,0};
long long sfmy[25]={0,0,0,0,0,1,0,2,0,3,0,4,0,5,0,0,7,0,0,9,0,0,11,0,0};
long long sfox[25]={0,0,0,0,0,0,1,0,2,0,3,0,1,1,6,6,2,8,8,3,10,10,4,12,12};
long long sfoy[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,2,3,0,3,4,0,4,1};
long long sfoz[25]={0,0,0,0,0,1,2,2,3,3,4,4,4,5,5,7,7,7,9,9,9,11,11,11,5};
long long sfwz[8][8]={
{-1,-1,-1,-1,-1,-1,-1,-1},
{-1,-1,-1,-1,22,-1,-1,-1},
{-1,-1,-1,21,11,23,-1,-1},
{-1,-1,20,10, 4,12,24,-1},
{-1,19, 9, 3, 0, 1, 5,13},
{-1,-1,18, 8, 2, 6,14,-1},
{-1,-1,-1,17, 7,15,-1,-1},
{-1,-1,-1,-1,16,-1,-1,-1}
};
long long mymp[14][14]={ //起点:4 3 终点:8 4
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,1,1,1,1,0,1,0,1,0,1,0},
{0,1,0,2,1,0,0,0,1,0,1,0,1,0},
{0,1,0,1,1,0,1,1,1,1,1,0,1,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0},
{0,1,1,1,1,1,1,0,1,0,1,1,1,0},
{0,1,0,0,3,1,1,0,1,0,0,0,1,0},
{0,1,0,1,1,1,0,0,0,0,1,0,1,0},
{0,1,0,1,0,1,1,1,1,0,1,0,1,0},
{0,1,0,0,0,0,0,0,0,0,1,0,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
void Color(long long a)
{
if(a==-1)SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),112); //迷雾:灰
if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),240); //路段:白
if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),128); //墙体:灰
if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),144); //入口:蓝
if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),160); //出口:绿 注意:如果改变了,移动成功后底部的颜色条也会改变,不建议修改
if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),192); //人物:红 注意:如果改变了,移动失败后底部的颜色条也会改变,不建议修改
if(a==9) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7); //重置:黑
}
bool icse[25];
bool checkn(long long h,long long l,long long x)
{
long long nh=h+sfyh[x],nl=l+sfyl[x];
if(icse[x]==false || mymp[nh][nl]==1)
{
return true;
}
return false;
}
long long dif=25,k=3;
void wdif()
{
cout<<"Your difficulty : ";
if(k==1)
{
cout<<"Hard\n";
}else if(k==2)
{
cout<<"Normal\n";
}else if(k==3)
{
cout<<"Easy\n";
}
cout<<"View size : "<<k+1<<endl;
return;
}
void drawfront(long long h,long long l) //f==1 前
{
long long nh,nl,x;
for(long long i=-k;i<=0;i++)
{
for(long long j=-k;j<=k;j++)
{
nh=h+i;
nl=l+j;
x=sfwz[i+4][j+4];
if(x==-1 || x>=dif)
{
Color(9);
cout<<" ";
}else if(icse[x]==false)
{
Color(-1);
cout<<" ";
}else if(x==0)
{
Color(5);
cout<<" ";
}else
{
x=mymp[nh][nl];
Color(x);
cout<<" ";
}
}
Color(9);
cout<<endl;
}
return;
}
void drawleft(long long h,long long l) //f==2 左
{
long long nh,nl,x;
for(long long i=-k;i<=0;i++)
{
for(long long j=k;j>=-k;j--)
{
nh=h+j;
nl=l+i;
x=sfwz[j+4][i+4];
if(x==-1 || x>=dif)
{
Color(9);
cout<<" ";
}else if(icse[x]==false)
{
Color(-1);
cout<<" ";
}else if(x==0)
{
Color(5);
cout<<" ";
}else
{
x=mymp[nh][nl];
Color(x);
cout<<" ";
}
}
Color(9);
cout<<endl;
}
return;
}
void drawback(long long h,long long l) //f==3 后
{
long long nh,nl,x;
for(long long i=k;i>=0;i--)
{
for(long long j=k;j>=-k;j--)
{
nh=h+i;
nl=l+j;
x=sfwz[i+4][j+4];
if(x==-1 || x>=dif)
{
Color(9);
cout<<" ";
}else if(icse[x]==false)
{
Color(-1);
cout<<" ";
}else if(x==0)
{
Color(5);
cout<<" ";
}else
{
x=mymp[nh][nl];
Color(x);
cout<<" ";
}
}
Color(9);
cout<<endl;
}
return;
}
void drawright(long long h,long long l) //f==4 右
{
long long nh,nl,x;
for(long long i=k;i>=0;i--)
{
for(long long j=-k;j<=k;j++)
{
nh=h+j;
nl=l+i;
x=sfwz[j+4][i+4];
if(x==-1 || x>=dif)
{
Color(9);
cout<<" ";
}else if(icse[x]==false)
{
Color(-1);
cout<<" ";
}else if(x==0)
{
Color(5);
cout<<" ";
}else
{
x=mymp[nh][nl];
Color(x);
cout<<" ";
}
}
Color(9);
cout<<endl;
}
return;
}
void drawmymft(long long h,long long l,long long f)
{
long long x,nh,nl;
wdif();
icse[0]=true;
for(long long i=1;i<dif;i++)
{
icse[i]=true;
nh=h+sfyh[i];
nl=l+sfyl[i];
if(checkn(h,l,sfmx[i])==true || checkn(h,l,sfmy[i])==true || (checkn(h,l,sfox[i])==true && (checkn(h,l,sfoy[i])==true || checkn(h,l,sfoz[i])==true)))
{
icse[i]=false;
}
}
if(f==1)
{
drawfront(h,l);
}else if(f==2)
{
drawleft(h,l);
}else if(f==3)
{
drawback(h,l);
}else if(f==4)
{
drawright(h,l);
}
return;
}
void drawmym(long long h,long long l)
{
long long x,nh,nl;
wdif();
icse[0]=true;
for(long long i=1;i<dif;i++)
{
icse[i]=true;
nh=h+sfyh[i];
nl=l+sfyl[i];
if(checkn(h,l,sfmx[i])==true || checkn(h,l,sfmy[i])==true || (checkn(h,l,sfox[i])==true && (checkn(h,l,sfoy[i])==true || checkn(h,l,sfoz[i])==true)))
{
icse[i]=false;
}
}
for(long long i=-k;i<=k;i++)
{
for(long long j=-k;j<=k;j++)
{
nh=h+i;
nl=l+j;
x=sfwz[i+4][j+4];
if(x==-1 || icse[x]==false || x>=dif)
{
Color(-1);
cout<<" ";
}else if(x==0)
{
Color(5);
cout<<" ";
}else
{
x=mymp[nh][nl];
Color(x);
cout<<" ";
}
}
Color(9);
cout<<endl;
}
return;
}
long long ftfront(long long ft)
{
return ft;
}
long long ftleft(long long ft)
{
ft%=4;
ft++;
return ft;
}
long long ftback(long long ft)
{
ft+=2;
if(ft>4)
{
ft-=4;
}
return ft;
}
long long ftright(long long ft)
{
ft--;
if(ft==0)
{
ft=4;
}
return ft;
}
int main()
{
long long h=4,l=3,f=1,nh,nl,zh=8,zl=4;
char ch;
bool canw,vf=true;
cout<<"Select view :\n A.All B.One side\n";
ch=getch();
if(ch=='a' || ch=='A')
{
vf=false;
}
system("cls");
cout<<"Select Difficulty :\n A.Easy B.Normal C.Hard\n";
ch=getch();
if(ch=='a' || ch=='A')
{
dif=25;
k=3;
}else if(ch=='b' || ch=='B')
{
dif=13;
k=2;
}else if(ch=='c' || ch=='C')
{
dif=5;
k=1;
}
system("cls");
if(vf==true)
{
drawmymft(h,l,f);
}else
{
drawmym(h,l);
}
while(true)
{
if(h==zh && l==zl)
{
cout<<"You Win!";
return 0;
}
ch=getch();
nh=h;
nl=l;
if(ch=='w' || ch=='W')
{
nh+=yh[ftfront(f)];
nl+=yl[ftfront(f)];
}
if(ch=='a' || ch=='A')
{
nh+=yh[ftleft(f)];
nl+=yl[ftleft(f)];
}
if(ch=='s' || ch=='S')
{
nh+=yh[ftback(f)];
nl+=yl[ftback(f)];
}
if(ch=='d' || ch=='D')
{
nh+=yh[ftright(f)];
nl+=yl[ftright(f)];
}
if(vf==true && (ch=='f' || ch=='F'))
{
f=ftfront(f);
}
if(vf==true && (ch=='l' || ch=='L'))
{
f=ftleft(f);
}
if(vf==true && (ch=='b' || ch=='B'))
{
f=ftback(f);
}
if(vf==true && (ch=='r' || ch=='R'))
{
f=ftright(f);
}
canw=false;
if(mymp[nh][nl]!=1)
{
canw=true;
h=nh;
l=nl;
}
system("cls");
if(vf==true)
{
drawmymft(h,l,f);
}else
{
drawmym(h,l);
}
if(canw==true)
{
cout<<"Action successful : Yes\n";
Color(3);
cout<<" \n";
Color(9);
}else
{
cout<<"Action successful : No\n";
Color(5);
cout<<" \n";
Color(9);
}
}
return 0;
}
:::
玩法
开始时按
全视野模式也加入了难度,详见 Step
在显示的地图下面会显示一个颜色条(初始没有),若当前移动后会撞墙(即此次移动失败),颜色为红,否则为绿。
地图
代码内置的联手小地图:
自定义
显示颜色,迷宫地图等都支持自定义。
颜色
:::info[设置颜色的代码片段]
void Color(long long a)
{
if(a==-1)SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),112); //迷雾:灰
if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),240); //路段:白
if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),128); //墙体:灰
if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),144); //入口:蓝
if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),160); //出口:绿 注意:如果改变了,移动成功后底部的颜色条也会改变,不建议修改
if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),192); //人物:红 注意:如果改变了,移动失败后底部的颜色条也会改变,不建议修改
if(a==9) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7); //重置:黑
}
:::
每行代表的内容在注释里。
修改方法
颜色数字对应表
在下面的部分找到需要的颜色,替换代码需要修改的行最后面的数字。
每行颜色一样。
地图
:::info[设置地图的代码片段]
long long mymp[14][14]={ //起点:4 3 终点:8 4
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,1,1,1,1,0,1,0,1,0,1,0},
{0,1,0,2,1,0,0,0,1,0,1,0,1,0},
{0,1,0,1,1,0,1,1,1,1,1,0,1,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0},
{0,1,1,1,1,1,1,0,1,0,1,1,1,0},
{0,1,0,0,3,1,1,0,1,0,0,0,1,0},
{0,1,0,1,1,1,0,0,0,0,1,0,1,0},
{0,1,0,1,0,1,1,1,1,0,1,0,1,0},
{0,1,0,0,0,0,0,0,0,0,1,0,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
:::
修改方式
墙为
将数字大小设为迷宫行数加一和列数加一。
第
地图最外圈需为墙,即
起点终点在 main 函数下的第一行修改。
其中 h 和 l 是起点的地图下标,zh 和 zl 是终点的地图下标。
挑战
注意到代码里的地图很小,但这并不意味着作者懒得做地图,因为大地图在这里等着你!
这里作者发布一个挑战,在锁定单边视野的 Easy 难度的情况下通关大地图。在还没有人通关的情况下,大地图不会公开。
大地图挑战 exe 下载
这里的 exe 就是将代码中的地图设为大地图后运行出的 exe。
通关后会得到通关代码,将代码发送给作者视为通关。
有人通关后,带大地图的完整代码和地图将在地图合集展示。
第一个通关的人可以获得作者小号的两个关注。快去试试吧。
警告:请勿用不正当的手段得到代码。
鸣谢
感谢首席体验官 @returnzheng,关注他谢谢喵(returnzheng 说的)
感谢帮忙调整大迷宫地图的 @happy12313,关注他谢谢喵(YLXxxx 说的)
感谢帮忙调格式的 @Shellchen,关注他谢谢喵(YLXxxx 说的)
终于码完了,如果你觉得好玩,点个赞再走吧~