Newer
Older
HardPoint-Project-Abertay-University-Unity3D / Assets / Scripts / Systems / RandomGeneration / RoomSpawner.cs
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class RoomSpawner : MonoBehaviour
{
    [Header("Prefabs")]
    [SerializeField] private GameObject corridorPrefab;
    [SerializeField] private GameObject startRoom;

    [SerializeField] private List<GameObject> spawnableRooms;
    [SerializeField] private List<GameObject> bossRooms;

    [Header("Spawn parameters")]
    [SerializeField] private int numberOfRooms;
    [SerializeField] private Vector2 roomoffset;
    [Tooltip("The rooms spawned are being counted. This parameter asks after how many rooms can there be a chance for the boss room to spawn.")]
    [SerializeField] private int bossRoomNumber;
    //[SerializeField]
    //[Tooltip("If adaptative it's true, it will add the offset to room size.If offset it's 0 they will just generate based on their size, this may overlap.")]
    private bool adaptative = false;

    private GameObject[,] rooms;
    private RoomInformation[,] roomsInfos;
    private System.Random random;

    private void Awake()
    {
        random = new System.Random();
        rooms = new GameObject[numberOfRooms * 2 + 1, numberOfRooms * 2 + 1];
        roomsInfos = new RoomInformation[numberOfRooms * 2 + 1, numberOfRooms * 2 + 1];
        GameObject currentRoom = Instantiate(startRoom);
        Vector2 coords = new Vector2(numberOfRooms, numberOfRooms);
        rooms[(int)coords.x, (int)coords.y] = currentRoom;
        currentRoom.name = "StartRoom";
        RoomInformation ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
        roomsInfos[(int)coords.x, (int)coords.y] = ri;
        int nor = 0;
        float bossRoom = (float)random.NextDouble() * (numberOfRooms - bossRoomNumber);
        float bossRoomRegister = bossRoom;
        bool spawnedBoss = false;
        bool wantsToSpawnBoss = false;
        while (true)
        {
            GameObject toSpawn = spawnableRooms[Random.Range(0, spawnableRooms.Count)];
            int o = UnityEngine.Random.Range(1, 4);
            if (nor >= numberOfRooms && spawnedBoss) break;
            if (nor >= bossRoomNumber && !spawnedBoss)
            {
                if (bossRoom <= 0)
                {
                    toSpawn = bossRooms[Random.Range(0, bossRooms.Count)];
                    wantsToSpawnBoss = true;
                }
                bossRoom--;
            }
            if (adaptative)
            {
                switch (o)
                {
                    case 0:
                        if (rooms[(int)coords.x + 1, (int)coords.y] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x + ri.dimensions.x + roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x + 1, coords.y);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;
                        }
                        break;
                    case 1:
                        if (rooms[(int)coords.x, (int)coords.y + 1] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y + ri.dimensions.y + roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x, coords.y + 1);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;



                        }
                        break;
                    case 2:
                        if (rooms[(int)coords.x, (int)coords.y - 1] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y - ri.dimensions.y - roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x, coords.y - 1);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;


                        }
                        break;
                    case 3:
                        if (rooms[(int)coords.x - 1, (int)coords.y] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x - ri.dimensions.x - roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x - 1, coords.y);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;

                        }
                        break;
                }
            }
            else
            {
                switch (o)
                {
                    case 0:
                        if (rooms[(int)coords.x + 1, (int)coords.y] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x + roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x + 1, coords.y);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;

                        }
                        break;
                    case 1:
                        if (rooms[(int)coords.x, (int)coords.y + 1] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y + roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x, coords.y + 1);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;



                        }
                        break;
                    case 2:
                        if (rooms[(int)coords.x, (int)coords.y - 1] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y - roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x, coords.y - 1);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++; 
                            if (wantsToSpawnBoss) spawnedBoss = true;



                        }
                        break;
                    case 3:
                        if (rooms[(int)coords.x - 1, (int)coords.y] == null)
                        {
                            currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x - roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
                            coords = new Vector2(coords.x - 1, coords.y);
                            ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
                            rooms[(int)coords.x, (int)coords.y] = currentRoom;
                            roomsInfos[(int)coords.x, (int)coords.y] = ri;
                            nor++;
                            if (wantsToSpawnBoss) spawnedBoss = true;
                        }
                        break;
                }
                
            }
            
        }
       

    }
    public List<string> WhereCanIOpen(Vector2 myCoords)
    {
        List<string> list = new List<string>();
        if (rooms[(int)myCoords.x + 1, (int)myCoords.y] != null)
        {
            list.Add("wallR");
           CreateBridge(myCoords, 0);
        }
        if (rooms[(int)myCoords.x - 1, (int)myCoords.y] != null)
        {
            list.Add("wallL");
            CreateBridge(myCoords, 1);
        }
        if (rooms[(int)myCoords.x, (int)myCoords.y + 1] != null)
        {
            list.Add("roof");
            CreateBridge(myCoords, 2);
        }
        if (rooms[(int)myCoords.x, (int)myCoords.y - 1] != null)
        {
            list.Add("floor");
            CreateBridge(myCoords, 3);
        }
        return list;
    }

    public void CreateBridge(Vector2 coords, int dir)
    {
        GameObject[] exi = new GameObject[2];

        switch (dir)
        {
            case 0:
                exi = GetExits(coords, coords + new Vector2(1, 0), "wallR", "wallL");
                if (exi[0] == null || exi[1] == null) break;
                if (exi[0].transform.position.y >= exi[1].transform.position.y)
                {
                    SpawnHorizontalCorridor(exi[0], exi[1]);
                }
                else
                {
                    SpawnHorizontalCorridor(exi[1], exi[0]);
                }
                break;
            case 1:
                exi = GetExits(coords, coords + new Vector2(-1, 0), "wallL", "wallR");
                if (exi[0] == null || exi[1] == null) break;
                if (exi[0].transform.position.y >= exi[1].transform.position.y)
                {
                    SpawnHorizontalCorridor(exi[0], exi[1]);
                }
                else
                {
                    SpawnHorizontalCorridor(exi[1], exi[0]);
                }
                break;
            case 2:
                exi = GetExits(coords, coords + new Vector2(0, 1), "roof", "floor");
                if (exi[0] == null || exi[1] == null) break;
                if (exi[0].transform.position.x >= exi[1].transform.position.x)
                {
                    SpawnVerticalCorridor(exi[1], exi[0]);
                }
                else
                {
                    SpawnVerticalCorridor(exi[0], exi[1]);
                }
                break;
            case 3:
                exi = GetExits(coords, coords + new Vector2(0, -1), "floor", "roof");
                if (exi[0] == null || exi[1] == null) break;
                if (exi[0].transform.position.x >= exi[1].transform.position.x)
                {
                    SpawnVerticalCorridor(exi[1], exi[0]);
                }
                else
                {
                    SpawnVerticalCorridor(exi[0], exi[1]);
                }
                break;
        }
    }

    void SpawnHorizontalCorridor(GameObject upper, GameObject bottom)
    {
        //Upper part spawn
        Vector3 c = new Vector3((upper.transform.position.x + bottom.transform.position.x) / 2 + upper.transform.localScale.x / 2,
                        upper.transform.position.y + upper.transform.localScale.y / 2 + corridorPrefab.transform.localScale.y / 2, upper.transform.position.z);
        GameObject t = Instantiate(corridorPrefab, c, Quaternion.identity);
        t.transform.localScale = new Vector3(Mathf.Abs(upper.transform.position.x - bottom.transform.position.x), 1, 1);


        //Bottom spawn
        c = new Vector3((upper.transform.position.x + bottom.transform.position.x) / 2 + upper.transform.localScale.x / 2,
            bottom.transform.position.y - bottom.transform.localScale.y / 2 - corridorPrefab.transform.localScale.y / 2, bottom.transform.position.z);
        t = Instantiate(corridorPrefab, c, Quaternion.identity);
        t.transform.localScale = new Vector3(Mathf.Abs(upper.transform.position.x - bottom.transform.position.x), 1, 1);
    }

    void SpawnVerticalCorridor(GameObject left, GameObject right)
    {
        //Left spawn
        Vector3 c = new Vector3(left.transform.position.x - left.transform.localScale.x/2 - corridorPrefab.transform.localScale.x/2, 
            (left.transform.position.y + right.transform.position.y)/2, left.transform.position.z);
        GameObject t = Instantiate(corridorPrefab, c, Quaternion.identity);
        t.transform.localScale = new Vector3(1, Mathf.Abs(left.transform.position.y - right.transform.position.y), 1);
        t.name = "Left";

        //Right spawn
        c = new Vector3(right.transform.position.x + right.transform.localScale.x / 2 + corridorPrefab.transform.localScale.x / 2,
            (left.transform.position.y + right.transform.position.y) / 2, right.transform.position.z);
        t = Instantiate(corridorPrefab, c, Quaternion.identity);
        t.transform.localScale = new Vector3(1, Mathf.Abs(left.transform.position.y - right.transform.position.y), 1);
        t.name = "Right";
    }

    GameObject[] GetExits(Vector2 coords1, Vector2 coords2,  string f, string s)
    {
        GameObject[] ret = new GameObject[2];
        foreach (ExitScript g in roomsInfos[(int)coords1.x, (int)coords1.y].exits)
        {
            if (g != null)
            {
                if (g.transform.parent.name == f)
                {
                    ret[0] = g.gameObject;
                }
            }
        }
        foreach (ExitScript g in roomsInfos[(int)coords2.x, (int)coords2.y].exits)
        {
            if (g != null)
            {
                if (g.transform.parent.name == s)
                {
                    ret[1] = g.gameObject;
                }
            }
        }
        return ret;
    }
}