using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Serialization; using Random = UnityEngine.Random; namespace Level.BuildModules { public class ProceduralPrefabs : MonoBehaviour { [FormerlySerializedAs("roomPrefabs")] public Room[] roomPrefabs; [FormerlySerializedAs("StartingRoom")] public Room startingRoom; private Room[,] _spawnedRooms; public int size = 32; private int _startCellX = 0; private int _startCellY = 0; private void Start() { _spawnedRooms = new Room[size, size]; _spawnedRooms[_startCellX, _startCellY] = startingRoom; for (int i = 0; i < size; i++) { // Это вот просто убрать чтобы подземелье генерировалось мгновенно на старте // yield return new WaitForSecondsRealtime(0.1f); PlaceOneRoom(); } } private void PlaceOneRoom() { HashSet vacantPlaces = new HashSet(); for (int x = 0; x < _spawnedRooms.GetLength(0); x++) { for (int y = 0; y < _spawnedRooms.GetLength(1); y++) { if (_spawnedRooms[x, y] == null) continue; int maxX = _spawnedRooms.GetLength(0) - 1; int maxY = _spawnedRooms.GetLength(1) - 1; AddVacantPlaceIfValid(x - 1, y, vacantPlaces); AddVacantPlaceIfValid(x, y - 1, vacantPlaces); AddVacantPlaceIfValid(x + 1, y, vacantPlaces); AddVacantPlaceIfValid(x, y + 1, vacantPlaces); } } Room newRoom = Instantiate(roomPrefabs[Random.Range(0, roomPrefabs.Length)]); int limit = 500; while (limit-- > 0) { Vector2Int position = vacantPlaces.ElementAt(Random.Range(0, vacantPlaces.Count)); // newRoom.RotateRandomly(); if (ConnectToSomething(newRoom, position)) { newRoom.transform.position = new Vector3(position.x - _startCellX, 0, position.y - _startCellY) * newRoom.roomSize; _spawnedRooms[position.x, position.y] = newRoom; return; } } Destroy(newRoom.gameObject); } private void AddVacantPlaceIfValid(int x, int y, HashSet vacantPlaces) { if (x >= 0 && x < _spawnedRooms.GetLength(0) && y >= 0 && y < _spawnedRooms.GetLength(1) && _spawnedRooms[x, y] == null) { vacantPlaces.Add(new Vector2Int(x, y)); } } private bool ConnectToSomething(Room room, Vector2Int p) { List neighbours = new List(); AddNeighbourIfValid(room.DoorU, p.x, p.y + 1, Vector2Int.up, neighbours); AddNeighbourIfValid(room.DoorD, p.x, p.y - 1, Vector2Int.down, neighbours); AddNeighbourIfValid(room.DoorR, p.x + 1, p.y, Vector2Int.right, neighbours); AddNeighbourIfValid(room.DoorL, p.x - 1, p.y, Vector2Int.left, neighbours); AddNeighbourIfValid(room.DoorU2, p.x, p.y + 1, Vector2Int.up, neighbours); AddNeighbourIfValid(room.DoorD2, p.x, p.y - 1, Vector2Int.down, neighbours); AddNeighbourIfValid(room.DoorR2, p.x + 1, p.y, Vector2Int.right, neighbours); AddNeighbourIfValid(room.DoorL2, p.x - 1, p.y, Vector2Int.left, neighbours); AddNeighbourIfValid(room.DoorU3, p.x, p.y + 1, Vector2Int.up, neighbours); AddNeighbourIfValid(room.DoorD3, p.x, p.y - 1, Vector2Int.down, neighbours); AddNeighbourIfValid(room.DoorR3, p.x + 1, p.y, Vector2Int.right, neighbours); AddNeighbourIfValid(room.DoorL3, p.x - 1, p.y, Vector2Int.left, neighbours); if (neighbours.Count == 0) return false; Vector2Int selectedDirection = neighbours[Random.Range(0, neighbours.Count)]; Room selectedRoom = _spawnedRooms[p.x + selectedDirection.x, p.y + selectedDirection.y]; DisableDoors(room, selectedRoom, selectedDirection); return true; } private void AddNeighbourIfValid(GameObject door, int x, int y, Vector2Int direction, List neighbours) { if (door != null && x >= 0 && x <= _spawnedRooms.GetLength(0) - 1 && y >= 0 && y <= _spawnedRooms.GetLength(1) - 1 && _spawnedRooms[x, y] != null) { neighbours.Add(direction); } } private void DisableDoors(Room room, Room selectedRoom, Vector2Int direction) { int rand = Random.Range(1, 4); if (direction == Vector2Int.up) { switch (rand) { case 1 : room.DoorU.SetActive(false); selectedRoom.DoorD.SetActive(false); break; case 2 : room.DoorU2.SetActive(false); selectedRoom.DoorD2.SetActive(false); break; case 3 : room.DoorU3.SetActive(false); selectedRoom.DoorD3.SetActive(false); break; } } else if (direction == Vector2Int.down) { switch (rand) { case 1 : room.DoorD.SetActive(false); selectedRoom.DoorU.SetActive(false); break; case 2 : room.DoorD2.SetActive(false); selectedRoom.DoorU2.SetActive(false); break; case 3 : room.DoorD3.SetActive(false); selectedRoom.DoorU3.SetActive(false); break; } } else if (direction == Vector2Int.right) { switch (rand) { case 1 : room.DoorR.SetActive(false); selectedRoom.DoorL.SetActive(false); break; case 2 : room.DoorR2.SetActive(false); selectedRoom.DoorL2.SetActive(false); break; case 3 : room.DoorR3.SetActive(false); selectedRoom.DoorL3.SetActive(false); break; } } else if (direction == Vector2Int.left) { switch (rand) { case 1 : room.DoorL.SetActive(false); selectedRoom.DoorR.SetActive(false); break; case 2 : room.DoorL2.SetActive(false); selectedRoom.DoorR2.SetActive(false); break; case 3 : room.DoorL3.SetActive(false); selectedRoom.DoorR3.SetActive(false); break; } } } } }