Roguelike random underground city II. Setting doors and optimizing the selection of final rooms

Roguelike Random Dungeon

Set up doors & optimize the final room selection

1, Set up doors & optimize the final room selection

First, we add doors in four directions.
Click Prefab, and then we create a square to temporarily replace our door.
Right click create 2D sprites square.

Then drag them into our Prefab, copy them and place them in the position shown in the figure.

Next, create a Room script and mount it on Prefab.
First, we declare the four GameObject s.

    public GameObject doorLeft,doorRight,doorUp,doorDown;

Go back to Unity alignment and assign values.
The Sorting Layer will be used here. It represents our display layer. In order to display our door, we establish a Room layer and establish Ground and Player layers at the same time.


Next, we will judge whether there are doors up, down, left and right in this room. We need to generate four Boolean values.

    public bool roomLeft,roomRight, roomUp, roomDown;

Then we need to consider whether they are displayed later, so we define the display method in the Start method.

    void Start()
    {
        doorLeft.SetActive(roomLeft);
        doorRight.SetActive(roomRight);
        doorUp.SetActive(roomUp);
        doorDown.SetActive(roomDown);
    }

We will judge whether there are rooms up, down, left and right in the current room. If there is a room, the door will be displayed, and if there is no room, it will not be displayed.
Next, we judge whether there are rooms up, down, left and right.
In order to obtain the variables above each Room, change the List type of rooms we set at the beginning to Room, and make appropriate changes in the following places.

    public List<Room> rooms = new List<Room>();
     void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //Change point position
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            {
                endRoom = room.gameObject;
            }
        }
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

Next, we will set up a method to judge whether there are rooms up, down, left and right, and assign a value to the Room.
Two parameters need to be added to the method, one is used to identify the Room and the other is used to obtain the location of the Room.

    public void SetupRoom(Room newRoom,Vector3 roomPosition)
    {
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yOffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yOffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xOffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xOffset, 0, 0), 0.2f, roomLayer);
    }

By calling this method, you can comment out the method that found the last room before.

     void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //Change point position
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            //if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            //{
                //endRoom = room.gameObject;
            //}
            SetupRoom(room,room.transform.position);
        }
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

So our door is set.

2, Optimize final room selection

We need to choose the room farthest from our birth point, so next I add a Text to display the steps from each room to the grid of my birth point room.
First, create a Canvas for our Prefab, Canvas, create a Text, and change the Text to 0.

After setting, we need to get the Text in the script and change its value.
Here we create a new method in the Room script.

    public void UpdateRoom()
    {

    }

How do we count our steps?
The number of steps can be obtained by dividing the x and y values of our current room coordinates by our x and y offsets!
We want to get this value, so we start by defining a variable.
Because our coordinates may be negative, we need to use absolute values in mathematical methods.
Here I divide it directly by a fixed value for convenience.

    public int stepToStart;
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));
    }

Then we define a variable to get our text.
Then let this text show our stepToStart.

    public Text text;
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));

        text.text = stepToStart.ToString();
    }

Then we will call this method in the SetupRoom method in the RoomGenerator script.

    public void SetupRoom(Room newRoom,Vector3 roomPosition)
    {
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yOffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yOffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xOffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xOffset, 0, 0), 0.2f, roomLayer);

        newRoom.UpdateRoom();
    }

How do we set up our final room next?
Our idea is to find the room with the largest number of steps and the next largest, find the room with only one door, and randomly select one as the final room. If there is no room with only one door, then we will randomly select the room with the largest number of steps as the final room.
Next, we need to design three lists, one for the room with the largest number of steps, one for the room with several steps, and one for the room with only one door.
First, back to the Room script, we first find a Room with several doors.
Let's first define a variable to record the number of doors.
Then we have four Boolean values. For each Boolean value that is true, our number is increased by 1.

    public int doorNumber;
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));

        text.text = stepToStart.ToString();

        if (roomUp)
            doorNumber++;
        if (roomDown)
            doorNumber++;
        if (roomLeft)
            doorNumber++;
        if (roomRight)
            doorNumber++;
    }

Next, go back to the RoomGenerator script and define three values.

    List<GameObject> farRooms = new List<GameObject>();
    List<GameObject> lessFarRooms = new List<GameObject>();
    List<GameObject> oneWayRooms = new List<GameObject>();

Then we define a variable to represent the number with the largest number of steps.

    public int maxStep;

A new method is defined to find the final room.
First, we use a for loop to find the room with the largest number of steps in all rooms, add it to the farRooms array, and put the next largest room into the lessFarRooms array.

        //Get maximum value
        for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].stepToStart > maxStep)
                maxStep = rooms[i].stepToStart;
        }
        //Obtain the maximum value room and the next largest value room
        foreach (var room in rooms)
        {
            if (room.stepToStart == maxStep)
                farRooms.Add(room.gameObject);
            if(room.stepToStart == maxStep-1)
                lessFarRooms.Add(room.gameObject);
        }

There is only one door in the next array.

        for (int i = 0; i < farRooms.Count; i++)
        {
            if (farRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(farRooms[i]);
        }

        for (int i = 0; i < lessFarRooms.Count; i++)
        {
            if (lessFarRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(lessFarRooms[i]);
        }

Next, if there are values in the two oneWayRooms arrays, randomly take a value in this array as the corresponding final room. If the value is 0, randomly take a value in the farRooms value as the corresponding final room.

        if (oneWayRooms.Count != 0)
        {
            endRoom = oneWayRooms[Random.Range(0, oneWayRooms.Count)];
        }
        else
        {
            endRoom = farRooms[Random.Range(0, farRooms.Count)];
        }

Finally, just call it above.

    void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //Change point position
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            //if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            //{
            //    endRoom = room.gameObject;
            //}
            SetupRoom(room,room.transform.position);
        }
        FindEndRoom();
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

Finally, run it, and the effect is as follows.

Source code

At this stage, our complete code is as follows:
RoomGenerator script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class RoomGenerator : MonoBehaviour
{
    public enum Direction {up,down,left,right };
    public Direction direction;

    [Header("Room information")]
    public GameObject roomPrefab;
    public int rooNumber;
    public Color startColor,endColor;
    private GameObject endRoom;

    [Header("position control ")]
    public Transform generatorPoint;
    public float xOffset;
    public float yOffset;
    public LayerMask roomLayer;

    public int maxStep;

    public List<Room> rooms = new List<Room>();

    List<GameObject> farRooms = new List<GameObject>();
    List<GameObject> lessFarRooms = new List<GameObject>();
    List<GameObject> oneWayRooms = new List<GameObject>();
    // Start is called before the first frame update
    void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //Change point position
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            //if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            //{
            //    endRoom = room.gameObject;
            //}
            SetupRoom(room,room.transform.position);
        }
        FindEndRoom();
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.anyKeyDown)
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    public void ChangePointPos()
    {
        do
        {
            direction = (Direction)Random.Range(0, 4);

            switch (direction)
            {
                case Direction.up:
                    generatorPoint.position += new Vector3(0, yOffset, 0);
                    break;
                case Direction.down:
                    generatorPoint.position += new Vector3(0, -yOffset, 0);
                    break;
                case Direction.left:
                    generatorPoint.position += new Vector3(-xOffset, 0, 0);
                    break;
                case Direction.right:
                    generatorPoint.position += new Vector3(xOffset, 0, 0);
                    break;
            }
        }while (Physics2D.OverlapCircle(generatorPoint.position,0.2f,roomLayer));
    }

    public void SetupRoom(Room newRoom,Vector3 roomPosition)
    {
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yOffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yOffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xOffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xOffset, 0, 0), 0.2f, roomLayer);

        newRoom.UpdateRoom();
    }

    public void FindEndRoom()
    {
        //Get maximum value
        for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].stepToStart > maxStep)
                maxStep = rooms[i].stepToStart;
        }
        //Obtain the maximum value room and the next largest value room
        foreach (var room in rooms)
        {
            if (room.stepToStart == maxStep)
                farRooms.Add(room.gameObject);
            if(room.stepToStart == maxStep-1)
                lessFarRooms.Add(room.gameObject);
        }

        for (int i = 0; i < farRooms.Count; i++)
        {
            if (farRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(farRooms[i]);
        }

        for (int i = 0; i < lessFarRooms.Count; i++)
        {
            if (lessFarRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(lessFarRooms[i]);
        }

        if (oneWayRooms.Count != 0)
        {
            endRoom = oneWayRooms[Random.Range(0, oneWayRooms.Count)];
        }
        else
        {
            endRoom = farRooms[Random.Range(0, farRooms.Count)];
        }
    }
}

Room script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Room : MonoBehaviour
{
    public GameObject doorLeft,doorRight,doorUp,doorDown;

    public bool roomLeft,roomRight, roomUp, roomDown;

    public Text text;

    public int stepToStart;

    public int doorNumber;
    // Start is called before the first frame update
    void Start()
    {
        doorLeft.SetActive(roomLeft);
        doorRight.SetActive(roomRight);
        doorUp.SetActive(roomUp);
        doorDown.SetActive(roomDown);
    }

    // Update is called once per frame
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));

        text.text = stepToStart.ToString();

        if (roomUp)
            doorNumber++;
        if (roomDown)
            doorNumber++;
        if (roomLeft)
            doorNumber++;
        if (roomRight)
            doorNumber++;
    }
}

Tags: C# Unity

Posted by trev on Fri, 13 May 2022 22:55:51 +0300