随机迷宫

182 阅读3分钟

灵感来源:www.bilibili.com/video/BV1tK…
视频说的很详细了,我这里就不多写什么了,建议大家去看下视频。
这里我简单列一下视频里提到了三个规则
1、只有当隔壁没有去过的格子才可以砸
2、当无墙可砸时,随机到一个去过的格子
3、所有格子都要经过

首先按照视频一开始提到的那样,创建迷宫我想到的步骤是:
1、绘制迷宫框架。
2、设置起点、终点。(其实功能做到后面发现设置终点没有意义,不过作为迷宫留个终点没毛病)
3、按照规则从起点开始砸墙。

分析规则可以得知要创建的这个格子类,需要包含 位置、状态、存留的线,下面是创建的格子类。

public class MIGONGModel
{
    private readonly int RowIndex;
    private readonly int ColumnIndex;
    public MIGONGModel(int rowindex, int columnindex)
    {
        this.RowIndex = rowindex;
        this.ColumnIndex = columnindex;
        this.IsPass = false;
        this.IsStart = false;
        this.IsEnd = false;
        this.BorderLine = new Dictionary<string, Entity>();
    }
    /// <summary>
    /// 当前的格子位置y, x
    /// </summary>
    public Tuple<int, int> CurrentCol
    {
        get
        {
            return new Tuple<int, int>(this.RowIndex, this.ColumnIndex);
        }
    }
    /// <summary>
    /// 相邻的格子线 上下左右
    /// </summary>
    public Dictionary<string, Entity> BorderLine { set; get; }

    /// <summary>
    /// 是否经过
    /// </summary>
    public bool IsPass { set; get; }
    /// <summary>
    /// 是否出口
    /// </summary>
    public bool IsEnd { set; get; }
    /// <summary>
    /// 是否起点
    /// </summary>
    public bool IsStart { set; get; }
}

在步骤1的时候需要记录格子的数据信息,需要注意的是
202352-03511.jpg
上图中比如1和5,1和2之间有共用的线,如果你在绘制的时候绘制两次,那砸墙的时候也要砸两遍。
按照第一个规则,得到下一个,在当前格子周边没有经过的格子

private Dictionary<string, MIGONGModel> NextCol(MIGONGModel currentCol)
{
    int RowIndex = currentCol.CurrentCol.Item1;
    int ColumnIndex = currentCol.CurrentCol.Item2;
    Dictionary<string, MIGONGModel> temp = new Dictionary<string, MIGONGModel>();
    if (AllCols.ContainsKey(new Tuple<int, int>(RowIndex + 1, ColumnIndex)) && !AllCols[new Tuple<int, int>(RowIndex + 1, ColumnIndex)].IsPass)
    {//下
        temp.Add("bottom", AllCols[new Tuple<int, int>(RowIndex + 1, ColumnIndex)]);
    }
    if (AllCols.ContainsKey(new Tuple<int, int>(RowIndex - 1, ColumnIndex)) && !AllCols[new Tuple<int, int>(RowIndex - 1, ColumnIndex)].IsPass)
    {//上
        temp.Add("top", AllCols[new Tuple<int, int>(RowIndex - 1, ColumnIndex)]);
    }
    if (AllCols.ContainsKey(new Tuple<int, int>(RowIndex, ColumnIndex + 1)) && !AllCols[new Tuple<int, int>(RowIndex, ColumnIndex + 1)].IsPass)
    {//右
        temp.Add("right", AllCols[new Tuple<int, int>(RowIndex, ColumnIndex + 1)]);
    }
    if (AllCols.ContainsKey(new Tuple<int, int>(RowIndex, ColumnIndex - 1)) && !AllCols[new Tuple<int, int>(RowIndex, ColumnIndex - 1)].IsPass)
    {//左
        temp.Add("left", AllCols[new Tuple<int, int>(RowIndex, ColumnIndex - 1)]);
    }
    return temp;
}

如果按照规则1在周边已经找不到可以砸的格子,走规则2,在当前已经经过的格子里找到存在可以砸墙的格子随机一个。

var temp = AllCols.Where(o => o.Value.IsPass && NextCol(o.Value).Count > 0); ;
if (temp.Count() == 0)
{
    break;
}
//得到下一个周边存在没有经过的格子
int nextT = new Random((int)DateTime.Now.Ticks).Next(0, temp.Count());
var nextdataT = temp.ElementAt(nextT);
start = nextdataT.Key;

好了,剩下的代码就不粘了,直接上结果 迷宫1.gif


WPF版

前面是在CAD里弄的二维,我一开始搬到WPF也是从二维开始在Canvas上实现,然后在Viewbox里实现3D。
需要注意的是 得到的线段点位数据。 在Canvas上绘制,二维坐标系Y轴 向下是正方向。3D坐标系里Y轴向上是正方向。转换成3D的时候需要处理Y坐标
coordsystem-1.png
在转换成3D之前记得处理下线段的合并,由于我前面是一个格子的长度一段线,这样整体下来需要绘制的3D对象太多了,通过对相连的水平线,垂直线合并成一条线能减少点压力。

demo.gif

后续打算完善成用鼠标控制3D迷宫,如果有可能的话 再来个小球控制在迷宫里移动

具体注意细节,以及后续修改 改天更新......