Prim的算法C#Unity

时间:2014-07-10 16:51:47

标签: c# algorithm unity3d prims-algorithm

我目前正在使用prim算法在Unity中生成随机迷宫。

如果我运行游戏,这就是迷宫的样子。

http://i1.ytimg.com/vi/ucWX34Vrel8/maxresdefault.jpg

这就是我想要迷宫的样子。

http://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/MAZE_30x20_Prim.ogv/220px--MAZE_30x20_Prim.ogv.jpg

不同之处在于,第一个角落的白色方块接触,而第二个角落的白色方块之间始终有空间。

这是控制迷宫视觉创作的代码:

void FindNext(){
    //We create an empty Transform variable
    // to store the next cell in.
    Transform next;
    //List for the current cell's adjacents
    List<Transform> curAdjacents;
    //List for an element's adjacents
    List<Transform> eleAdjacents;
    //Number variable for while loop
    int num = 1;
    //Perform this loop 
    // While:
    //  The proposed next gameObject's AdjacentsOpened
    //   is less than or equal to 2.
    //   This is to ensure the maze-like structure.
    do{
        //We'll initially assume that each sub-list of AdjSet is empty
        // and try to prove that assumption false in the for loop.
        // This boolean value will keep track.
        bool empty = true;
        //We'll also take a note of which list is the Lowest,
        // and store it in this variable.
        int lowestList = 0;
        for(int i = 0; i < 10; i++){
            //We loop through each sub-list in the AdjSet list of
            // lists, until we find one with a count of more than 0.
            // If there are more than 0 items in the sub-list,
            // it is not empty.
            //We then stop the loop by using the break keyword;
            // We've found the lowest sub-list, so there is no need
            // to continue searching.
            lowestList = i;
            if(AdjSet[i].Count > 0){
                empty = false;
                break;
            }
        }
        //There is a chance that none of the sub-lists of AdjSet will
        // have any items in them.
        //If this happens, then we have no more cells to open, and
        // are done with the maze production.
        if(empty){ 
            //If we finish, as stated and determined above,
            // display a message to the DebugConsole
            // that includes how many seconds it took to finish.
            Debug.Log("We're Done, "+Time.timeSinceLevelLoad+" seconds taken"); 
            //Then, cancel our recursive invokes of the FindNext function,
            // as we're done with the maze.
            //If we allowed the invokes to keep going, we will receive an error.
            CancelInvoke("FindNext");
            //Set.Count-1 is the index of the last element in Set,
            // or the last cell we opened.
            //This will be marked as the end of our maze, and so
            // we mark it red.
            Set[Set.Count-1].renderer.material.color = Color.red;
            //Every cell in the grid that is not in the set
            // will be moved one unit up and turned black.
            // (I changed the default color from black to clear earlier).
            // If you instantiate a FirstPersonController in the maze now,
            // you can actually try walking through it.
            // It's really hard.
            foreach(Transform cell in Grid){
                if(!Set.Contains(cell)){
                    cell.Translate(Vector3.up); 
                    cell.renderer.material.color = Color.black;
                }
            }
            return;
        }
        //If we did not finish, then:
        // 1. Use the smallest sub-list in AdjSet
        //     as found earlier with the lowestList
        //     variable.
        // 2. With that smallest sub-list, take the first
        //     element in that list, and use it as the 'next'.
        next = AdjSet[lowestList][0];
        curAdjacents = next.GetComponent<CellScript>().Adjacents;
        //Since we do not want the same cell in both AdjSet and Set,
        // remove this 'next' variable from AdjSet.
        AdjSet[lowestList].Remove(next);

        //This is code I'm trying to use to solve the issue
        //When I run it though it makes all but the first and last,
        //square white. It is supposed to NOT break if one of the current,
        //cell's adjacents cells has an adjacent cell that has already,
        //been made white. I don't know what's wrong with this code.
        //foreach(Transform element in curAdjacents){
            //eleAdjacents = element.GetComponent<CellScript>().Adjacents;
            //foreach(Transform elem in eleAdjacents){
                //if(Set.Contains(elem)){
                    //continue;
                //}
                //else{
                    //Debug.Log("BREAK!");
                    //num = 0;
                    //break;
                //}
            //}
        //}
    }while(next.GetComponent<CellScript>().AdjacentsOpened >= 2 && num == 1);
    //The 'next' transform's material color becomes white.
    next.renderer.material.color = Color.white;
    //We add this 'next' transform to the Set our function.
    AddToSet(next);
    //Recursively call this function as soon as this function
    // finishes.
    Invoke("FindNext", 0);
}

欢迎任何解决方案,无论是小的更改还是对所有代码的完全重做。如果您不知道如何修复代码,但是您知道如何按照我希望使用prim算法的方式制作迷宫,请分享它。

2 个答案:

答案 0 :(得分:0)

事实上,我猜你几乎就在那里,你只需要在节点之间加入人工空间。我想如果你在像

这样的图表上操作
ooo
ooo
ooo

其中o表示节点,迷宫中实际生成的路径应该看起来像

o-o-o
| | |
o-o-o
| | |
o-o-o

这意味着实际迷宫中必须包含更多空间。

答案 1 :(得分:0)

好的,我会尝试使用一堆ascii图片来解释这个逻辑,因为我的文字并不那么热。

假设您从一个类似于:

的迷宫开始
...X..
.X.X.X
X....X
X.X.X.
X.X...
...XXX

其中&#34;。&#34; s是可行驶的道路,&#34; X&#34; s是墙壁。 假设你的起始迷宫是一个数组,为了获得一个很好的分离的迷宫,你可以“逐块”地构建“超级块”并将它们插入一个更大的数组中。 在此示例中,左上角的块将查看,向上,向下,向左和向右以查看其邻居可移动的位置。然后构建一个“超级块”,如:

XXX
X..
X.X

假设“角落”将成为墙壁。在构造之后,它将自身插入较大阵列的左上部分。 同样,第二个块将构造如下:

XXX
...
XXX

然后将其自身插入左上角的第二个位置。根据您希望它的运行方式,它可以将第一个块重叠一个空格以保持拉伸。此时,您的较大数组看起来像(其中[]为空/未分配):

XXXXXX[][][][][]
X.....[][][][][]
X.XXXX[][][][][]
[][][][][][][][]
[][][][][][][][]

接下来,每个块都会自行查看,制作一个超级块,然后将自己设置为大型数组,直到得到类似的内容:

XXXXXXXXXXXXXXXXXX
X.......XXXXX.....
X.XXXXX.XXXXX.XXXX
XXXXXXX.XXXXX.XXXX
XXXX..........XXXX
XXXX.XXXXX.XXXXXXX
XXXX.XXXXX.XXXXXXX
XXXX.XXXXX.XXXXX.X
XXXX.XXXXX.XXXXX.X
XXXX.XXXXX.XXXXX.X 
XXXX.XXXXX.......X
XXXX.XXXXXXXXXXXXX
XXXX.XXXXXXXXXXXXX
........XXXXXXXXXX
XXXXXXXXXXXXXXXXXX