Created
January 14, 2024 02:13
-
-
Save pppoe252110/066f4b3de6424ea04d9527bc37593130 to your computer and use it in GitHub Desktop.
Dungeon Rooms Proceed Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEngine; | |
public class DungeonCell : MonoBehaviour | |
{ | |
public List<int> connections = new List<int>(); | |
public int roomId = -1; | |
public Transform leftWall; | |
public Transform rightWall; | |
public Transform forwardWall; | |
public Transform backWall; | |
public Transform centerFloor; | |
public Transform centerCeiling; | |
public bool leftSet; | |
public bool rightSet; | |
public bool forwardSet; | |
public bool backSet; | |
public void SetLeftWall(GameObject obj) | |
{ | |
leftSet = true; | |
obj.transform.parent = leftWall; | |
} | |
public void SetRightWall(GameObject obj) | |
{ | |
rightSet = true; | |
obj.transform.parent = rightWall; | |
} | |
public void SetForwardWall(GameObject obj) | |
{ | |
forwardSet = true; | |
obj.transform.parent = forwardWall; | |
} | |
public void SetBackWall(GameObject obj) | |
{ | |
backSet = true; | |
obj.transform.parent = backWall; | |
} | |
public void SetCenterFloor(GameObject obj) | |
{ | |
obj.transform.parent = centerFloor; | |
} | |
public void SetCenterCeiling(GameObject obj) | |
{ | |
obj.transform.parent = centerCeiling; | |
} | |
//private void OnDrawGizmos() | |
//{ | |
// Random.InitState(roomId); | |
// Gizmos.color = Random.ColorHSV(); | |
// Gizmos.DrawCube( | |
// new Vector3(centerWall.transform.position.x, centerWall.transform.position.y, centerWall.transform.position.z), | |
// new Vector3(2.5f, 0, 2.5f)); | |
//} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Sirenix.OdinInspector; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using UnityEditor; | |
using UnityEngine; | |
public class DungeonGenerator : MonoBehaviour | |
{ | |
[Title("Prefabs", "Prefabs and room parts", TitleAlignments.Centered)] | |
[SerializeField] private DungeonCell _cellPrefab; | |
[SerializeField] private DungeonRoomData[] _roomsData; | |
[TitleGroup("Generation", "Seed and rooms properies", TitleAlignments.Centered)] | |
[Title("Randomization")] | |
[SerializeField] private int seed = 1; | |
[Title("Room Properties")] | |
[SerializeField] private Vector3 _roomSize = new Vector3(5, 5, 5); | |
[SerializeField] private Vector3Int _roomBoundsMin = new Vector3Int(2, 0, 2); | |
[SerializeField] private Vector3Int _roomBoundsMax = new Vector3Int(5, 0, 5); | |
[SerializeField] private Dictionary<Vector3Int, DungeonCell> _cells; | |
[Min(1)] | |
[SerializeField] private int _width = 10; | |
[Min(1)] | |
[SerializeField] private int _length = 10; | |
[Title("Room Joining", "Joining rooms", TitleAlignments.Centered)] | |
[SerializeField] private bool _joinSmallRooms = false; | |
[Min(1)] | |
[SerializeField] private int _maxRoomCellsJoin = 4; | |
[Sirenix.OdinInspector.DisplayAsString()] | |
private string lastMS; | |
private void Start() | |
{ | |
Clear(); | |
GenerateWithNewSeed(); | |
} | |
[Button] | |
private void JustGenerate() | |
{ | |
Generate(); | |
} | |
[Button] | |
private void GenerateWithNewSeed() | |
{ | |
seed++; | |
Generate(); | |
} | |
[Button] | |
private void Clear() | |
{ | |
#if UNITY_EDITOR | |
if (!Application.isPlaying) | |
{ | |
EditorApplication.delayCall += delegate | |
{ | |
for (int i = transform.childCount - 1; i >= 0; i--) | |
{ | |
DestroyImmediate(transform.GetChild(i).gameObject); | |
} | |
}; | |
_cells = new Dictionary<Vector3Int, DungeonCell>(); | |
return; | |
} | |
#endif | |
for (int i = transform.childCount - 1; i >= 0; i--) | |
{ | |
Destroy(transform.GetChild(i).gameObject); | |
} | |
_cells = new Dictionary<Vector3Int, DungeonCell>(); | |
} | |
private void Generate() | |
{ | |
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); | |
stopwatch.Start(); | |
int id = 0; | |
int itterations = 0; | |
if (_cells?.Count > 0) | |
{ | |
var cells = _cells.Values.ToArray(); | |
for (int i = 0; i < cells.Length; i++) | |
{ | |
if (cells[i] != null) | |
DestroyImmediate(cells[i]?.gameObject); | |
} | |
} | |
_cells = new Dictionary<Vector3Int, DungeonCell>(); | |
Random.InitState(seed); | |
for (int x = 0; x < _width; x++) | |
{ | |
for (int z = 0; z < _length; z++) | |
{ | |
var pos = new Vector3(x * _roomSize.x + _roomSize.x / 2f, _roomSize.y / 2f, z * _roomSize.z + _roomSize.z / 2f); | |
var cell = Instantiate(_cellPrefab, pos, Quaternion.identity); | |
cell.transform.parent = transform; | |
_cells.Add(new Vector3Int(x, 0, z), cell); | |
} | |
} | |
List<DungeonCell> freeCells = _cells.Values.ToList(); | |
while (freeCells.Count > 0) | |
{ | |
if (itterations >= _width * _length) | |
{ | |
//Debug.Log("PIZDEC"); | |
break; | |
} | |
var rCell = freeCells[Random.Range(0, freeCells.Count)]; | |
var cellPos = _cells.First(s => s.Value == rCell).Key; | |
var maxWidth = Random.Range(_roomBoundsMin.x, _roomBoundsMax.x + 1); | |
var maxLength = Random.Range(_roomBoundsMin.z, _roomBoundsMax.z + 1); | |
Vector3Int max = GetRoomMaxBound(cellPos, maxWidth, maxLength); | |
for (int x = 0; x < max.x; x++) | |
{ | |
for (int z = 0; z < max.z; z++) | |
{ | |
var targetCell = _cells.GetValueOrDefault(new Vector3Int(cellPos.x + x, cellPos.y, cellPos.z + z)); | |
targetCell.roomId = id; | |
freeCells.Remove(targetCell); | |
} | |
} | |
itterations++; | |
id++; | |
} | |
if (_joinSmallRooms) | |
{ | |
JoinRooms(); | |
} | |
GenerateDoors(); | |
GenerateWalls(); | |
GenerateFloor(); | |
GenerateCeiling(); | |
stopwatch.Stop(); | |
lastMS = stopwatch.ElapsedMilliseconds.ToString(); | |
Debug.Log(stopwatch.ElapsedMilliseconds + "ms"); | |
} | |
public void JoinRooms() | |
{ | |
var rooms = _cells.GroupBy(s => s.Value.roomId).Where(s => s.Count() <= _maxRoomCellsJoin).ToList(); | |
for (int i = 0; i < rooms.Count; i++) | |
{ | |
foreach (var room in rooms[i]) | |
{ | |
if (_cells.TryGetValue(new Vector3Int(room.Key.x + 1, room.Key.y, room.Key.z), out var rightCell)) | |
{ | |
if (rooms.Any(s => s.Any(a => a.Value == rightCell && a.Value.roomId != room.Value.roomId))) | |
{ | |
var cellsToJoin = _cells.Where(s => s.Value.roomId == rightCell.roomId); | |
foreach (var item in cellsToJoin) | |
{ | |
item.Value.roomId = room.Value.roomId; | |
} | |
} | |
} | |
if (_cells.TryGetValue(new Vector3Int(room.Key.x, room.Key.y, room.Key.z + 1), out var forwardCell)) | |
{ | |
if (rooms.Any(s => s.Any(a => a.Value == forwardCell && a.Value.roomId != room.Value.roomId))) | |
{ | |
var cellsToJoin = _cells.Where(s => s.Value.roomId == forwardCell.roomId); | |
foreach (var item in cellsToJoin) | |
{ | |
item.Value.roomId = room.Value.roomId; | |
} | |
} | |
} | |
} | |
} | |
} | |
public Vector3Int GetRoomMaxBound(Vector3Int cellPos, int maxWidth, int maxLength) | |
{ | |
int resultWidth = maxWidth; | |
int resultLength = maxLength; | |
List<List<Vector3Int>> results = new List<List<Vector3Int>>(); | |
for (int x = 0; x < resultWidth; x++) | |
{ | |
for (int z = 0; z < resultLength; z++) | |
{ | |
var targetX = x; | |
var targetZ = z; | |
if (x + cellPos.x >= _width) | |
{ | |
targetX = _width - cellPos.x - 1; | |
} | |
if (z + cellPos.z >= _length) | |
{ | |
targetZ = _length - cellPos.z - 1; | |
} | |
if (GetFreeCells(targetX, targetZ, cellPos, out var cells)) | |
{ | |
results.Add(cells); | |
} | |
} | |
} | |
var max = results.OrderByDescending(x => x.Count).First().OrderByDescending(s => s.x + s.z).First(); | |
return max; | |
} | |
public bool GetFreeCells(int x, int z, Vector3Int cellPos, out List<Vector3Int> cells) | |
{ | |
List<Vector3Int> checkCells = new List<Vector3Int>(); | |
for (int x1 = 0; x1 <= x; x1++) | |
{ | |
for (int z1 = 0; z1 <= z; z1++) | |
{ | |
var freeCell = _cells.GetValueOrDefault(new Vector3Int(cellPos.x + x1, 0, cellPos.z + z1)); | |
if (freeCell.roomId != -1) | |
{ | |
cells = null; | |
return false; | |
} | |
else | |
{ | |
checkCells.Add(new Vector3Int(x1 + 1, 0, z1 + 1)); | |
} | |
} | |
} | |
cells = checkCells; | |
return true; | |
} | |
public void GenerateFloor() | |
{ | |
for (int x = 0; x < _width; x++) | |
{ | |
for (int z = 0; z < _length; z++) | |
{ | |
if (_cells.TryGetValue(new Vector3Int(x, 0, z), out var cell)) | |
{ | |
var floor = Instantiate(_roomsData[0].floorPrefab, cell.centerFloor.position, cell.centerFloor.rotation); | |
cell.SetCenterFloor(floor); | |
} | |
} | |
} | |
} | |
public void GenerateCeiling() | |
{ | |
for (int x = 0; x < _width; x++) | |
{ | |
for (int z = 0; z < _length; z++) | |
{ | |
if (_cells.TryGetValue(new Vector3Int(x, 0, z), out var cell)) | |
{ | |
var ceiling = Instantiate(_roomsData[0].ceilingPrefab, cell.centerCeiling.position, cell.centerCeiling.rotation); | |
cell.SetCenterFloor(ceiling); | |
} | |
} | |
} | |
} | |
public void GenerateDoors() | |
{ | |
var rooms = _cells.GroupBy(s => s.Value.roomId).ToList(); | |
for (int i = 0; i < rooms.Count; i++) | |
{ | |
foreach (var room in rooms[i]) | |
{ | |
if (_cells.TryGetValue(new Vector3Int(room.Key.x + 1, room.Key.y, room.Key.z), out var rightCell)) | |
{ | |
if (room.Value.roomId != rightCell.roomId && | |
!_cells.Where(s => s.Value.roomId == room.Value.roomId).Any(s => s.Value.connections.Contains(room.Value.roomId))) | |
{ | |
var wall = Instantiate(_roomsData[0].doorPrefab, room.Value.rightWall.position, room.Value.rightWall.rotation); | |
room.Value.SetRightWall(wall); | |
room.Value.connections.Add(room.Value.roomId); | |
} | |
} | |
if (_cells.TryGetValue(new Vector3Int(room.Key.x, room.Key.y, room.Key.z + 1), out var forwardCell)) | |
{ | |
if (room.Value.roomId != forwardCell.roomId && | |
!_cells.Where(s => s.Value.roomId == room.Value.roomId).Any(s => s.Value.connections.Contains(room.Value.roomId))) | |
{ | |
var wall = Instantiate(_roomsData[0].doorPrefab, room.Value.forwardWall.position, room.Value.forwardWall.rotation); | |
room.Value.SetForwardWall(wall); | |
room.Value.connections.Add(room.Value.roomId); | |
} | |
} | |
} | |
} | |
} | |
public void GenerateWalls() | |
{ | |
for (int x = 0; x < _width; x++) | |
{ | |
for (int z = 0; z < _length; z++) | |
{ | |
var cell = _cells.GetValueOrDefault(new Vector3Int(x, 0, z)); | |
if (_cells.TryGetValue(new Vector3Int(x, 0, z + 1), out var cellF) && cell.roomId != cellF.roomId) | |
{ | |
if (!cell.forwardSet) | |
{ | |
var wall = Instantiate(_roomsData[0].wallPrefab, cell.forwardWall.position, cell.forwardWall.rotation); | |
cell.SetForwardWall(wall); | |
} | |
} | |
if (_cells.TryGetValue(new Vector3Int(x + 1, 0, z), out var cellR) && cell.roomId != cellR.roomId) | |
{ | |
if (!cell.rightSet) | |
{ | |
var wall = Instantiate(_roomsData[0].wallPrefab, cell.rightWall.position, cell.rightWall.rotation); | |
cell.SetRightWall(wall); | |
} | |
} | |
if (!_cells.GetValueOrDefault(new Vector3Int(x, 0, z + 1))) | |
{ | |
if (!cell.forwardSet) | |
{ | |
var wall = Instantiate(_roomsData[0].wallPrefab, cell.forwardWall.position, cell.forwardWall.rotation); | |
cell.SetForwardWall(wall); | |
} | |
} | |
if (!_cells.GetValueOrDefault(new Vector3Int(x + 1, 0, z))) | |
{ | |
if (!cell.rightSet) | |
{ | |
var wall = Instantiate(_roomsData[0].wallPrefab, cell.rightWall.position, cell.rightWall.rotation); | |
cell.SetRightWall(wall); | |
} | |
} | |
if (!_cells.GetValueOrDefault(new Vector3Int(x, 0, z - 1))) | |
{ | |
if (!cell.backSet) | |
{ | |
var wall = Instantiate(_roomsData[0].wallPrefab, cell.backWall.position, cell.backWall.rotation); | |
cell.SetBackWall(wall); | |
} | |
} | |
if (!_cells.GetValueOrDefault(new Vector3Int(x - 1, 0, z))) | |
{ | |
if (!cell.leftSet) | |
{ | |
var wall = Instantiate(_roomsData[0].wallPrefab, cell.leftWall.position, cell.leftWall.rotation); | |
cell.SetLeftWall(wall); | |
} | |
} | |
} | |
} | |
} | |
//public Vector3Int GetRoomMaxBound(Vector3Int cellPos, int maxWidth, int maxLength) | |
//{ | |
// int resultWidth = maxWidth; | |
// int resultLength = maxLength; | |
// Vector3Int lastCheckPos = Vector3Int.zero; | |
// for (int x = 0; x < resultWidth; x++) | |
// { | |
// for (int z = 0; z < resultLength; z++) | |
// { | |
// if (x + cellPos.x >= _width) | |
// { | |
// resultWidth = x; | |
// break; | |
// } | |
// if (z + cellPos.z >= _length) | |
// { | |
// resultLength = z; | |
// break; | |
// } | |
// var freeCell = _cells.GetValueOrDefault(new Vector3Int(x + cellPos.x, cellPos.y, z + cellPos.z)); | |
// if (freeCell.roomId != -1) | |
// { | |
// if (lastCheckPos.x < x) | |
// resultWidth = Mathf.Min(x, resultWidth); | |
// if (lastCheckPos.z < z) | |
// resultLength = Mathf.Min(z, resultLength); | |
// } | |
// lastCheckPos = new Vector3Int(x, 0, z); | |
// } | |
// } | |
// return new Vector3Int(resultWidth, 0, resultLength); | |
//} | |
private void OnDrawGizmos() | |
{ | |
if (_cells != null && _cells.Count > 0) | |
for (int x = 0; x < _width; x++) | |
{ | |
for (int z = 0; z < _length; z++) | |
{ | |
if (_cells.TryGetValue(new Vector3Int(x, 0, z), out var cell)) | |
{ | |
Random.InitState(cell.roomId); | |
Gizmos.color = Random.ColorHSV(); | |
Gizmos.DrawCube(new Vector3(x * _roomSize.x + _roomSize.x / 2f, 0, z * _roomSize.z + _roomSize.z / 2f), new Vector3(_roomSize.x, 0.1f, _roomSize.z)); | |
} | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
[System.Serializable] | |
public class DungeonRoomData | |
{ | |
public GameObject wallPrefab; | |
public GameObject doorPrefab; | |
public GameObject floorPrefab; | |
public GameObject ceilingPrefab; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment