├── .gitignore ├── README.md ├── RoomGeneratorProd.cs ├── demo ├── Assets │ ├── Prefabs.meta │ ├── Prefabs │ │ ├── Room.prefab │ │ └── Room.prefab.meta │ ├── Scripts.meta │ ├── Scripts │ │ ├── Debug.cs │ │ ├── Debug.cs.meta │ │ ├── Room.cs │ │ ├── Room.cs.meta │ │ ├── RoomGeneratorControllor.cs │ │ └── RoomGeneratorControllor.cs.meta │ ├── _Scene.meta │ └── _Scene │ │ ├── Main.unity │ │ └── Main.unity.meta └── ProjectSettings │ ├── AudioManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── Physics2DSettings.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityAdsSettings.asset │ └── UnityAnalyticsManager.asset └── example.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # =============== # 2 | # Unity generated # 3 | # =============== # 4 | Temp/ 5 | Library/ 6 | 7 | # ===================================== # 8 | # Visual Studio / MonoDevelop generated # 9 | # ===================================== # 10 | ExportedObj/ 11 | obj/ 12 | *.svd 13 | *.userprefs 14 | /*.csproj 15 | *.pidb 16 | *.suo 17 | /*.sln 18 | *.user 19 | *.unityproj 20 | *.booproj 21 | 22 | # ============ # 23 | # OS generated # 24 | # ============ # 25 | .DS_Store 26 | .DS_Store? 27 | ._* 28 | .Spotlight-V100 29 | .Trashes 30 | ehthumbs.db 31 | Thumbs.db 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Procedural-Generation-Tilemap 2 | 3 | Unity implementation for [Procedural Dungeon Generation](https://github.com/adonaac/blog/issues/7) 4 | 5 | # How to run demo 6 | 7 | 1. Open Main scene 8 | 2. Enable Gizmos and click play 9 | 10 | You can adjust arguments for generating map with the script component of RoomGenerator gameobject. 11 | 12 | # How to use 13 | 14 | In production, you can use RoomGeneratorProd.cs. It is mush faster than 15 | demo. 16 | 17 | # Preview 18 | 19 | ![](https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/master/example.gif) 20 | 21 | 22 | # inspire 23 | 24 | http://fisherevans.com/blog/post/dungeon-generation 25 | -------------------------------------------------------------------------------- /RoomGeneratorProd.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class RoomGeneratorProd : MonoBehaviour { 6 | #region stored data 7 | public List allRooms; 8 | public List mainRooms; 9 | public List halls = new List (); 10 | public List secondaryRoom = new List (); 11 | public TileType[,] TileMapData; 12 | #endregion 13 | 14 | #region custom variables 15 | public float RoomRandomCircleRadius = 60.0f; 16 | public int RoomCount = 50; 17 | public int RoomMaxWidth = 30; 18 | public int RoomMinWidth = 9; 19 | public int RoomMaxHeight = 30; 20 | public int RoomMinHeight = 9; 21 | public int HallWidth = 3; 22 | public float MainRoomMulValue = 0.7f; 23 | public int HallOffsetOfEdge = 1; 24 | public float multiper = 1.1f; // for seperation of rooms, speed up the time. Usually there's no need to modify this. 25 | #endregion 26 | 27 | #region private data 28 | private Dictionary> neighborRoomCollection = new Dictionary>(); 29 | 30 | private static RoomGeneratorProd instance; 31 | private static GameObject gameobject; 32 | #endregion 33 | 34 | public enum TileType : byte 35 | { 36 | Empty = 0, // array default value is 0 37 | MainRoom, 38 | HallRoom, 39 | Hall 40 | } 41 | 42 | #region public functions 43 | 44 | // use this function to generate rooms 45 | public void GenerateRoom(){ 46 | //Random.seed = 1; 47 | RandomAddRooms (); 48 | SeprateRooms (); 49 | MarkMainRooms (); 50 | FindNeighbors (); 51 | GenerateHallLines (); 52 | FindSecondaryRooms (); 53 | } 54 | 55 | static public RoomGeneratorProd GetInstance(){ 56 | if (!instance) { 57 | gameobject = new GameObject (); 58 | gameobject.name = "RoomGeneratorProd"; 59 | instance = gameobject.AddComponent(typeof(RoomGeneratorProd)) as RoomGeneratorProd; 60 | } 61 | return instance; 62 | } 63 | 64 | public void FillTilemap(){ 65 | 66 | Vector2 offset = new Vector2 (int.MaxValue, int.MaxValue); 67 | int height = 0; 68 | int width = 0; 69 | 70 | // first, find the map size and offset. 71 | // allrooms does not contain halls, so we must foreach twice. 72 | foreach (Rect r in halls){ 73 | if (r.xMin < offset.x) offset.x = (int) r.xMin; 74 | if (r.yMin < offset.y) offset.y = (int) r.yMin; 75 | if (r.yMax > height) height = (int) r.yMax; 76 | if (r.xMax > width) width = (int) r.xMax; 77 | } 78 | foreach (Rect r in allRooms){ 79 | if (r.xMin < offset.x) offset.x = (int) r.xMin; 80 | if (r.yMin < offset.y) offset.y = (int) r.yMin; 81 | if (r.yMax > height) height = (int) r.yMax; 82 | if (r.xMax > width) width = (int) r.xMax; 83 | } 84 | TileMapData = new TileType[width - (int)offset.x, height - (int)offset.y]; 85 | 86 | MarkTileWithRect (halls, TileType.Hall, offset); 87 | MarkTileWithRect (secondaryRoom, TileType.HallRoom, offset); 88 | MarkTileWithRect (mainRooms, TileType.MainRoom, offset); 89 | 90 | } 91 | 92 | 93 | #endregion 94 | 95 | #region private functions 96 | 97 | void MarkTileWithRect(List list, TileType t, Vector2 offset){ 98 | foreach (Rect r in list) { 99 | for (int x = (int)r.xMin; x < (int)r.xMax; x++) { 100 | for (int y = (int)r.yMin; y < (int)r.yMax; y++) { 101 | TileMapData [x - (int)offset.x, y - (int)offset.y] = t; 102 | } 103 | } 104 | } 105 | } 106 | 107 | Vector2 GetRandomPointInCircle(float radius){ 108 | float t = 2 * Mathf.PI * Random.Range (0.0f, 1.0f); 109 | float u = Random.Range (0.0f, 1.0f) + Random.Range (0.0f, 1.0f); 110 | float r; 111 | if (u > 1) 112 | r = 2 - u; 113 | else 114 | r = u; 115 | return new Vector2(radius * r * Mathf.Cos(t), radius * r * Mathf.Sin(t)); 116 | } 117 | 118 | 119 | void RandomAddRooms(){ 120 | allRooms = new List (); 121 | for (int i = 0; i < RoomCount; i ++) { 122 | Vector2 r = GetRandomPointInCircle (RoomRandomCircleRadius); 123 | Rect room = new Rect (Mathf.Round (r.x + RoomRandomCircleRadius), 124 | Mathf.Round (r.y + RoomRandomCircleRadius), 125 | Mathf.Round (Random.Range (RoomMinWidth, RoomMaxWidth)), 126 | Mathf.Round (Random.Range (RoomMinHeight, RoomMaxHeight)) 127 | ); 128 | allRooms.Add (room); 129 | } 130 | } 131 | 132 | void SeprateRooms(){ 133 | int roomCount = allRooms.Count; 134 | bool touching; 135 | do { 136 | touching = false; 137 | 138 | for (int i = 0; i < roomCount; i ++) { 139 | Rect a = allRooms[i]; 140 | for (int j = i + 1; j < roomCount; j++) { 141 | Rect b = allRooms[j]; 142 | if (a.Overlaps(b)){ 143 | touching = true; 144 | float dx = Mathf.Min ( a.xMax - b.xMin, a.x - (b.xMax) ); 145 | float dy = Mathf.Min ( a.y - (b.yMax), (a.yMax) - b.y); 146 | 147 | if (Mathf.Abs(dx) < Mathf.Abs(dy)){ 148 | float dxa = -dx / 2; 149 | float dxb = dx + dxa; 150 | a.x += dxa * multiper; 151 | b.x += dxb * multiper; 152 | } 153 | else { 154 | float dya = -dy/2; 155 | float dyb = dy + dya; 156 | b.y += dyb * multiper; 157 | a.y += dya * multiper; 158 | } 159 | a.x = Mathf.Floor(a.x); 160 | a.y = Mathf.Floor(a.y); 161 | b.y = Mathf.Floor(b.y); 162 | b.x = Mathf.Floor(b.x); 163 | 164 | allRooms[i] = a; 165 | allRooms[j] = b; 166 | } 167 | 168 | } 169 | } 170 | } while (touching == true); 171 | } 172 | 173 | float GetDist(Rect a, Rect b){ 174 | return Mathf.Pow(a.center.x - b.center.x, 2) + Mathf.Pow(a.center.y - b.center.y , 2); 175 | } 176 | 177 | void MarkMainRooms(){ 178 | mainRooms = new List(); 179 | float minWidth = RoomMaxWidth * MainRoomMulValue; 180 | float minHeight = RoomMaxHeight * MainRoomMulValue; 181 | foreach (Rect r in allRooms) { 182 | if (r.height > minHeight && r.width > minWidth){ 183 | mainRooms.Add(r); 184 | } 185 | } 186 | } 187 | 188 | void FindNeighbors(){ 189 | Rect a, b, c; 190 | float abDist, acDist, bcDist; 191 | bool skip; 192 | int roomCount = mainRooms.Count; 193 | for (int i = 0; i < roomCount; i ++) { 194 | a = mainRooms[i]; 195 | for (int j = i + 1; j < roomCount; j++){ 196 | skip = false; 197 | b = mainRooms[j]; 198 | abDist = GetDist(a, b); 199 | for (int k =0; k < roomCount; k ++){ 200 | if(k ==i || k == j) continue; 201 | c = mainRooms[k]; 202 | acDist = GetDist(a, c); 203 | bcDist = GetDist(b, c); 204 | if(acDist < abDist && bcDist < abDist) 205 | skip = true; 206 | if(skip) 207 | break; 208 | } 209 | if(!skip){ 210 | if(! neighborRoomCollection.ContainsKey(a)){ 211 | neighborRoomCollection.Add (a, new List()); 212 | } 213 | neighborRoomCollection[a].Add(b); 214 | } 215 | } 216 | } 217 | } 218 | 219 | void GenerateHallLines(){ 220 | foreach (Rect a in neighborRoomCollection.Keys) { 221 | foreach(Rect b in neighborRoomCollection[a]){ 222 | 223 | Vector2 p1, p2 ,p3 ,p4; 224 | p1 = new Vector2(a.x, a.y + a.height); 225 | p2 = new Vector2(a.x + a.width, a.y); 226 | p3 = new Vector2(b.x, b.y + b.height); 227 | p4 = new Vector2(b.x + b.width, b.y); 228 | 229 | float minXdiff = 2 * HallOffsetOfEdge + HallWidth; 230 | if (p2.x - p3.x > minXdiff && p4.x - p1.x > minXdiff ){ 231 | Rect Hall = new Rect( 232 | p4.x > p2.x ? p2.x - HallOffsetOfEdge - HallWidth : p4.x - HallOffsetOfEdge - HallWidth , 233 | p3.y <= p2.y ? p3.y : p1.y, 234 | HallWidth, 235 | p3.y <= p2.y ? Mathf.Abs(p2.y - p3.y) : Mathf.Abs(p4.y - p1.y) 236 | ); 237 | halls.Add(Hall); 238 | continue; 239 | } 240 | 241 | float minYdiff = 2 * HallOffsetOfEdge + HallWidth; 242 | if (p3.y - p2.y > minYdiff && p1.y - p4.y > minYdiff){ 243 | Rect Hall = new Rect( 244 | p3.x >= p2.x ? p2.x : p4.x, 245 | p1.y < p3.y ? p1.y - HallOffsetOfEdge - HallWidth : p3.y - HallOffsetOfEdge - HallWidth, 246 | p2.x <= p3.x ? Mathf.Abs(p3.x - p2.x) : Mathf.Abs(p1.x - p4.x), 247 | HallWidth 248 | ); 249 | halls.Add(Hall); 250 | continue; 251 | } 252 | 253 | Rect ra, rb; 254 | if (a.center.x < b.center.x){ 255 | ra = a; 256 | rb = b; 257 | }else{ 258 | ra = b; 259 | rb = a; 260 | } 261 | 262 | float x = Mathf.Floor(ra.center.x); 263 | float y = Mathf.Floor(ra.center.y); 264 | float dx = Mathf.Floor(rb.center.x - x); 265 | float dy = Mathf.Floor(rb.center.y - y); 266 | if (Random.value > 0.5f){ 267 | Rect Hall = new Rect(x, y, dx + HallWidth, HallWidth); 268 | halls.Add(Hall); 269 | if(dy > 0){ 270 | Hall = new Rect(x + dx , y, HallWidth, dy); 271 | halls.Add(Hall); 272 | }else{ 273 | Hall = new Rect(x + dx , y + dy, HallWidth, -dy); 274 | halls.Add(Hall); 275 | } 276 | 277 | }else{ 278 | Rect Hall = new Rect(x, y + dy, dx + HallWidth, HallWidth); 279 | halls.Add(Hall); 280 | 281 | if(dy > 0){ 282 | Hall = new Rect(x, y, HallWidth, dy); 283 | halls.Add(Hall); 284 | }else{ 285 | Hall = new Rect(x, y + dy, HallWidth, -dy); 286 | halls.Add(Hall); 287 | } 288 | } 289 | } 290 | } 291 | } 292 | 293 | void FindSecondaryRooms(){ 294 | secondaryRoom = new List (); 295 | foreach (Rect r in allRooms) { 296 | foreach(Rect h in halls){ 297 | if (!(mainRooms.Contains(r)) && r.Overlaps(h)) 298 | secondaryRoom.Add(r); 299 | } 300 | } 301 | } 302 | 303 | #endregion 304 | } 305 | 306 | -------------------------------------------------------------------------------- /demo/Assets/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cefdde6ee96e048158a89b745e3aa80e 3 | folderAsset: yes 4 | timeCreated: 1446546176 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /demo/Assets/Prefabs/Room.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/Assets/Prefabs/Room.prefab -------------------------------------------------------------------------------- /demo/Assets/Prefabs/Room.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c6931cab9e0045209a2b45b45c5247b 3 | timeCreated: 1446546180 4 | licenseType: Free 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /demo/Assets/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 81d4a56f5ced14a59a19388ee93e25d7 3 | folderAsset: yes 4 | timeCreated: 1446540521 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /demo/Assets/Scripts/Debug.cs: -------------------------------------------------------------------------------- 1 | // DebugX.cs 2 | // Hayden Scott-Baron (Dock) - http://starfruitgames.com 3 | // Adds a number of useful Debug Draw features 4 | 5 | using UnityEngine; 6 | using System.Collections; 7 | 8 | public class DebugX : MonoBehaviour 9 | { 10 | public static void DrawCube(Vector3 pos, Color col, Vector3 scale) 11 | { 12 | Vector3 halfScale = scale * 0.5f; 13 | 14 | Vector3[] points = new Vector3[] 15 | { 16 | pos + new Vector3(halfScale.x, halfScale.y, halfScale.z), 17 | pos + new Vector3(-halfScale.x, halfScale.y, halfScale.z), 18 | pos + new Vector3(-halfScale.x, -halfScale.y, halfScale.z), 19 | pos + new Vector3(halfScale.x, -halfScale.y, halfScale.z), 20 | pos + new Vector3(halfScale.x, halfScale.y, -halfScale.z), 21 | pos + new Vector3(-halfScale.x, halfScale.y, -halfScale.z), 22 | pos + new Vector3(-halfScale.x, -halfScale.y, -halfScale.z), 23 | pos + new Vector3(halfScale.x, -halfScale.y, -halfScale.z), 24 | }; 25 | 26 | Debug.DrawLine(points[0], points[1], col); 27 | Debug.DrawLine(points[1], points[2], col); 28 | Debug.DrawLine(points[2], points[3], col); 29 | Debug.DrawLine(points[3], points[0], col); 30 | } 31 | 32 | public static void DrawRect(Rect rect, Color col) 33 | { 34 | Vector3 pos = new Vector3(rect.x + rect.width / 2, rect.y + rect.height / 2, 0.0f); 35 | Vector3 scale = new Vector3(rect.width, rect.height, 0.0f); 36 | 37 | DebugX.DrawRect(pos, col, scale); 38 | } 39 | 40 | public static void DrawRect(Rect rect, Color col, float scale) 41 | { 42 | Vector3 pos = new Vector3((rect.x + rect.width / 2) * scale, (rect.y + rect.height / 2) * scale, 0.0f); 43 | Vector3 dimensions = new Vector3(rect.width * scale, rect.height * scale, 0.0f); 44 | 45 | DebugX.DrawRect(pos, col, dimensions); 46 | } 47 | 48 | public static void DrawRect(Vector3 pos, Color col, Vector3 scale) 49 | { 50 | Vector3 halfScale = scale * 0.5f; 51 | 52 | Vector3[] points = new Vector3[] 53 | { 54 | pos + new Vector3(halfScale.x, halfScale.y, halfScale.z), 55 | pos + new Vector3(-halfScale.x, halfScale.y, halfScale.z), 56 | pos + new Vector3(-halfScale.x, -halfScale.y, halfScale.z), 57 | pos + new Vector3(halfScale.x, -halfScale.y, halfScale.z), 58 | }; 59 | 60 | Debug.DrawLine(points[0], points[1], col); 61 | Debug.DrawLine(points[1], points[2], col); 62 | Debug.DrawLine(points[2], points[3], col); 63 | Debug.DrawLine(points[3], points[0], col); 64 | } 65 | 66 | public static void DrawPoint(Vector3 pos, Color col, float scale) 67 | { 68 | Vector3[] points = new Vector3[] 69 | { 70 | pos + (Vector3.up * scale), 71 | pos - (Vector3.up * scale), 72 | pos + (Vector3.right * scale), 73 | pos - (Vector3.right * scale), 74 | pos + (Vector3.forward * scale), 75 | pos - (Vector3.forward * scale) 76 | }; 77 | 78 | Debug.DrawLine(points[0], points[1], col); 79 | Debug.DrawLine(points[2], points[3], col); 80 | Debug.DrawLine(points[4], points[5], col); 81 | 82 | Debug.DrawLine(points[0], points[2], col); 83 | Debug.DrawLine(points[0], points[3], col); 84 | Debug.DrawLine(points[0], points[4], col); 85 | Debug.DrawLine(points[0], points[5], col); 86 | 87 | Debug.DrawLine(points[1], points[2], col); 88 | Debug.DrawLine(points[1], points[3], col); 89 | Debug.DrawLine(points[1], points[4], col); 90 | Debug.DrawLine(points[1], points[5], col); 91 | 92 | Debug.DrawLine(points[4], points[2], col); 93 | Debug.DrawLine(points[4], points[3], col); 94 | Debug.DrawLine(points[5], points[2], col); 95 | Debug.DrawLine(points[5], points[3], col); 96 | 97 | } 98 | } -------------------------------------------------------------------------------- /demo/Assets/Scripts/Debug.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 521f630b0d1514991acf3743ef5eaa6f 3 | timeCreated: 1446553887 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /demo/Assets/Scripts/Room.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | 5 | public class Room : MonoBehaviour { 6 | public Rect pos; 7 | public bool mainRoom = false; 8 | public bool isHall = false; 9 | public bool disable = false; 10 | 11 | private static Texture2D _staticRectTexture; 12 | private static GUIStyle _staticRectStyle; 13 | 14 | public void Start(){ 15 | 16 | } 17 | 18 | public void Update(){ 19 | if (disable) 20 | return; 21 | 22 | transform.position = new Vector2 (pos.x, pos.y); 23 | if (isHall) { 24 | DebugX.DrawRect (pos, new Color(0.5f, 1.0f, 0.3f, 0.7f)); 25 | return; 26 | } 27 | 28 | if (!mainRoom) { 29 | DebugX.DrawRect (pos, Color.blue); 30 | } else { 31 | DebugX.DrawRect (pos, Color.red); 32 | } 33 | } 34 | 35 | public float GetRight(){ 36 | return pos.x + pos.width; 37 | } 38 | 39 | public float GetLeft(){ 40 | return this.pos.x; 41 | } 42 | 43 | public float GetTop(){ 44 | return this.pos.y + this.pos.height; 45 | } 46 | 47 | public float GetBottom(){ 48 | return this.pos.y; 49 | } 50 | } -------------------------------------------------------------------------------- /demo/Assets/Scripts/Room.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db0bdb37319154748a91f0bcc1459631 3 | timeCreated: 1446541679 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /demo/Assets/Scripts/RoomGeneratorControllor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class RoomGeneratorControllor : MonoBehaviour { 6 | public enum TileType : byte 7 | { 8 | Empty = 0, // array default value is 0 9 | MainRoom, 10 | HallRoom, 11 | Hall 12 | } 13 | 14 | private List rooms = new List(); 15 | private List mainRooms = new List(); 16 | private class LineSegment{ 17 | public Vector2 start; 18 | public Vector2 stop; 19 | 20 | public LineSegment(Vector2 start, Vector2 stop){ 21 | this.start = start; 22 | this.stop = stop; 23 | } 24 | } 25 | 26 | private Dictionary> neighborGraph = new Dictionary> (); 27 | private Dictionary> neighborRoomCollection = new Dictionary>(); 28 | private List halls = new List (); 29 | 30 | public float RoomRandomCircleRadius = 200.0f; 31 | public int RoomCount = 100; 32 | public int RoomMaxWidth = 30; 33 | public int RoomMinWidth = 3; 34 | public int RoomMaxHeight = 30; 35 | public int RoomMinHeight = 3; 36 | public int HallWidth = 3; 37 | public float MainRoomMulValue = 0.7f; 38 | public int HallOffsetOfEdge = 1; 39 | public Camera cam; 40 | public Room roomObj; 41 | 42 | private TileType[,] TileMapData; 43 | 44 | void Start () { 45 | Time.timeScale = 10; 46 | StartCoroutine (GenStep1 ()); 47 | GenStep1 (); 48 | } 49 | 50 | IEnumerator GenStep1(){ 51 | rooms.Clear (); 52 | for (int i = 0; i < RoomCount; i ++) { 53 | Vector2 r = GetRandomPointInCircle(RoomRandomCircleRadius); 54 | Room room = Instantiate(roomObj) as Room; 55 | room.pos = new Rect(Mathf.Round(r.x + RoomRandomCircleRadius), 56 | Mathf.Round(r.y + RoomRandomCircleRadius), 57 | Mathf.Round(Random.Range(RoomMinWidth, RoomMaxWidth)), 58 | Mathf.Round(Random.Range(RoomMinHeight, RoomMaxHeight)) 59 | ); 60 | rooms.Add(room); 61 | yield return new WaitForSeconds (0.05f); 62 | } 63 | StartCoroutine (SeprateRooms ()); 64 | } 65 | 66 | Vector2 GetRandomPointInCircle(float radius){ 67 | float t = 2 * Mathf.PI * Random.Range (0.0f, 1.0f); 68 | float u = Random.Range (0.0f, 1.0f) + Random.Range (0.0f, 1.0f); 69 | float r; 70 | if (u > 1) 71 | r = 2 - u; 72 | else 73 | r = u; 74 | return new Vector2(radius * r * Mathf.Cos(t), radius * r * Mathf.Sin(t)); 75 | } 76 | 77 | bool TouchTest(Room a, Room b){ 78 | return a.pos.Overlaps (b.pos); 79 | } 80 | 81 | IEnumerator SeprateRooms(){ 82 | int roomCount = rooms.Count; 83 | bool touching; 84 | do { 85 | touching = false; 86 | for (int i = 0; i < roomCount; i ++) { 87 | Room a = rooms[i]; 88 | for (int j = i + 1; j < roomCount; j++) { 89 | Room b = rooms[j]; 90 | a.pos.x = Mathf.Floor(a.pos.x); 91 | a.pos.y = Mathf.Floor(a.pos.y); 92 | b.pos.y = Mathf.Floor(b.pos.y); 93 | b.pos.x = Mathf.Floor(b.pos.x); 94 | if (TouchTest(a, b)){ 95 | touching = true; 96 | float dx = Mathf.Min (a.GetRight() - b.GetLeft(), a.GetLeft() - b.GetRight()); 97 | float dy = Mathf.Min (a.GetBottom() - b.GetTop(), a.GetTop() - b.GetBottom()); 98 | 99 | if (Mathf.Abs(dx) < Mathf.Abs(dy)){ 100 | float dxa = -dx / 2; 101 | float dxb = dx + dxa; 102 | a.pos.x += dxa; 103 | b.pos.x += dxb; 104 | } 105 | else { 106 | float dya = -dy/2; 107 | float dyb = dy + dya; 108 | b.pos.y += dyb; 109 | a.pos.y += dya; 110 | } 111 | } 112 | } 113 | yield return null; 114 | } 115 | } while (touching == true); 116 | StartCoroutine(MarkMainRooms()); 117 | } 118 | 119 | IEnumerator MarkMainRooms(){ 120 | mainRooms.Clear (); 121 | float minWidth = RoomMaxWidth * MainRoomMulValue; 122 | float minHeight = RoomMaxHeight * MainRoomMulValue; 123 | foreach (Room r in rooms) { 124 | if (r.pos.height > minHeight && r.pos.width > minWidth){ 125 | r.mainRoom = true; 126 | mainRooms.Add(r); 127 | } 128 | yield return new WaitForSeconds (0.5f); 129 | } 130 | StartCoroutine (FindNeighbors ()); 131 | } 132 | 133 | float GetDist(Room a, Room b){ 134 | return Mathf.Pow(a.pos.center.x - b.pos.center.x, 2) + Mathf.Pow(a.pos.center.y - b.pos.center.y , 2); 135 | } 136 | 137 | IEnumerator FindNeighbors(){ 138 | Room a, b, c; 139 | float abDist, acDist, bcDist; 140 | bool skip; 141 | int roomCount = mainRooms.Count; 142 | for (int i = 0; i < roomCount; i ++) { 143 | a = mainRooms[i]; 144 | for (int j = i + 1; j < roomCount; j++){ 145 | skip = false; 146 | b = mainRooms[j]; 147 | abDist = GetDist(a, b); 148 | for (int k =0; k < roomCount; k ++){ 149 | if(k ==i || k == j) continue; 150 | c = mainRooms[k]; 151 | acDist = GetDist(a,c); 152 | bcDist = GetDist(b,c); 153 | if(acDist < abDist && bcDist < abDist) 154 | skip = true; 155 | if(skip) 156 | break; 157 | } 158 | if(!skip){ 159 | if(! neighborGraph.ContainsKey(a)){ 160 | neighborGraph.Add(a, new List()); 161 | neighborRoomCollection.Add (a, new List()); 162 | } 163 | neighborGraph[a].Add(new LineSegment(a.pos.center, b.pos.center)); 164 | neighborRoomCollection[a].Add(b); 165 | yield return new WaitForSeconds(0.001f); 166 | } 167 | } 168 | } 169 | StartCoroutine (GenerateHallLines ()); 170 | } 171 | 172 | IEnumerator GenerateHallLines(){ 173 | foreach (Room a in neighborRoomCollection.Keys) { 174 | foreach(Room b in neighborRoomCollection[a]){ 175 | 176 | Vector2 p1, p2 ,p3 ,p4; 177 | p1 = new Vector2(a.pos.x, a.pos.y + a.pos.height); 178 | p2 = new Vector2(a.pos.x + a.pos.width, a.pos.y); 179 | p3 = new Vector2(b.pos.x, b.pos.y + b.pos.height); 180 | p4 = new Vector2(b.pos.x + b.pos.width, b.pos.y); 181 | 182 | float minXdiff = 2 * HallOffsetOfEdge + HallWidth; 183 | if (p2.x - p3.x > minXdiff && p4.x - p1.x > minXdiff ){ 184 | Rect Hall = new Rect( 185 | p4.x > p2.x ? p2.x - HallOffsetOfEdge - HallWidth : p4.x - HallOffsetOfEdge - HallWidth , 186 | p3.y <= p2.y ? p3.y : p1.y, 187 | HallWidth, 188 | p3.y <= p2.y ? Mathf.Abs(p2.y - p3.y) : Mathf.Abs(p4.y - p1.y) 189 | ); 190 | Room r = Instantiate(roomObj) as Room; 191 | r.pos = Hall; 192 | r.isHall = true; 193 | halls.Add(r); 194 | continue; 195 | } 196 | 197 | float minYdiff = 2 * HallOffsetOfEdge + HallWidth; 198 | if (p3.y - p2.y > minYdiff && p1.y - p4.y > minYdiff){ 199 | Rect Hall = new Rect( 200 | p3.x >= p2.x ? p2.x : p4.x, 201 | p1.y < p3.y ? p1.y - HallOffsetOfEdge - HallWidth : p3.y - HallOffsetOfEdge - HallWidth, 202 | p2.x <= p3.x ? Mathf.Abs(p3.x - p2.x) : Mathf.Abs(p1.x - p4.x), 203 | HallWidth 204 | ); 205 | Room r = Instantiate(roomObj) as Room; 206 | r.pos = Hall; 207 | r.isHall = true; 208 | halls.Add(r); 209 | continue; 210 | } 211 | 212 | Room ra, rb; 213 | if (a.pos.center.x < b.pos.center.x){ 214 | ra = a; 215 | rb = b; 216 | }else{ 217 | ra = b; 218 | rb = a; 219 | } 220 | 221 | float x = ra.pos.center.x; 222 | float y = ra.pos.center.y; 223 | float dx = rb.pos.center.x - x; 224 | float dy = rb.pos.center.y - y; 225 | 226 | if (Random.value > 0.5f){ 227 | Rect Hall = new Rect(x, y, dx + 1, 1); 228 | Room r = Instantiate(roomObj) as Room; 229 | r.pos = Hall; 230 | r.isHall = true; 231 | halls.Add(r); 232 | 233 | Hall = new Rect(x + dx , y + (dy > 0 ? 0 : dy) , 1, (dy > 0 ? dy : -dy)); 234 | r = Instantiate(roomObj) as Room; 235 | r.pos = Hall; 236 | r.isHall = true; 237 | halls.Add(r); 238 | }else{ 239 | Rect Hall = new Rect(x, y + dy, dx + 1, 1); 240 | Room r = Instantiate(roomObj) as Room; 241 | r.pos = Hall; 242 | r.isHall = true; 243 | halls.Add(r); 244 | 245 | Hall = new Rect(x, y + (dy > 0 ? 0 : dy), 1, (dy > 0 ? dy : -dy)); 246 | r = Instantiate(roomObj) as Room; 247 | r.pos = Hall; 248 | r.isHall = true; 249 | halls.Add(r); 250 | } 251 | yield return null; 252 | } 253 | } 254 | StartCoroutine (MarkHalls ()); 255 | } 256 | 257 | IEnumerator MarkHalls(){ 258 | foreach (Room h in halls) { 259 | h.pos.x = Mathf.Floor(h.pos.x) - 1; 260 | h.pos.y = Mathf.Floor(h.pos.y) - 1; 261 | h.pos.height = Mathf.Floor(h.pos.height) + 2; 262 | h.pos.width = Mathf.Floor(h.pos.width) + 2; 263 | } 264 | 265 | foreach (Room r in rooms){ 266 | if (r.mainRoom) continue; 267 | 268 | foreach (Room h in halls) { 269 | if (!r.mainRoom && TouchTest(h, r)){ 270 | Debug.Log("aaa"); 271 | r.isHall = true; 272 | } 273 | } 274 | if (!r.mainRoom && (!r.isHall)){ 275 | r.disable = true; 276 | } 277 | yield return null; 278 | } 279 | 280 | StartCoroutine (GenerateTileMap ()); 281 | } 282 | 283 | IEnumerator GenerateTileMap(){ 284 | int MapStartX = (int) (rooms [0].pos.x); 285 | int MapStartY = (int) (rooms [0].pos.y); 286 | int MapHeight = (int) (rooms [0].pos.height); 287 | int MapWidth = (int) (rooms [0].pos.height); 288 | foreach (Room r in rooms) { 289 | if (r.disable) continue; 290 | if (r.pos.x < MapStartX) MapStartX = (int) (r.pos.x); 291 | if (r.pos.y < MapStartY) MapStartY = (int) (r.pos.y); 292 | if (r.pos.x + r.pos.width > MapWidth) MapWidth = (int)(r.pos.x + r.pos.width); 293 | if (r.pos.y + r.pos.height > MapHeight) MapHeight = (int) (r.pos.y + r.pos.height); 294 | } 295 | foreach (Room r in halls) { 296 | if (r.pos.x < MapStartX) MapStartX = (int) (r.pos.x); 297 | if (r.pos.y < MapStartY) MapStartY = (int) (r.pos.y); 298 | if (r.pos.x + r.pos.width > MapWidth) MapWidth = (int) (r.pos.x + r.pos.width); 299 | if (r.pos.y + r.pos.height > MapHeight) MapHeight = (int) (r.pos.y + r.pos.height); 300 | } 301 | 302 | // first for main rooms 303 | TileMapData = new TileType[MapHeight, MapWidth]; 304 | foreach (Room r in mainRooms) { 305 | for (int x = (int) (r.pos.x - MapStartX); x < (int) (r.pos.x - MapStartX + r.pos.width); x++ ){ 306 | for (int y = (int) (r.pos.y - MapStartY); y < (int) (r.pos.y - MapStartY + r.pos.height); y++ ){ 307 | if (TileMapData[x, y] != TileType.Empty) continue; 308 | TileMapData[x, y] = TileType.MainRoom; 309 | } 310 | } 311 | } 312 | 313 | foreach (Room r in rooms) { 314 | if (r.mainRoom || r.disable) continue; 315 | for (int x = (int) (r.pos.x - MapStartX); x < (int) (r.pos.x - MapStartX + r.pos.width); x++ ){ 316 | for (int y = (int) (r.pos.y - MapStartY); y < (int) (r.pos.y - MapStartY + r.pos.height); y++ ){ 317 | if (TileMapData[x, y] != TileType.Empty) continue; 318 | TileMapData[x, y] = TileType.HallRoom; 319 | } 320 | } 321 | } 322 | 323 | foreach (Room r in halls) { 324 | if (r.mainRoom || r.disable) continue; 325 | for (int x = (int) (r.pos.x - MapStartX); x < (int) (r.pos.x - MapStartX + r.pos.width); x++ ){ 326 | for (int y = (int) (r.pos.y - MapStartY); y < (int) (r.pos.y - MapStartY + r.pos.height); y++ ){ 327 | if (TileMapData[x, y] != TileType.Empty) continue; 328 | TileMapData[x, y] = TileType.Hall; 329 | } 330 | } 331 | } 332 | 333 | // clean 334 | foreach (Room r in halls) { 335 | Destroy(r); 336 | } 337 | halls.Clear (); 338 | 339 | foreach (Room r in rooms) { 340 | if (!r.mainRoom) 341 | Destroy(r); 342 | } 343 | rooms.Clear (); 344 | 345 | yield return null; 346 | } 347 | 348 | void Update(){ 349 | foreach (Room r in neighborGraph.Keys) { 350 | foreach(LineSegment l in neighborGraph[r]){ 351 | Debug.DrawLine(l.start, l.stop, new Color(1f, 1f,0f,0.5f)); 352 | } 353 | } 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /demo/Assets/Scripts/RoomGeneratorControllor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 608c47cb3ad274c0d839a86c5eecc3ba 3 | timeCreated: 1446543802 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /demo/Assets/_Scene.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1125e9684f1f84a9d8fa617ac7ac77ed 3 | folderAsset: yes 4 | timeCreated: 1446548693 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /demo/Assets/_Scene/Main.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/Assets/_Scene/Main.unity -------------------------------------------------------------------------------- /demo/Assets/_Scene/Main.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f7ad9e00fb4e44dab967f020c4e67fcf 3 | timeCreated: 1446548705 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /demo/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.2.2f1 2 | m_StandardAssetsVersion: 0 3 | -------------------------------------------------------------------------------- /demo/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /demo/ProjectSettings/UnityAnalyticsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/demo/ProjectSettings/UnityAnalyticsManager.asset -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinxb/Procedural-Generation-Tilemap/c367b0af98e2aaf949c41d68838bfb118075ddab/example.gif --------------------------------------------------------------------------------