Как случайным образом создать лабиринт - PullRequest
0 голосов
/ 16 октября 2019

В настоящее время у меня есть код, который открывает все двери в моих сборных для комнат / плиток, которые не находятся на краях моей случайно сгенерированной карты. Я хотел бы изменить этот код так, чтобы не все двери были открыты, и это был скорее случайный лабиринт. Я хочу, чтобы каждая комната была доступна, и в лабиринте / игровом мире можно иметь более одного пути. Как я могу изменить свой код, чтобы он работал таким образом? Ниже приведен мой текущий код, который я хочу изменить.

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 голосов
/ 16 октября 2019

Проверьте этот блог, возможно, он поможет вам понять процедурную генерацию лабиринтов в Unity.

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

Но, по сути, вы можете использовать алгоритм рекурсивного обратного отслеживания. Это относительно просто реализовать.

Пометьте свою начальную точку как посещенную и выберите случайную соседнюю станцию, которая не посещается.

Произвольно выберите сетку в этой начальной точке и пропустите проход к ближайшей сетке (только если ближайшая сетка еще не была посещена. Это будет новая сетка

Вернитесь к последней сетке, которая имеет невырезанную стенку, и повторите, только если все близкие сетки были в посещенном состоянии.

Алгоритм заканчивается, когда процесс полностью продвинулся до начальной точки.

Я надеюсь, что вы могли бы уточнить немного больше о том, что вы ищете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...