人们总是对未知充满好奇,迫使他们满怀热情去求知,去解答。对于游戏也应如此,想让玩家对游戏满怀热情,玩游戏时不会感觉太无聊,我认为最重要的就是能够让玩家时刻对游戏接下来发生的事充满期待,激发玩家的好奇心。这对游戏自身的玩法性充满挑战。
优秀的画质,耐人寻味的剧情,题材新颖,有趣的游戏玩法等等都是一款优秀的游戏所不可或缺的。
迷宫,因为其复杂性和不可预知性让一大批人深深为之着迷。对于迷宫的解释,百度百科上是这样说的:
迷宫 指的是充满复杂通道,很难找到从其内部到达入口或从入口到达中心的道路,道路复杂难辨,人进去不容易出来的建筑物。通常比喻复杂艰深的问题或难以捉摸的局面。
所以说,在游戏中,迷宫能够提高游戏的玩法性和趣味性,玩家在迷宫中运用自己的智慧找到出口,成就感瞬间爆棚,也就更想要继续玩下去。
迷宫玩法,通常在解谜冒险类游戏中出现,其他类型的游戏也有一定的涉及,如果再在迷宫中加入一些随机事件,相信游戏的随机性和趣味性也会大大提高。
正是因为这么多的原因,作为游戏开发者,更应该学习开发迷宫玩法,其中迷宫生成算法必不可少。
经典的迷宫生成算法有四种:递归回溯算法,递归分割算法,随机Prim算法,Kruskal+并查集。关于详细介绍,许多大佬的博客解释的很清晰,这里不再赘述,作者选了一种生成的迷宫比较自然的随机Prim算法。
算法见解
下面是个人对算法的一些小见解
前提:算法考虑的均是方形迷宫
迷宫生成的基本流程是
1.先生成一个由有限个周围四面均是墙的封闭区域组成的方形大区域,例如5×5的迷宫就是由25个这种封闭区域组成的。
2.开始消除迷宫中间的部分墙壁(边框除外),只需保证迷宫内任意相邻两区域是互通的,这样就可以推出迷宫内任意两区域都是互通的。有了这个保障,迷宫的出口和入口就可以在四个边框上随意指定位置,不会出现无解的迷宫,也增加了生成迷宫的随机性。同时,让迷宫中的每一块区域充分利用,不会出现某一块区域永远无法到达的情况。
了解流程之后,首先就要考虑迷宫的存储方式,一种方式是用二维数组存储,例如用数字0代表墙壁,数字1代表道路就像这样:
int[,] maze = {
{
0,1,0,0,0}
,{
0,1,1,0,0}
,{
0,0,1,1,0}
,{
0,0,0,1,1}
,{
0,0,0,0,0}
};
还有一种方式是用两个二维数组,适合墙壁没有厚度或者厚度很小的迷宫,一个存储所有行的墙壁(类似横着的线)信息,一个存储所有列的墙壁(类似竖着的线)信息,数字0代表没有墙壁,数字1代表墙壁存在,也可以用bool变量表示。
作者在这里选用第二种,因为和算法结合性较好。
随机Prim算法描述
1.在初始生成的全区域封闭迷宫中随机选择一个区域作为当前区域
2.将区域四周未消除的墙加入列表中
3.循环执行以下方法,直至列表为空
随机从列表选择一面墙
如果墙两边区域存在一区域未被连通,就消除这面墙,并将这面墙两边区域附近未消除的墙加入列表(迷宫边框的墙壁除外)
从列表中移除这面墙
4.随机选取迷宫边框上的两个墙壁分别作为出口和入口(出口和入口可能会非常接近)
了解了原理,接下来就是在Unity实现,先看效果图
代码实现
首先定义一个迷宫类
public class MazeWall
{
//true表示墙壁存在,false表示墙壁不存在
public bool[,] rowWall;//存储迷宫所有行的墙壁信息
public bool[,] colWall;//存储迷宫所有列的墙壁信息
public int rowsum;//迷宫有多少行
public int colsum;//迷宫有多少列
/// <summary>
/// 判断区域是否连通,四面墙有一面墙打通即为连通
/// </summary>
/// <param name="rowindex"></param>
/// <param name="colindex"></param>
/// <returns></returns>
public bool this[int rowindex, int colindex]
{
get
{
//检查是否越界
if (rowindex >= rowsum || colindex >= colsum)
Debug.LogError("越界");
if (rowindex < 0 || colindex < 0)
Debug.LogError("越界");
//有一面墙不存在即为连通
return !(rowWall[rowindex, colindex] && rowWall[rowindex+1, colindex ] &&
colWall[rowindex, colindex] && colWall[rowindex, colindex + 1]);
}
}
//构造函数,初始化迷宫信息,
public MazeWall(int a,int b)
{
rowsum = a;
colsum = b;
rowWall =