DungeonProxy.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using DunGen.Graph;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. namespace DunGen
  6. {
  7. public struct ProxyDoorwayConnection
  8. {
  9. public DoorwayProxy A { get; private set; }
  10. public DoorwayProxy B { get; private set; }
  11. public ProxyDoorwayConnection(DoorwayProxy a, DoorwayProxy b)
  12. {
  13. A = a;
  14. B = b;
  15. }
  16. }
  17. public sealed class DungeonProxy
  18. {
  19. public List<TileProxy> AllTiles = new List<TileProxy>();
  20. public List<TileProxy> MainPathTiles = new List<TileProxy>();
  21. public List<TileProxy> BranchPathTiles = new List<TileProxy>();
  22. public List<ProxyDoorwayConnection> Connections = new List<ProxyDoorwayConnection>();
  23. private Transform visualsRoot;
  24. private Dictionary<TileProxy, GameObject> tileVisuals = new Dictionary<TileProxy, GameObject>();
  25. public DungeonProxy(Transform debugVisualsRoot = null)
  26. {
  27. visualsRoot = debugVisualsRoot;
  28. }
  29. public void ClearDebugVisuals()
  30. {
  31. var instances = tileVisuals.Values.ToArray();
  32. foreach (var instance in instances)
  33. GameObject.DestroyImmediate(instance);
  34. tileVisuals.Clear();
  35. }
  36. public void MakeConnection(DoorwayProxy a, DoorwayProxy b)
  37. {
  38. Debug.Assert(a != null && b != null);
  39. Debug.Assert(a != b);
  40. Debug.Assert(!a.Used && !b.Used);
  41. DoorwayProxy.Connect(a, b);
  42. var conn = new ProxyDoorwayConnection(a, b);
  43. Connections.Add(conn);
  44. }
  45. public void RemoveLastConnection()
  46. {
  47. Debug.Assert(Connections.Any(), "No connections to remove");
  48. RemoveConnection(Connections.Last());
  49. }
  50. public void RemoveConnection(ProxyDoorwayConnection connection)
  51. {
  52. connection.A.Disconnect();
  53. Connections.Remove(connection);
  54. }
  55. internal void AddTile(TileProxy tile)
  56. {
  57. AllTiles.Add(tile);
  58. if (tile.Placement.IsOnMainPath)
  59. MainPathTiles.Add(tile);
  60. else
  61. BranchPathTiles.Add(tile);
  62. if(visualsRoot != null)
  63. {
  64. var tileObj = GameObject.Instantiate(tile.Prefab, visualsRoot);
  65. tileObj.transform.localPosition = tile.Placement.Position;
  66. tileObj.transform.localRotation = tile.Placement.Rotation;
  67. tileVisuals[tile] = tileObj;
  68. }
  69. }
  70. internal void RemoveTile(TileProxy tile)
  71. {
  72. AllTiles.Remove(tile);
  73. if (tile.Placement.IsOnMainPath)
  74. MainPathTiles.Remove(tile);
  75. else
  76. BranchPathTiles.Remove(tile);
  77. GameObject tileInstance;
  78. if(tileVisuals.TryGetValue(tile, out tileInstance))
  79. {
  80. GameObject.DestroyImmediate(tileInstance);
  81. tileVisuals.Remove(tile);
  82. }
  83. }
  84. internal void ConnectOverlappingDoorways(float globalChance, DungeonFlow dungeonFlow, RandomStream randomStream)
  85. {
  86. const float epsilon = 0.00001f;
  87. var doorways = AllTiles.SelectMany(t => t.UnusedDoorways).ToArray();
  88. foreach (var previousDoorway in doorways)
  89. {
  90. foreach (var nextDoorway in doorways)
  91. {
  92. // Don't try to connect doorways that are already connected to another
  93. if (previousDoorway.Used || nextDoorway.Used)
  94. continue;
  95. // Don't try to connect doorways to themselves
  96. if (previousDoorway == nextDoorway || previousDoorway.TileProxy == nextDoorway.TileProxy)
  97. continue;
  98. var proposedConnection = new ProposedConnection(this, previousDoorway.TileProxy, nextDoorway.TileProxy, previousDoorway, nextDoorway);
  99. // These doors cannot be connected due to their sockets or other connection rules
  100. if (!dungeonFlow.CanDoorwaysConnect(proposedConnection))
  101. continue;
  102. float distanceSqrd = (previousDoorway.Position - nextDoorway.Position).sqrMagnitude;
  103. // The doorways are too far apart
  104. if (distanceSqrd >= epsilon)
  105. continue;
  106. if (dungeonFlow.RestrictConnectionToSameSection)
  107. {
  108. bool tilesAreOnSameLineSegment = previousDoorway.TileProxy.Placement.GraphLine == nextDoorway.TileProxy.Placement.GraphLine;
  109. // The tiles are not on a line segment
  110. if (previousDoorway.TileProxy.Placement.GraphLine == null)
  111. tilesAreOnSameLineSegment = false;
  112. if (!tilesAreOnSameLineSegment)
  113. continue;
  114. }
  115. float chance = globalChance;
  116. // Allow tiles to override the global connection chance
  117. // If both tiles want to override the connection chance, use the lowest value
  118. if (previousDoorway.TileProxy.PrefabTile.OverrideConnectionChance && nextDoorway.TileProxy.PrefabTile.OverrideConnectionChance)
  119. chance = Mathf.Min(previousDoorway.TileProxy.PrefabTile.ConnectionChance, nextDoorway.TileProxy.PrefabTile.ConnectionChance);
  120. else if (previousDoorway.TileProxy.PrefabTile.OverrideConnectionChance)
  121. chance = previousDoorway.TileProxy.PrefabTile.ConnectionChance;
  122. else if (nextDoorway.TileProxy.PrefabTile.OverrideConnectionChance)
  123. chance = nextDoorway.TileProxy.PrefabTile.ConnectionChance;
  124. // There is no chance to connect these doorways
  125. if (chance <= 0f)
  126. continue;
  127. if (randomStream.NextDouble() < chance)
  128. MakeConnection(previousDoorway, nextDoorway);
  129. }
  130. }
  131. }
  132. }
  133. }