Last active
November 21, 2020 13:09
-
-
Save Ratstail91/71a1ac59f82494467d7311568d07f726 to your computer and use it in GitHub Desktop.
Incomplete dungeon generator - only implements binary space partitioning right now.
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; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class DungeonGenerator : MonoBehaviour { | |
//parameters | |
public int dungeonWidth = 100; | |
public int dungeonHeight = 100; | |
public int terminationThreshold = 10; | |
//structures | |
enum Direction { | |
VERTICAL = 0, HORIZONTAL = 1 | |
} | |
enum TileType { | |
WALL = 0, EMPTY, ROOM | |
} | |
//lifecycle methods | |
int frameIndex = 0; | |
TileType[,] dungeonTileData = null; | |
void FixedUpdate() { | |
if (++frameIndex % 30 == 0) { | |
dungeonTileData = GenerateTileData(dungeonWidth, dungeonHeight); | |
} | |
} | |
void OnDrawGizmos() { | |
if (dungeonTileData != null) { | |
for (int i = 0; i < dungeonWidth; i++) { | |
for (int j = 0; j < dungeonHeight; j++) { | |
switch(dungeonTileData[i, j]) { | |
case TileType.WALL: | |
Gizmos.color = Color.grey; | |
Gizmos.DrawCube(new Vector3(i - dungeonWidth / 2, j - dungeonHeight / 2, 0), new Vector3(1, 1, 1)); | |
break; | |
case TileType.EMPTY: | |
Gizmos.color = Color.white; | |
Gizmos.DrawCube(new Vector3(i - dungeonWidth / 2, j - dungeonHeight / 2, 0), new Vector3(1, 1, 1)); | |
break; | |
case TileType.ROOM: | |
Gizmos.color = Color.blue; | |
Gizmos.DrawCube(new Vector3(i - dungeonWidth / 2, j - dungeonHeight / 2, 0), new Vector3(1, 1, 1)); | |
break; | |
} | |
} | |
} | |
} | |
} | |
//generation methods | |
TileType[,] GenerateTileData(int width, int height) { | |
TileType[,] tileData = new TileType[width, height]; | |
//zero the array | |
for (int i = 0; i < width; i++) { | |
for (int j = 0; j < height; j++) { | |
tileData[i, j] = TileType.WALL; | |
} | |
} | |
PartitionSpace(0, 0, width, height, ref tileData); | |
return tileData; | |
} | |
Vector2Int PartitionSpace(int x1, int y1, int x2, int y2, ref TileType[,] tileData) { | |
//calc the width & height | |
int width = x2 - x1; | |
int height = y2 - y1; | |
//check the termination threshold | |
if (width <= terminationThreshold || height <= terminationThreshold) { | |
//draw the box | |
return GenerateRoom(x1, y1, x2, y2, ref tileData); | |
} | |
//get the partition direction | |
Direction direction; | |
if (width == height) { | |
direction = (Direction)Random.Range(0, 2); | |
} else { | |
direction = (Direction)(height < width ? Direction.VERTICAL : Direction.HORIZONTAL); | |
} | |
//split the partition in the middle third | |
switch (direction) { | |
case Direction.VERTICAL: { | |
int splitPos = Random.Range(width/3, (width/3) * 2); | |
Vector2Int a = PartitionSpace(x1, y1, x1 + splitPos, y2, ref tileData); | |
Vector2Int b = PartitionSpace(x1 + splitPos + 1, y1, x2, y2, ref tileData); | |
return GenerateCorridor(a, b, ref tileData); | |
} | |
case Direction.HORIZONTAL: { | |
int splitPos = Random.Range(height/3, (height/3) * 2); | |
Vector2Int a = PartitionSpace(x1, y1, x2, y1 + splitPos, ref tileData); | |
Vector2Int b = PartitionSpace(x1, y1 + splitPos + 1, x2, y2, ref tileData); | |
return GenerateCorridor(a, b, ref tileData); | |
} | |
} | |
throw new System.InvalidOperationException("Unreachable"); | |
} | |
Vector2Int GenerateRoom(int x1, int y1, int x2, int y2, ref TileType[,] tileData) { | |
//calc the partition width & height | |
int width = x2 - x1; | |
int height = y2 - y1; | |
//TODO: prefab room chance | |
//room bounds | |
int xBegin = Random.Range(x1 + 1, x1 + width/2); | |
int xEnd = Random.Range(x1 + width/2 + 1, x2 - 1); | |
int yBegin = Random.Range(y1 + 1, y1 + height/2); | |
int yEnd = Random.Range(y1 + height/2 + 1, y2 - 1); | |
for (int i = xBegin; i <= xEnd; i++) { | |
for (int j = yBegin; j <= yEnd; j++) { | |
tileData[i, j] = TileType.ROOM; | |
} | |
} | |
return new Vector2Int(Random.Range(xBegin, xEnd + 1), Random.Range(yBegin, yEnd + 1)); | |
} | |
Vector2Int GenerateCorridor(Vector2Int a, Vector2Int b, ref TileType[,] tileData) { | |
Vector2Int ret = new Vector2Int(99999,99999); //return value | |
if (a == ret || b == ret) { | |
return ret; | |
} | |
int width = (int)Mathf.Abs(a.x - b.x); | |
int height = (int)Mathf.Abs(a.y - b.y); | |
//initial direction from a | |
Direction direction; | |
if (width == height) { | |
direction = (Direction)Random.Range(0, 2); | |
} else { | |
direction = width > height ? Direction.HORIZONTAL : Direction.VERTICAL; | |
} | |
//draw from a to b, overwriting wall tiles only | |
switch(direction) { | |
case Direction.HORIZONTAL: | |
for (int i = (int)Mathf.Min(a.x, b.x); i <= (int)Mathf.Max(a.x, b.x); i++) { | |
if (tileData[i, a.y] == TileType.WALL) { | |
tileData[i, a.y] = TileType.EMPTY; | |
} | |
CheckCorridorCenter(width, height, i, a.y, ref ret); | |
} | |
for (int j = (int)Mathf.Min(a.y, b.y); j <= (int)Mathf.Max(a.y, b.y); j++) { | |
if (tileData[b.x, j] == TileType.WALL) { | |
tileData[b.x, j] = TileType.EMPTY; | |
} | |
CheckCorridorCenter(width, height, (int)Mathf.Max(a.x, b.x), j, ref ret); | |
} | |
break; | |
case Direction.VERTICAL: | |
for (int j = (int)Mathf.Min(a.y, b.y); j <= (int)Mathf.Max(a.y, b.y); j++) { | |
if (tileData[a.x, j] == TileType.WALL) { | |
tileData[a.x, j] = TileType.EMPTY; | |
} | |
CheckCorridorCenter(width, height, a.x, j, ref ret); | |
} | |
for (int i = (int)Mathf.Min(a.x, b.x); i <= (int)Mathf.Max(a.x, b.x); i++) { | |
if (tileData[i, b.y] == TileType.WALL) { | |
tileData[i, b.y] = TileType.EMPTY; | |
} | |
CheckCorridorCenter(width, height, i, (int)Mathf.Max(a.y, b.y), ref ret); | |
} | |
break; | |
} | |
return ret; | |
} | |
//utility | |
void CheckCorridorCenter(int width, int height, int i, int j, ref Vector2Int center) { | |
if (center == new Vector2Int(99999,99999) && (width + height)/2 < i + j) { | |
center = new Vector2Int(i, j); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment