Linked Questions

Popular Questions

I use Two scripts for generation, but, sometimes it gets stuck and doesn't generate more rooms even when being way under the minimum rooms demanded. (I implemented a seed system to replicate the problem and try to solve it, just grab a seed with a problem and introduce it into the variable)

And example of stuck situations is:(T is start room and O are rooms)

OO..
OTO
..OO

or

OOO...
O.....TO
OOOO

I don't know if it's a timing issue with function calls or some variable not working alright.

Roombinger.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class Roombinger : MonoBehaviour
{
    public Camera MapCam;
    public GameObject StartRoom;
    public List<GameObject> Roomi;
    public GameObject ShopRoom;
    public GameObject BossRoom;
    private int currroomdooramount;
    public Roomathon currRoom;
    public Vector2Int startpos = new Vector2Int(3, 5);
    public int minrooms;
    public bool updated;
    public bool specials = false;
    public List<bool> childrengeneration = new List<bool>();

    public int seed;
    public static Roombinger instance;
    bool IsLoadingRoom = false;
    public string currentWorldName = "Basement";//Get name from dictionary

    public Vector3 StartRoomPos;
    public bool BossSpawned;
    public bool ShopSpawned;

    [SerializeField]
    public List<Roomathon> allChildren = new List<Roomathon>();
    [SerializeField]
    public List<Roomathon> Deadends = new List<Roomathon>();

    void Awake()
    {
        instance = this;
    }

    public int GetchildrenCount()
    {
        return allChildren.Count;
    }

    public bool DoesRoomExist(float x, float y)
    {
        return allChildren.Find(item => item.X == x && item.Y == y) != null;
    }

    public Roomathon FindRoom(float x, float y)
    {
        return allChildren.Find(item => item.X == x && item.Y == y);
    }

    public void OnPlayerEnterRoomo(Roomathon room)
    {
        CameraController1.instance.currRoom = room;
        currRoom = room;
    }

    // Start is called before the first frame update
    void Start()
    {
        var temp = Instantiate(StartRoom, new Vector3(0, 0, 0), Quaternion.identity, transform).GetComponent<Roomathon>();
        temp.X = 3;
        temp.Y = 5;
        temp.name = currentWorldName + "-" + "Start" + " " + temp.GetComponent<Roomathon>().X + ", " + temp.GetComponent<Roomathon>().Y;
        StartRoomPos = new Vector3(temp.X * temp.Width, temp.Y * temp.Height, 0);

        // comment this initialization out if setting up a specific seed(only numbers) manually
        seed = Random.Range(0, int.MaxValue);
        Random.InitState(seed);
    }

    // Update is called once per frame
    void Update()
    {
        Random.InitState(seed);
        allChildren = transform.Cast<Transform>().Select(t => t.gameObject.GetComponent<Roomathon>()).ToList();
        childrengeneration = new List<bool>();

        foreach (Roomathon child in allChildren)
        {
            childrengeneration.Add(child.isgenerating);
        }
        if (!childrengeneration.Contains(true) && allChildren.Count < minrooms)
        {
            // Only set the generating flag for rooms that are not generating
            foreach (Roomathon child in allChildren)
            {
                if (!child.isgenerating)
                {
                    child.isgenerating = true;
                }
            }
        }
        if (allChildren.Count < minrooms)
        {
            foreach (Roomathon child in allChildren)
            {
                if (!child.canGenerateMore)
                {
                    //if (Random.value < 0.75f)
                    //{
                        child.canGenerateMore = true;
                    //}
                }
            }
        }
        if (allChildren.Count > minrooms)
        {
            foreach (Roomathon child in allChildren)
            {
                child.isgenerating = false;
            }

        }

        if (!specials && !childrengeneration.Contains(true) && allChildren.Count >= minrooms && updated)
        {
            Debug.Log("splecia");
            /*foreach (Roomathon child in allChildren)
            {
                if(child.ds.Count == 4)
                {

                }
            }*/
            StartCoroutine(SpecialsSpawn());
            if (BossSpawned && ShopSpawned)
            {
                specials = true;
            }
        }
        if ((allChildren.Count >= minrooms&& !updated && !childrengeneration.Contains(true)))
        {
            //Debug.Log("Childrends??"+ (allChildren.Count == minrooms - 1));
            //allChildren.OrderBy(v => (v.X)).ToList();
            foreach (Roomathon child in allChildren)
            {
                //Debug.Log("toremove");
                child.RemoveUnconnectedDoors();
                if (child.deadend)
                {
                    /*if (Deadends.Contains(child))
                    {
                        Deadends.Remove(child);
                    }*/
                    //Debug.Log("if room has deads " + child);
                    Deadends.Add(child);
                }
                if (Deadends.Count >= 1) {
                    updated = true;
                }
                if (!child.canGenerateMore)
                {
                    child.isgenerating = false;
                }
            }
            
        }
        if (allChildren.Count >= minrooms)
        {
            foreach (Roomathon child in allChildren)
            {
                child.isgenerating = false;
            }
        }
        /*if(allChildren.Count == minrooms - 1 && !childrengeneration.Contains(false))
        {
            Debug.Log("Childrends??" + (allChildren.Count == minrooms - 1));
            foreach (Roomathon child in allChildren)
            {
                Debug.Log("toremove");
                child.RemoveUnconnectedDoors();
                if (child.deadend)
                {
                    if (Deadends.Contains(child))
                    {
                        Deadends.Remove(child);
                    }
                    Debug.Log("if room has deads " + child);
                    Deadends.Add(child);
                }
                if (Deadends.Count >= 1)
                {
                    updated = true;
                }
            }
        }*/
        //Debug.Log(allChildren.Count);
    }

    public GameObject GetaRoom()
    {
        return Roomi[Random.Range(0, Roomi.Count)].gameObject;
    }

    IEnumerator SpecialsSpawn()
    {
        Roomathon temp = null;
        //Debug.Log("Specialsss");

        var Deadendsposs = new List<Transform>();
        var Deadendsdiff = new List<Vector3>();
        foreach (Roomathon child in Deadends)
        {
            Deadendsposs.Add(child.transform);
            Deadendsdiff.Add(child.transform.position - StartRoomPos);
        }
        Deadendsdiff = Deadendsdiff.OrderBy(v => (Mathf.Abs(v.x) + Mathf.Abs(v.y) + Mathf.Abs(v.z))).ToList();
        Deadends = Deadends.OrderBy(v => (Mathf.Abs(v.transform.position.x) + Mathf.Abs(v.transform.position.y) + Mathf.Abs(v.transform.position.z))).ToList();
        yield return new WaitForSeconds(0.07f);
        Debug.Log("dd");
        //Debug.Log("trying" + (!BossSpawned && Deadends.Count != 0));
        //Debug.Log("Boss?" + !BossSpawned);
        //Debug.Log("No counts?" + (Deadends.Count != 0));
        if (!BossSpawned && Deadends.Count != 0 && allChildren.Count >= minrooms)
        {
            BossSpawned = true;
            Debug.Log("Boss?");
            Deadends = Deadends.OrderBy(v => (StartRoomPos - new Vector3(Mathf.Abs(v.transform.position.x), Mathf.Abs(v.transform.position.y), Mathf.Abs(v.transform.position.z))).magnitude).ToList();
            //Deadendsdiff = Deadendsdiff.OrderBy(v => (Mathf.Abs(v.x) + Mathf.Abs(v.y) + Mathf.Abs(v.z))).ToList();
            yield return new WaitForSeconds(0.1f);
            var nn = Deadends[0];
            Debug.Log(nn);
            yield return new WaitForSeconds(0.2f);
            temp = Instantiate(BossRoom, new Vector3(0, 0, 0), Quaternion.identity, transform).GetComponent<Roomathon>();
            temp.X = nn.X;
            temp.Y = nn.Y;
            temp.name = currentWorldName + "-" + "Boss" + " " + nn.X + ", " + nn.Y;
            Deadends.Remove(nn);
            //Deadends.Add(temp);
            Destroy(nn.gameObject);
            temp.RemoveUnconnectedDoors();
            Debug.Log("Removed");
        }
        /*if (temp != null)
        {
            Deadendsdiff.Remove(Deadendsdiff[Deadendsdiff.Count]);
        }*/
        yield return new WaitForSeconds(0.5f);
        if (!ShopSpawned && Deadends.Count != 0 && allChildren.Count >= minrooms && BossSpawned)
        {
            ShopSpawned = true;
            Debug.Log("Shop?");
            Deadends = Deadends.OrderBy(v => (StartRoomPos - new Vector3(Mathf.Abs(v.transform.position.x), Mathf.Abs(v.transform.position.y), Mathf.Abs(v.transform.position.z))).magnitude).ToList();
            //Deadendsdiff = Deadendsdiff.OrderBy(v => (Mathf.Abs(v.x) + Mathf.Abs(v.y) + Mathf.Abs(v.z))).ToList();
            yield return new WaitForSeconds(0.1f);
            var nn = Deadends[0];
            Debug.Log(nn);
            yield return new WaitForSeconds(0.2f);
            temp = Instantiate(ShopRoom, new Vector3(0, 0, 0), Quaternion.identity, transform).GetComponent<Roomathon>();
            temp.X = nn.X;
            temp.Y = nn.Y;
            temp.name = currentWorldName + "-" + "Shop" + " " + nn.X + ", " + nn.Y;
            Deadends.Remove(nn);
            //Deadends.Add(temp);
            Destroy(nn.gameObject);
            temp.RemoveUnconnectedDoors();
            Debug.Log("Removed2");
            yield return new WaitForSeconds(0.2f);
        }
        /*if (temp != null)
        {
            Deadendsdiff.Remove(Deadendsdiff[Deadendsdiff.Count]);
        }*/
    }

    void mapcampos()
    {
        var temp = new Vector3(0,0,-154.7f);
        allChildren.OrderBy(v => (v.X)).ToList();
        Debug.Log(((allChildren[0].transform.position) + ((allChildren[0].transform.position - allChildren[allChildren.Count - 1].transform.position) / 2)).x);
        temp.x = ((allChildren[0].transform.position) + ((allChildren[0].transform.position - allChildren[allChildren.Count - 1].transform.position) / 2)).x;
        allChildren.OrderBy(v => (v.Y)).ToList();
        Debug.Log(((allChildren[0].transform.position) + ((allChildren[0].transform.position - allChildren[allChildren.Count - 1].transform.position) / 2)).y);
        temp.y= ((allChildren[0].transform.position) + ((allChildren[0].transform.position - allChildren[allChildren.Count - 1].transform.position) / 2)).y;
        Debug.Log(temp);
        MapCam.transform.position = temp;
    }

}

