Hi All. I am stuck at this point. here is the code for anybody to use and maybe optimize and Post back here. Currently it is ending like this. Outer wall to thick if a wall is there. No doors ( Raycast maybe from the middle of the room to each side and look for a hallway? of none is found by each side the room is in the middle of other rooms. Then maybe pick a direction and place a door?
using UnityEngine;
using UnityEngine.Tilemaps;
using System.Collections;
using System.Collections.Generic;
public class DungeonGenerator : MonoBehaviour {
enum gridSpace { empty, _base, floor, wall, resource };
gridSpace[,] grid;
public int roomWidth, roomHeight;
[Range (0, 6)]
public int numberOfIterations;
[Range (1, 4)]
public int corridorThickness;
public bool shouldDebugDrawBsp;
public Tile debugTile,halwayTile,wallTile,doorTile;
public const int MIN_ROOM_DELTA = 3;
public Tilemap map;
public Tilemap roomMap;
private BspTree tree;
//public List<Vector4> roomList = new List<Vector4>();
public List<BspTree> rooms = new List<BspTree>();
// Use this for initialization
void Start () {
}
void OnDrawGizmos () {
AttemptDebugDrawBsp ();
AttemptDebugDrawBspRooms();
}
private void OnDrawGizmosSelected () {
AttemptDebugDrawBsp ();
AttemptDebugDrawBspRooms();
}
void AttemptDebugDrawBsp () {
if (shouldDebugDrawBsp) {
DebugDrawBsp ();
}
}
void AttemptDebugDrawBspRooms()
{
if (shouldDebugDrawBsp)
{
DebugDrawBspRooms();
}
}
public void DebugDrawBsp () {
if (tree == null) return; // hasn't been generated yet
DebugDrawBspNode (tree); // recursive call
}
public void DebugDrawBspNode (BspTree node) {
// Container
Gizmos.color = Color.green;
// top
Gizmos.DrawLine (new Vector3 (node.container.x, node.container.y, 0), new Vector3Int (node.container.xMax, node.container.y, 0));
// right
Gizmos.DrawLine (new Vector3 (node.container.xMax, node.container.y, 0), new Vector3Int (node.container.xMax, node.container.yMax, 0));
// bottom
Gizmos.DrawLine (new Vector3 (node.container.x, node.container.yMax, 0), new Vector3Int (node.container.xMax, node.container.yMax, 0));
// left
Gizmos.DrawLine (new Vector3 (node.container.x, node.container.y, 0), new Vector3Int (node.container.x, node.container.yMax, 0));
// children
if (node.left != null) DebugDrawBspNode (node.left);
if (node.right != null) DebugDrawBspNode (node.right);
}
public void DebugDrawBspRooms()
{
for (int i = 0; i < rooms.Count; i++)
{
if (rooms[i] == null) return; // hasn't been generated yet
DebugDrawBspNodeRooms(rooms[i]); // recursive call
}
}
public void DebugDrawBspNodeRooms(BspTree node)
{
// Container
Gizmos.color = Color.blue;
// top
Gizmos.DrawLine(new Vector3(node.container.x, node.container.y, 0), new Vector3Int(node.container.xMax, node.container.y, 0));
// right
Gizmos.DrawLine(new Vector3(node.container.xMax, node.container.y, 0), new Vector3Int(node.container.xMax, node.container.yMax, 0));
// bottom
Gizmos.DrawLine(new Vector3(node.container.x, node.container.yMax, 0), new Vector3Int(node.container.xMax, node.container.yMax, 0));
// left
Gizmos.DrawLine(new Vector3(node.container.x, node.container.y, 0), new Vector3Int(node.container.x, node.container.yMax, 0));
// children
if (node.left != null) DebugDrawBspNodeRooms(node.left);
if (node.right != null) DebugDrawBspNodeRooms(node.right);
}
private void InitReferences () {
map.ClearAllTiles ();
roomMap.ClearAllTiles();
rooms.Clear();
// roomList.Clear();
Random.InitState(Random.Range(0,9999999));
}
private void GenerateRoomsInsideContainers () {
BspTree.GenerateRoomsInsideContainersNode (tree);
}
private void GenerateContainersUsingBsp()
{
tree = BspTree.Split(numberOfIterations, new RectInt(0, 0, roomWidth, roomHeight));
//Add for Debugging
}
private void UpdateTilemapUsingTreeNode (BspTree node) {
if (node.left == null && node.right == null) {
for (int i = node.room.x; i < node.room.xMax; i++) {
for (int j = node.room.y; j < node.room.yMax; j++) {
grid[i, j] = gridSpace.wall; //Fill Big Room With Wall. Smaller Room will remove Walls
// map.SetTile (new Vector3Int (i, j, 0), debugTile);
}
}
} else {
if (node.left != null) UpdateTilemapUsingTreeNode (node.left);
if (node.right != null) UpdateTilemapUsingTreeNode (node.right);
}
}
private void FillRoomsOnTilemap () {
UpdateTilemapUsingTreeNode (tree);
}
void SpawnLevel()
{
Debug.Log("Spawn ");
for (int x = 0; x < roomWidth; x++)
{
for (int y = 0; y < roomHeight; y++)
{
switch (grid[x, y])
{
case gridSpace.empty:
break;
case gridSpace.floor:
map.SetTile(new Vector3Int(x, y, 0), halwayTile);
break;
case gridSpace._base:
map.SetTile(new Vector3Int(x, y, 0), debugTile);
break;
case gridSpace.wall:
map.SetTile(new Vector3Int(x, y, 0), wallTile);
break;
case gridSpace.resource:
break;
}
}
}
}
void WallsBarrier()
{
for (int x = 0; x < roomWidth; x++)
{
for (int y = 0; y < 2; y++)
{
{
//if Raam sont fill ?????
grid[x, y] = gridSpace.wall;
}
}
}
for (int x = 0; x < roomWidth; x++)
{
for (int y = roomHeight - 1; y > (roomHeight - 3); y--)
{
{
//if Raam sont fill ?????
grid[x, y] = gridSpace.wall;
}
}
}
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < roomHeight; y++)
{
{
//if Raam sont fill ?????
grid[x, y] = gridSpace.wall;
}
}
}
for (int x = roomWidth - 1; x > (roomWidth - 3); x--)
{
for (int y = 0; y < roomHeight; y++)
{
{
//if Raam sont fill ?????
grid[x, y] = gridSpace.wall;
}
}
}
}
private void GenerateCorridors()
{
// for each parent
// find their center
// find a direction and connect these centers
GenerateCorridorsNode(tree);
}
private void GenerateCorridorsNode(BspTree node)
{
print('a');
if (node.IsInternal())
{
print('b');
RectInt leftContainer = node.left.container;
RectInt rightContainer = node.right.container;
Vector2 leftCenter = leftContainer.center;
Vector2 rightCenter = rightContainer.center;
Vector2 direction = (rightCenter - leftCenter).normalized; // arbitrarily choosing right as the target point
while (Vector2.Distance(leftCenter, rightCenter) > 1)
{
if (direction.Equals(Vector2.right))
{
for (int i = 0; i < corridorThickness; i++)
{
//map.SetTile(new Vector3Int((int)leftCenter.x, (int)leftCenter.y + i, 0), wallTile);
grid[(int)leftCenter.x, (int)leftCenter.y + i] = gridSpace.wall;
}
}
else if (direction.Equals(Vector2.up))
{
for (int i = 0; i < corridorThickness; i++)
{
// map.SetTile(new Vector3Int((int)leftCenter.x + i, (int)leftCenter.y, 0), wallTile);
grid[(int)leftCenter.x + i, (int)leftCenter.y]= gridSpace.wall;
}
}
leftCenter.x += direction.x;
leftCenter.y += direction.y;
}
if (node.left != null) GenerateCorridorsNode(node.left);
if (node.right != null) GenerateCorridorsNode(node.right);
}
}
public void GenerateDungeon () {
grid = new gridSpace[roomWidth, roomHeight];
//set grid's default state
for (int x = 0; x < roomWidth; x++)
{
for (int y = 0; y < roomHeight; y++)
{
//make every cell "empty"
grid[x, y] = gridSpace.floor; //Replace with Empty
}
}
//Create Floor
InitReferences ();
GenerateContainersUsingBsp ();
GenerateRoomsInsideContainers ();//Grphics
FillRoomsOnTilemap();
//Create Rooms ins Froor Space
GenerateRoomsUsingBsp(tree);
GenerateSmallRoomsInsideContainers();
FillSmaalRoomsOnTilemap();
FixWalls();
WallsBarrier();
// GenerateCorridors();
SpawnLevel();
Debug.Log(rooms.Count);
}
private void GenerateRoomsUsingBsp(BspTree node)
{
if (node.left == null && node.right == null)
{
GenerateRoomsUsingBsp(node.container.x+2, node.container.y+2, node.container.width-2, node.container.height-2);
// map.SetTile (new Vector3Int (i, j, 0), debugTile);
}
else
{
if (node.left != null) GenerateRoomsUsingBsp(node.left);
if (node.right != null) GenerateRoomsUsingBsp(node.right);
}
}
private void GenerateRoomsUsingBsp(int startX, int startY, int width, int height )
{
Debug.Log(" Creating Room ");
BspTree newroom = BspTree.Split(2, new RectInt(startX, startY, width-2, height-2));
// roomList.Add(new Vector4(startX, startY, width - 2, height - 2));
// public List<PersonsData> Persons = new List<PersonsData>();
rooms.Add(newroom);
}
// private void GenerateSmallRoomsInsideContainers()
// {
// BspTree.GenerateRoomsInsideContainersNode(tree);
// }
void GenerateSmallRoomsInsideContainers()
{
for (int i = 0; i < rooms.Count; i++)
{
if (rooms[i] == null) return; // hasn't been generated yet
BspTree.GenerateSmallRoomsInsideContainersNode(rooms[i]);
}
}
void UpdateTilemapForRoomUsingTreeNode(BspTree node)
{
if (node.left == null && node.right == null)
{
for (int i = node.room.x; i < node.room.xMax; i++)
{
for (int j = node.room.y; j < node.room.yMax; j++)
{
grid[i, j] = gridSpace._base;
// map.SetTile (new Vector3Int (i, j, 0), debugTile);
}
}
}
else
{
if (node.left != null) UpdateTilemapForRoomUsingTreeNode(node.left);
if (node.right != null) UpdateTilemapForRoomUsingTreeNode(node.right);
}
}
private void FillSmaalRoomsOnTilemap()
{
for (int i = 0; i < rooms.Count; i++)
{
if (rooms[i] == null) return; // hasn't been generated yet
UpdateTilemapForRoomUsingTreeNode(rooms[i]);
}
}
void FixWalls() //Remove if Double Wall
{
for (int x = 3; x < roomWidth - 3; x++)
{
for (int y = 3; y < roomHeight - 3; y++)
{
if (grid[x, y] == gridSpace.wall && grid[x , y+1] == gridSpace.wall && grid[x-1, y] == gridSpace.wall&& grid[x, y-1] == gridSpace._base )
{
grid[x, y] = gridSpace._base;
}
}
}
}
}
using System;
using UnityEngine;
public class BspTree {
public RectInt container;
public RectInt room;
public BspTree left;
public BspTree right;
public BspTree (RectInt container) {
this.container = container;
}
public bool IsLeaf () {
return left == null && right == null;
}
public bool IsInternal() {
return left != null || right != null;
}
internal static BspTree Split (int numberOfIterations, RectInt container) {
var node = new BspTree (container);
if (numberOfIterations == 0) return node;
if (container.width > 25 && container.height > 25) //Min Room Size
{
var splittedContainers = SplitContainer(container);
node.left = Split(numberOfIterations - 1, splittedContainers[0]);
node.right = Split(numberOfIterations - 1, splittedContainers[1]);
}
return node;
}
private static RectInt[] SplitContainer (RectInt container) {
RectInt c1, c2;
//if (UnityEngine.Random.Range (0f, 1f) > 0.5f)
if (container.width < container.height)
{
// vertical
c1 = new RectInt (container.x, container.y, container.width, (int) UnityEngine.Random.Range (container.height * 0.3f, container.height * 0.7f));
c2 = new RectInt (container.x, container.y + c1.height, container.width, container.height - c1.height);
} else {
// horizontal
c1 = new RectInt (container.x, container.y, (int) UnityEngine.Random.Range (container.width * 0.3f, container.width * 0.7f), container.height);
c2 = new RectInt (container.x + c1.width, container.y, container.width - c1.width, container.height);
}
return new RectInt[] { c1, c2 };
}
public static void GenerateRoomsInsideContainersNode(BspTree node)
{
// should create rooms for leafs
if (node.IsLeaf()) {
//var randomX = UnityEngine.Random.Range(DungeonGenerator.MIN_ROOM_DELTA, node.container.width / 4);
// var randomY = UnityEngine.Random.Range(DungeonGenerator.MIN_ROOM_DELTA, node.container.height / 4);
int roomX = node.container.x+2;// + randomX;
int roomY = node.container.y+2;// + randomY;
int roomW = node.container.width - 4;// (int) (randomX * UnityEngine.Random.Range(1f, 2f));
int roomH = node.container.height - 4;// (int) (randomY * UnityEngine.Random.Range(1f, 2f));
node.room = new RectInt(roomX, roomY, roomW, roomH);
} else {
if (node.left != null) GenerateRoomsInsideContainersNode(node.left);
if (node.right != null) GenerateRoomsInsideContainersNode(node.right);
}
}
public static void GenerateSmallRoomsInsideContainersNode(BspTree node)
{
// should create rooms for leafs
if (node.IsLeaf())
{
//var randomX = UnityEngine.Random.Range(DungeonGenerator.MIN_ROOM_DELTA, node.container.width / 4);
// var randomY = UnityEngine.Random.Range(DungeonGenerator.MIN_ROOM_DELTA, node.container.height / 4);
int roomX = node.container.x +1;// + randomX;
int roomY = node.container.y + 1;// + randomY;
int roomW = node.container.width - 2;// (int) (randomX * UnityEngine.Random.Range(1f, 2f));
int roomH = node.container.height - 2;// (int) (randomY * UnityEngine.Random.Range(1f, 2f));
node.room = new RectInt(roomX, roomY, roomW, roomH);
}
else
{
if (node.left != null) GenerateSmallRoomsInsideContainersNode(node.left);
if (node.right != null) GenerateSmallRoomsInsideContainersNode(node.right);
}
}
}
Editor script for Editor folder
using UnityEditor;
using UnityEngine;
[CustomEditor (typeof (DungeonGenerator))]
public class DungeonGeneratorEditor : Editor {
bool showTiles = true;
void OnEnable () {
}
public override void OnInspectorGUI () {
DrawDefaultInspector ();
DungeonGenerator myScript = (DungeonGenerator) target;
if (GUILayout.Button ("Generate Dungeon")) {
myScript.GenerateDungeon ();
}
}
}