DungeonGeneratorDrawUtil.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. using UnityEditor;
  2. using UnityEngine;
  3. namespace DunGen.Editor
  4. {
  5. public static class DungeonGeneratorDrawUtil
  6. {
  7. private static class Labels
  8. {
  9. public static readonly GUIContent RandomizeSeed = new GUIContent("Randomize Seed", "If checked, a new random seed will be created every time a dungeon is generated. If unchecked, a specific seed will be used each time");
  10. public static readonly GUIContent Seed = new GUIContent("Seed", "The seed used to generate a dungeon layout. Generating a dungeon multiple times with the same seed will produce the exact same results each time");
  11. public static readonly GUIContent MaxFailedAttempts = new GUIContent("Max Failed Attempts", "The maximum number of times DunGen is allowed to fail at generating a dungeon layout before giving up. This only applies in-editor; in a packaged build, DunGen will keep trying indefinitely");
  12. public static readonly GUIContent LengthMultiplier = new GUIContent("Length Multiplier", "Used to alter the length of the dungeon without modifying the Dungeon Flow asset. 1 = normal-length, 2 = double-length, 0.5 = half-length, etc.");
  13. public static readonly GUIContent UpDirection = new GUIContent("Up Direction", "The up direction of the dungeon. This won't actually rotate your dungeon, but it must match the expected up-vector for your dungeon layout - usually +Y for 3D and side-on 2D, -Z for top-down 2D");
  14. public static readonly GUIContent TriggerPlacement = new GUIContent("Trigger Placement", "Places trigger colliders around Tiles which can be used in conjunction with the DungenCharacter component to receive events when changing rooms");
  15. public static readonly GUIContent TriggerLayer = new GUIContent("Trigger Layer", "The layer to place the tile root objects on if \"Place Tile Triggers\" is checked");
  16. public static readonly GUIContent GenerateAsynchronously = new GUIContent("Generate Asynchronously", "If checked, DunGen will generate the layout without blocking Unity's main thread, allowing for things like animated loading screens to be shown");
  17. public static readonly GUIContent MaxFrameTime = new GUIContent("Max Frame Time", "How many milliseconds the dungeon generation is allowed to take per-frame");
  18. public static readonly GUIContent PauseBetweenRooms = new GUIContent("Pause Between Rooms", "If greater than zero, the dungeon generation will pause for the set time (in seconds) after placing a room; useful for visualising the generation process");
  19. public static readonly GUIContent OverlapThreshold = new GUIContent("Overlap Threshold", "Maximum distance two connected tiles are allowed to overlap without being discarded. If doorways aren't exactly on the tile's axis-aligned bounding box, two tiles can overlap slighty when connected. This property can help to fix this issue");
  20. public static readonly GUIContent CollideAllDungeons = new GUIContent("Collide All Dungeons", "When placing a new tile, DunGen will test for collisions against all tiles in every dungeon in the scene, instead of just this one");
  21. public static readonly GUIContent DisallowOverhangs = new GUIContent("Disallow Overhangs", "If checked, two tiles cannot overlap along the Up-Vector (a room cannot spawn above another room)");
  22. public static readonly GUIContent Padding = new GUIContent("Padding", "A minimum buffer distance between two unconnected tiles");
  23. public static readonly GUIContent RestrictToBounds = new GUIContent("Restrict to Bounds?", "If checked, tiles will only be placed within the specified bounds below. May increase generation times");
  24. public static readonly GUIContent PlacementBounds = new GUIContent("Placement Bounds", "Tiles are not allowed to be placed outside of these bounds");
  25. public static readonly GUIContent RepeatMode = new GUIContent("Repeat Mode");
  26. public static readonly GUIContent[] UpDirectionDisplayOptions = new GUIContent[]
  27. {
  28. new GUIContent("+X"),
  29. new GUIContent("-X"),
  30. new GUIContent("+Y"),
  31. new GUIContent("-Y"),
  32. new GUIContent("+Z"),
  33. new GUIContent("-Z")
  34. };
  35. }
  36. public static void DrawDungeonGenerator(SerializedProperty dungeonGeneratorProp, bool isRuntimeDungeon)
  37. {
  38. var dungeonFlowProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.DungeonFlow));
  39. var shouldRandomizeSeedProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.ShouldRandomizeSeed));
  40. var seedProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.Seed));
  41. var maxAttemptCountProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.MaxAttemptCount));
  42. var lengthMultiplierProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.LengthMultiplier));
  43. var upDirectionProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.UpDirection));
  44. var debugRenderProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.DebugRender));
  45. var triggerPlacementProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.TriggerPlacement));
  46. var tileTriggerLayerProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.TileTriggerLayer));
  47. var generateAsyncProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.GenerateAsynchronously));
  48. var maxAsyncFrameMsProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.MaxAsyncFrameMilliseconds));
  49. var pauseBetweenRoomsProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.PauseBetweenRooms));
  50. var restrictToBoundsProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.RestrictDungeonToBounds));
  51. var placementBoundsProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.TilePlacementBounds));
  52. var overrideRepeatModeProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.OverrideRepeatMode));
  53. var repeatModeProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.RepeatMode));
  54. var overrideAllowTileRotationProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.OverrideAllowTileRotation));
  55. var allowTileRotationProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.AllowTileRotation));
  56. var collisionSettingsProp = dungeonGeneratorProp.FindPropertyRelative(nameof(DungeonGenerator.CollisionSettings));
  57. EditorGUILayout.PropertyField(dungeonFlowProp);
  58. EditorGUILayout.PropertyField(shouldRandomizeSeedProp, Labels.RandomizeSeed);
  59. if (!shouldRandomizeSeedProp.boolValue)
  60. EditorGUILayout.PropertyField(seedProp, Labels.Seed);
  61. EditorGUILayout.PropertyField(lengthMultiplierProp, Labels.LengthMultiplier);
  62. upDirectionProp.enumValueIndex = EditorGUILayout.Popup(Labels.UpDirection, upDirectionProp.enumValueIndex, Labels.UpDirectionDisplayOptions);
  63. if (lengthMultiplierProp.floatValue < 0)
  64. lengthMultiplierProp.floatValue = 0.0f;
  65. if (isRuntimeDungeon)
  66. {
  67. EditorGUILayout.Space();
  68. EditorGUILayout.BeginVertical("box");
  69. {
  70. EditorGUI.indentLevel++;
  71. generateAsyncProp.isExpanded = EditorGUILayout.Foldout(generateAsyncProp.isExpanded, "Asynchronous Generation", true);
  72. if (generateAsyncProp.isExpanded)
  73. {
  74. EditorGUILayout.PropertyField(generateAsyncProp, Labels.GenerateAsynchronously);
  75. var unitsLabelSize = EditorStyles.label.CalcSize(new GUIContent("milliseconds"));
  76. EditorGUI.BeginDisabledGroup(!generateAsyncProp.boolValue);
  77. EditorGUILayout.BeginHorizontal();
  78. maxAsyncFrameMsProp.floatValue = EditorGUILayout.Slider(Labels.MaxFrameTime, maxAsyncFrameMsProp.floatValue, 0f, 1000f);
  79. EditorGUILayout.LabelField("milliseconds", GUILayout.Width(unitsLabelSize.x));
  80. EditorGUILayout.EndHorizontal();
  81. EditorGUILayout.BeginHorizontal();
  82. pauseBetweenRoomsProp.floatValue = EditorGUILayout.Slider(Labels.PauseBetweenRooms, pauseBetweenRoomsProp.floatValue, 0, 5);
  83. EditorGUILayout.LabelField("seconds", GUILayout.Width(unitsLabelSize.x));
  84. EditorGUILayout.EndHorizontal();
  85. EditorGUI.EndDisabledGroup();
  86. }
  87. EditorGUI.indentLevel--;
  88. }
  89. EditorGUILayout.EndVertical();
  90. }
  91. // Collision Settings
  92. if (collisionSettingsProp != null)
  93. {
  94. EditorGUILayout.BeginVertical("box");
  95. {
  96. EditorGUI.indentLevel++;
  97. collisionSettingsProp.isExpanded = EditorGUILayout.Foldout(collisionSettingsProp.isExpanded, "Collision", true);
  98. if (collisionSettingsProp.isExpanded)
  99. {
  100. EditorGUILayout.PropertyField(triggerPlacementProp, Labels.TriggerPlacement);
  101. EditorGUI.BeginDisabledGroup(triggerPlacementProp.enumValueIndex == 0);
  102. {
  103. tileTriggerLayerProp.intValue = EditorGUILayout.LayerField(Labels.TriggerLayer, tileTriggerLayerProp.intValue);
  104. }
  105. EditorGUI.EndDisabledGroup();
  106. EditorGUILayout.Space();
  107. EditorGUILayout.PropertyField(collisionSettingsProp.FindPropertyRelative("OverlapThreshold"), Labels.OverlapThreshold);
  108. EditorGUILayout.PropertyField(collisionSettingsProp.FindPropertyRelative("AvoidCollisionsWithOtherDungeons"), Labels.CollideAllDungeons);
  109. EditorGUILayout.PropertyField(collisionSettingsProp.FindPropertyRelative("DisallowOverhangs"), Labels.DisallowOverhangs);
  110. var paddingProp = collisionSettingsProp.FindPropertyRelative("Padding");
  111. EditorGUI.BeginChangeCheck();
  112. float padding = EditorGUILayout.DelayedFloatField(Labels.Padding, paddingProp.floatValue);
  113. if (EditorGUI.EndChangeCheck())
  114. paddingProp.floatValue = Mathf.Max(0f, padding);
  115. }
  116. EditorGUI.indentLevel--;
  117. }
  118. EditorGUILayout.EndVertical();
  119. }
  120. // Constraints
  121. EditorGUILayout.BeginVertical("box");
  122. {
  123. EditorGUI.indentLevel++;
  124. restrictToBoundsProp.isExpanded = EditorGUILayout.Foldout(restrictToBoundsProp.isExpanded, "Constraints", true);
  125. if (restrictToBoundsProp.isExpanded)
  126. {
  127. EditorGUILayout.HelpBox("Constraints can make dungeon generation more likely to fail. Stricter constraints increase the chance of failure.", MessageType.Info);
  128. EditorGUILayout.Space();
  129. EditorGUILayout.PropertyField(restrictToBoundsProp, Labels.RestrictToBounds);
  130. EditorGUI.BeginDisabledGroup(!restrictToBoundsProp.boolValue);
  131. EditorGUILayout.PropertyField(placementBoundsProp, Labels.PlacementBounds);
  132. EditorGUI.EndDisabledGroup();
  133. }
  134. EditorGUI.indentLevel--;
  135. }
  136. EditorGUILayout.EndVertical();
  137. // Overrides
  138. EditorGUILayout.BeginVertical("box");
  139. {
  140. EditorGUI.indentLevel++;
  141. overrideRepeatModeProp.isExpanded = EditorGUILayout.Foldout(overrideRepeatModeProp.isExpanded, "Global Overrides", true);
  142. if (overrideRepeatModeProp.isExpanded)
  143. {
  144. EditorGUILayout.BeginHorizontal();
  145. {
  146. EditorGUILayout.PropertyField(overrideRepeatModeProp, GUIContent.none, GUILayout.Width(10));
  147. EditorGUI.BeginDisabledGroup(!overrideRepeatModeProp.boolValue);
  148. EditorGUILayout.PropertyField(repeatModeProp, Labels.RepeatMode);
  149. EditorGUI.EndDisabledGroup();
  150. }
  151. EditorGUILayout.EndHorizontal();
  152. DrawOverride("Allow Tile Rotation", overrideAllowTileRotationProp, allowTileRotationProp);
  153. }
  154. EditorGUI.indentLevel--;
  155. }
  156. EditorGUILayout.EndVertical();
  157. // Debug Settings
  158. EditorGUILayout.BeginVertical("box");
  159. {
  160. EditorGUI.indentLevel++;
  161. debugRenderProp.isExpanded = EditorGUILayout.Foldout(debugRenderProp.isExpanded, "Debug", true);
  162. if (debugRenderProp.isExpanded)
  163. {
  164. if (isRuntimeDungeon)
  165. EditorGUILayout.PropertyField(debugRenderProp);
  166. EditorGUILayout.PropertyField(maxAttemptCountProp, Labels.MaxFailedAttempts);
  167. }
  168. EditorGUI.indentLevel--;
  169. }
  170. EditorGUILayout.EndVertical();
  171. }
  172. private static void DrawOverride(string label, SerializedProperty overrideProp, SerializedProperty valueProp)
  173. {
  174. EditorGUILayout.BeginHorizontal();
  175. EditorGUILayout.PropertyField(overrideProp, GUIContent.none, GUILayout.Width(10));
  176. EditorGUI.BeginDisabledGroup(!overrideProp.boolValue);
  177. EditorGUILayout.PropertyField(valueProp, new GUIContent(label));
  178. EditorGUI.EndDisabledGroup();
  179. EditorGUILayout.EndHorizontal();
  180. }
  181. }
  182. }