Roomathon.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class Roomathon : MonoBehaviour
{
    [Header("Ingame Properties")]
    public Vector2 SwlextedNeighbor2 = Vector2.zero;
    public Vector2 SwlextedNeighbor = Vector2.zero;
    public List<Vector2> availableNeighbors2;
    public List<Vector2> availableNeighbors;
    private bool isCoroutineRunning = false;
    public bool canGenerateMore = true;
    public List<GameObject> Neighbors2;
    public List<GameObject> Neighbors;
    public bool isgenerating = true;
    public bool deadend = false;
    public List<Door> ds;
    public int Height;
    public int Width;
    public int X;
    public int Y;


    [Header("Outer Properties")]
    public List<Door> doors = new List<Door>();
    public SpriteRenderer MapSprite;
    public Door bottomDoor;
    public Door rightDoor;
    public Door leftDoor;
    public Door topDoor;





    // Start is called before the first frame update
    void Start()
    {
        transform.position = new Vector3(X * Width, Y * Height, 0);
        availableNeighbors2 = new List<Vector2>();
        availableNeighbors = new List<Vector2>();
        Neighbors = new List<GameObject>();

        if (Roombinger.instance == null)
        {
            Debug.Log("No controller instance found");
            return;
        }

        // add Doors to ds
        Door[] ds = GetComponentsInChildren<Door>();
        foreach (Door d in ds)
        {
            doors.Add(d);
            switch (d.doorType)
            {
                case Door.DoorType.right:
                    rightDoor = d;
                    break;
                case Door.DoorType.left:
                    leftDoor = d;
                    break;
                case Door.DoorType.top:
                    topDoor = d;
                    break;
                case Door.DoorType.bottom:
                    bottomDoor = d;
                    break;
            }
        }
        StartCoroutine(RoomGenerationCoroutine());
    }
    public int SearchNeighbors(int x, int y)
    {
        // Clear relevant lists

        availableNeighbors.Clear();
        SwlextedNeighbor = Vector2.zero;
        Neighbors.Clear();

        // Each Findroom removes and adds the item to avoid dupes
        if (Roombinger.instance.FindRoom(x + 1, y) != null)
        {
            //Debug.Log(Roombinger.instance.FindRoom(x + 1, y).gameObject+"roomj");
            Neighbors.RemoveAll(item => item == Roombinger.instance.FindRoom(x + 1, y).gameObject);
            Neighbors.Add(Roombinger.instance.FindRoom(x + 1, y).gameObject);
        }
        else
        // If there isn't a room add to availables
        {
            availableNeighbors.Add(new Vector2(x + 1, y));
        }
        if (Roombinger.instance.FindRoom(x - 1, y) != null)
        {
            Neighbors.RemoveAll(item => item == Roombinger.instance.FindRoom(x - 1, y).gameObject);
            Neighbors.Add(Roombinger.instance.FindRoom(x - 1, y).gameObject);
        }
        else
        {
            availableNeighbors.Add(new Vector2(x - 1, y));
        }
        if (Roombinger.instance.FindRoom(x, y + 1) != null)
        {
            Neighbors.RemoveAll(item => item == Roombinger.instance.FindRoom(x, y+1).gameObject);
            Neighbors.Add(Roombinger.instance.FindRoom(x, y + 1).gameObject);
        }
        else
        {
            availableNeighbors.Add(new Vector2(x, y + 1));
        }
        if (Roombinger.instance.FindRoom(x, y - 1) != null)
        {
            Neighbors.RemoveAll(item => item == Roombinger.instance.FindRoom(x, y-1).gameObject);
            Neighbors.Add(Roombinger.instance.FindRoom(x, y - 1).gameObject);
        }
        else
        {
            availableNeighbors.Add(new Vector2(x, y - 1));
        }
        if (availableNeighbors.Count > 0)
        {
            SwlextedNeighbor = availableNeighbors[Random.Range(0, availableNeighbors.Count)];
            if (Roombinger.instance.DoesRoomExist(SwlextedNeighbor.x, SwlextedNeighbor.y))
            {
                availableNeighbors.Remove(SwlextedNeighbor);
            }
            else
            {
                SwlextedNeighbor = availableNeighbors[Random.Range(0, availableNeighbors.Count)];
            }
        }
        return Neighbors.Count;
    }

    public int SearchNeighbors2(int x, int y)
    {
        availableNeighbors2.Clear();
        SwlextedNeighbor2 = Vector2.zero;
        Neighbors2.Clear();
        if (Roombinger.instance.FindRoom(x + 1, y) != null)
        {
            //Debug.Log(Roombinger.instance.FindRoom(x + 1, y).gameObject+"roomj");
            Neighbors2.RemoveAll(item => item == Roombinger.instance.FindRoom(x + 1, y).gameObject);
            Neighbors2.Add(Roombinger.instance.FindRoom(x + 1, y).gameObject);
        }
        else
        {
            availableNeighbors2.Add(new Vector2(x + 1, y));
        }
        if (Roombinger.instance.FindRoom(x - 1, y) != null)
        {
            Neighbors2.RemoveAll(item => item == Roombinger.instance.FindRoom(x - 1, y).gameObject);
            Neighbors2.Add(Roombinger.instance.FindRoom(x - 1, y).gameObject);
        }
        else
        {
            availableNeighbors2.Add(new Vector2(x - 1, y));
        }
        if (Roombinger.instance.FindRoom(x, y + 1) != null)
        {
            Neighbors2.RemoveAll(item => item == Roombinger.instance.FindRoom(x, y + 1).gameObject);
            Neighbors2.Add(Roombinger.instance.FindRoom(x, y + 1).gameObject);
        }
        else
        {
            availableNeighbors2.Add(new Vector2(x, y + 1));
        }
        if (Roombinger.instance.FindRoom(x, y - 1) != null)
        {
            Neighbors2.RemoveAll(item => item == Roombinger.instance.FindRoom(x, y - 1).gameObject);
            Neighbors2.Add(Roombinger.instance.FindRoom(x, y - 1).gameObject);
        }
        else
        {
            availableNeighbors2.Add(new Vector2(x, y - 1));
        }
        if (availableNeighbors2.Count > 0)
        {
            SwlextedNeighbor2 = availableNeighbors2[Random.Range(0, availableNeighbors2.Count)];
            if (Roombinger.instance.DoesRoomExist(SwlextedNeighbor2.x, SwlextedNeighbor2.y))
            {
                availableNeighbors2.Remove(SwlextedNeighbor2);
            }
            else
            {
                SwlextedNeighbor2 = availableNeighbors2[Random.Range(0, availableNeighbors2.Count)];
            }
        }
        return Neighbors2.Count;
    }
    private IEnumerator RoomGenerationCoroutine()
    {
        isCoroutineRunning = true;
        while (isgenerating && canGenerateMore)
        {
            Debug.Log("InLoop");
            bool isDeadEnd = SearchNeighbors(X, Y) == 1;
            if (isDeadEnd && Random.value < 0.25f)
            {
                canGenerateMore = false; // The room cannot generate more
            }
            // 50% chance to stop
            if ((Random.value > 0.5f))
            {
                isgenerating = false;
            }
            // If total room number is greater or equal to minrooms stop generating
            if (Roombinger.instance.allChildren.Count >= Roombinger.instance.minrooms)
            {
                isgenerating = false;
            }
            var maxNeighbor1 = 1;
            // If start room allow up to 3 neighbors
            if (X == 3 && Y == 5 && SearchNeighbors(X, Y) < 4)
            {
                maxNeighbor1 = 3;
            }
            // if not start room only allow one neighbor (past room)
            else if (X != 3 && Y != 5)
            {
                maxNeighbor1 = 1;
            }
            //check neighbors
            if (SearchNeighbors(X, Y) <= maxNeighbor1)
            {
                // Check if there isn't any existing room at selected place
                yield return new WaitForSeconds(0.2f);
                if (!Roombinger.instance.DoesRoomExist(SwlextedNeighbor.x, SwlextedNeighbor.y))
                {
                    // If the isn't any existing room there total rooms are minor or equal to minrooms
                    yield return new WaitForSeconds(0.2f);
                    if (!Roombinger.instance.DoesRoomExist(SwlextedNeighbor.x, SwlextedNeighbor.y) && Roombinger.instance.GetchildrenCount() <= Roombinger.instance.minrooms)
                    {
                        // Search if neighbors of selected place is minor or equal to 1 and total rooms are minor than minrooms (task takes times needs WaitForseconds or wont work correctly)
                        var tmmm = ((SearchNeighbors2((int)SwlextedNeighbor.x, (int)SwlextedNeighbor.y) <= 1) && (Roombinger.instance.allChildren.Count<Roombinger.instance.minrooms));
                        yield return new WaitForSeconds(0.2f);
                        if (tmmm)
                        {
                            // Get a random room from list of variants and instantiate on selected place with corresponding name as child of RoomManager, end with adding the room to allchildren list
                            var ChosenRoom = Roombinger.instance.GetaRoom();
                            var temp = Instantiate(ChosenRoom, new Vector3(SwlextedNeighbor.x, SwlextedNeighbor.y, 0), Quaternion.identity, transform.parent);
                            temp.GetComponent<Roomathon>().X = (int)SwlextedNeighbor.x;
                            temp.GetComponent<Roomathon>().Y = (int)SwlextedNeighbor.y;
                            temp.name = Roombinger.instance.currentWorldName + "-" + temp.name + " " + temp.GetComponent<Roomathon>().X + ", " + temp.GetComponent<Roomathon>().Y;
                            //Debug.Log(Roombinger.instance.currentWorldName + "-" + temp.name + " " + temp.GetComponent<Roomathon>().X + ", " + temp.GetComponent<Roomathon>().Y + " spawned");
                            temp.transform.parent = transform.parent;
                            Roombinger.instance.allChildren.Add(temp.GetComponent<Roomathon>());
                        }
                    }
                }
            }
        }
        isCoroutineRunning = false;
    }


    // Update is called once per frame
    void Update()
    {
        
        /*if (!isCoroutineRunning && Roombinger.instance.GetchildrenCount() < Roombinger.instance.minrooms)
        {
            isgenerating = true;
            StartCoroutine(RoomGenerationCoroutine());
        }*/
    }
    // Draw Room bounds in editor
    void OnDrawGizmos()
    {
        Gizmos.color = Color.green;
        Gizmos.DrawWireCube(transform.position, new Vector3(Width, Height, 0));
    }

    public Vector3 GetRoomCenter()
    {
        return new Vector2(X * Width, Y * Height);
    }

    // Change Mapsprite color to selected and change currRoom
    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            Roombinger.instance.OnPlayerEnterRoomo(gameObject.GetComponent<Roomathon>());
            var teuump = MapSprite.color;
            teuump.a =1f;
            MapSprite.color = teuump;
        }
    }
    // Change Mapsprite color to not selected
    void OnTriggerExit2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            var teuump = MapSprite.color;
            teuump.a = 0.35f;
            MapSprite.color = teuump;
        }
    }

    // Add all Door items to ds and for each one if a room isn't found in its direction setactive false and remove them from temp list that gets pushed into ds later and if ds doors is 1 then mark room as deadend
    public void RemoveUnconnectedDoors()
    {
        ds = GetComponentsInChildren<Door>().ToList();
        List<Door> doorsToRemove = new List<Door>(); // Create a list to hold doors to be removed

        foreach (Door door in ds)
        {
            switch (door.doorType)
            {
                case Door.DoorType.right:
                    if (GetRight() == null)
                    {
                        door.gameObject.SetActive(false);
                        doorsToRemove.Add(door); // Add the door to the removal list
                    }
                    break;
                case Door.DoorType.left:
                    if (GetLeft() == null)
                    {
                        door.gameObject.SetActive(false);
                        doorsToRemove.Add(door); // Add the door to the removal list
                    }
                    break;
                case Door.DoorType.top:
                    if (GetTop() == null)
                    {
                        door.gameObject.SetActive(false);
                        doorsToRemove.Add(door); // Add the door to the removal list
                    }
                    break;
                case Door.DoorType.bottom:
                    if (GetBottom() == null)
                    {
                        door.gameObject.SetActive(false);
                        doorsToRemove.Add(door); // Add the door to the removal list
                    }
                    break;
            }
        }
        
        // Now remove the doors that were marked for removal
        foreach (Door doorToRemove in doorsToRemove)
        {
            ds.Remove(doorToRemove);
        }
        if (ds.Count == 1)
        {
            deadend = true;
        }
    }
    public Roomathon GetLeft()
    {

        if (Roombinger.instance.DoesRoomExist(X - 1, Y))
        {
            return Roombinger.instance.FindRoom(X - 1, Y);
        }
        return null;
    }
    public Roomathon GetTop()
    {
        if (Roombinger.instance.DoesRoomExist(X, Y + 1))
        {
            return Roombinger.instance.FindRoom(X, Y + 1);
        }
        return null;
    }
    public Roomathon GetBottom()
    {
        if (Roombinger.instance.DoesRoomExist(X, Y - 1))
        {
            return Roombinger.instance.FindRoom(X, Y - 1);
        }
        return null;
    }
    public Roomathon GetRight()
    {
        if (Roombinger.instance.DoesRoomExist(X + 1, Y))
        {
            return Roombinger.instance.FindRoom(X + 1, Y);
        }
        return null;
    }
}

I've tried messing with max neighbor variables and waitforseconds delays and changing variables conditions but nothing is working.

Related Questions