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; } }