首页 > 解决方案 > 如何随机创建一个迷宫

问题描述

我目前有代码可以打开我的预制件上的所有门,用于不在我随机生成的地图边缘的房间/瓷砖。我想修改这段代码,以便不是所有的门都打开,它更像是一个随机生成的迷宫。我希望每个房间都可以进入,并且可以有不止一条穿过迷宫/游戏世界的路径。如何更改我的代码,使其以这种方式工作?以下是我要修改的当前代码。

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 语句中发生,但我不确定如何去做,因为我以前从未做过迷宫。谢谢您的帮助!

标签: c#algorithmunity3dmaze

解决方案


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

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

但本质上你可以使用递归回溯算法。实现起来相对简单。

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

在该起点随机选择一个格子,并刻出一条通往近格子的通道(仅当尚未访问近格子时。它将是新的格子

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

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

我希望你能澄清一下你在找什么。


推荐阅读