如何随机创建一个迷宫

时间:2019-10-16 06:06:57

标签: c# algorithm unity3d maze

我目前有代码可以打开预制板上所有不在随机生成的地图边缘的房间/瓷砖的门。我想修改此代码,以便不是所有的门都打开,而是更多是随机生成的迷宫。我希望每个房间都可以访问,并且可能有多个路径可以穿越迷宫/游戏世界。如何更改代码,使其以这种方式工作?下面是我要修改的当前代码。

using UnityEngine;

public class Room : MonoBehaviour {

    public GameObject doorNorth;
    public GameObject doorSouth;
    public GameObject doorEast;
    public GameObject doorWest;
}

using UnityEngine;
using System;
public class mapGenerator : MonoBehaviour {
    public int rows;
    public int cols;
    public GameObject[] gridPrefabs;
    private float roomWidth = 50.0f;
    private float roomHeight = 50.0f;
    public Room[,] grid;//used to keep track of rooms created ,uses two numbers to refer to it in memory
    public bool isMapOfDay;
    public bool isRandomMap;
    public int chosenSeed;


    // Use this for initialization
    void Start () {
        chosenSeed = GameManager.instance.mapSeed;
        rows = GameManager.instance.mapRows;
        cols = GameManager.instance.mapColumns;
        isMapOfDay = GameManager.instance.useMapOfDay;
        isRandomMap = GameManager.instance.useRandomMap;
        gridPrefabs = GameManager.instance.mapTiles;

    }


    public GameObject RandomRoomPrefab()//Returns a random room
    {   
        return gridPrefabs [UnityEngine.Random.Range (0, gridPrefabs.Length)];      
    }
    public void GenerateGrid()//used to generate map grid
    {

        if (isRandomMap == true && isMapOfDay == false) {//sets map to random map based on time
            UnityEngine.Random.InitState(DateToInt(DateTime.Now));//sets "random" seed to current time
        } else if (isRandomMap == false && isMapOfDay == true) {//sets map to map of day based on numbers in day
            UnityEngine.Random.InitState(DateToInt (DateTime.Now.Date));
        } else {//if both are selected just use random map
            UnityEngine.Random.InitState(DateToInt (DateTime.Now));
        }
        if (chosenSeed != 0) {//if a specific seed is entered in game manager use this instead
            UnityEngine.Random.InitState(chosenSeed);
        }
        //Clear out the grid
        grid = new Room[cols, rows];
        GameManager.instance.mapGrid = grid;
        //For each grid row...
        for (int i=0; i<rows; i++)
        {
            //for each column in that row
            for (int j=0; j<cols; j++) 
            {
                //Figure out the location
                float xPosition = roomWidth * j;
                float zPosition = roomHeight * i;
                Vector3 newPosition = new Vector3 (xPosition, 0.0f, zPosition);
                //create a new grid at appropiate location
                GameObject tempRoomObj = Instantiate (RandomRoomPrefab (), newPosition, Quaternion.identity)as GameObject;
                //set its parent
                tempRoomObj.transform.parent = this.transform;
                //give the temp room a meaningful name
                tempRoomObj.name = "Room_" + j + "," + i;
                //Get the room object
                Room tempRoom = tempRoomObj.GetComponent<Room> ();
                //open doors as needed
                if (i == 0) {
                    //open north doors if on bottom row
                    tempRoom.doorNorth.SetActive (false);
                } else if (i == rows - 1) {
                    //Otherwise, if doors are on the top row open south doors
                    tempRoom.doorSouth.SetActive (false);
                } else {
                    //otherwise, this row is in the middle so both north and south open
                    tempRoom.doorNorth.SetActive (false);
                    tempRoom.doorSouth.SetActive (false);
                }
                if (j == 0) {
                    //if first column then east doors are opened
                    tempRoom.doorEast.SetActive (false);
                } else if (j == cols - 1) {
                    //Otheriwse, if one last column row open west doors
                    tempRoom.doorWest.SetActive (false);
                } else {
                    //otherwise, we are in middle so both west and east are opened
                    tempRoom.doorEast.SetActive (false);
                    tempRoom.doorWest.SetActive (false);
                }

                //save it to the grid array
                grid [j, i] = tempRoom;//
                GameManager.instance.mapGrid=grid;
            }
        }

    }
    public int DateToInt(DateTime dateToUse)//adds date and time up and returns it as an int
    {
        int dateToReturn = dateToUse.Year + dateToUse.Month + dateToUse.Day + dateToUse.Hour +dateToUse.Minute + dateToUse.Second + dateToUse.Millisecond;
        return dateToReturn;
    }
    public void clear()//clears grid
    {
        for (int c=0; c<GameManager.instance.mapGrid.GetLength(0); c++) {
            for (int r=0; r<GameManager.instance.mapGrid.GetLength(1); r++) {
                if(GameManager.instance.mapGrid[c,r]!=null)//if not null destroy
                {
                   Destroy(GameManager.instance.mapGrid[c,r].gameObject);
                }


            }

        }
    }

}

我相信需要在我的else语句中进行更改,但是我不确定如何进行此操作,因为我以前从未做过迷宫。感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

查看此博客,它也许可以帮助您了解Unity中迷宫的程序生成。

https://www.raywenderlich.com/82-procedural-generation-of-mazes-with-unity

但实际上,您可以使用递归回溯算法。实施起来相对简单。

将起点标记为已访问并选择一个未访问的随机Neightbor。

从该起点随机选择一个网格,并刻划一条通向近网格的通道(仅当尚未访问近网格时才使用。它将是新网格

仅当所有附近的网格都处于访问状态时,才返回最后一个没有雕刻壁的网格并重复。

当过程一直备份到起点时,算法结束。

我希望您能进一步说明您要寻找的东西。