TileProxy.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using DunGen.Tags;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.Linq;
  6. using UnityEngine;
  7. namespace DunGen
  8. {
  9. public sealed class DoorwayProxy
  10. {
  11. public bool Used { get { return ConnectedDoorway != null; } }
  12. public TileProxy TileProxy { get; private set; }
  13. public int Index { get; private set; }
  14. public DoorwaySocket Socket { get; private set; }
  15. public Doorway DoorwayComponent { get; private set; }
  16. public Vector3 LocalPosition { get; private set; }
  17. public Quaternion LocalRotation { get; private set; }
  18. public DoorwayProxy ConnectedDoorway { get; private set; }
  19. public Vector3 Forward { get { return (TileProxy.Placement.Rotation * LocalRotation) * Vector3.forward; } }
  20. public Vector3 Up { get { return (TileProxy.Placement.Rotation * LocalRotation) * Vector3.up; } }
  21. public Vector3 Position { get { return TileProxy.Placement.Transform.MultiplyPoint(LocalPosition); } }
  22. public TagContainer Tags { get; private set; }
  23. public bool IsDisabled { get; internal set; }
  24. public DoorwayProxy(TileProxy tileProxy, DoorwayProxy other)
  25. {
  26. TileProxy = tileProxy;
  27. Index = other.Index;
  28. Socket = other.Socket;
  29. DoorwayComponent = other.DoorwayComponent;
  30. LocalPosition = other.LocalPosition;
  31. LocalRotation = other.LocalRotation;
  32. Tags = new TagContainer(other.Tags);
  33. }
  34. public DoorwayProxy(TileProxy tileProxy, int index, Doorway doorwayComponent, Vector3 localPosition, Quaternion localRotation)
  35. {
  36. TileProxy = tileProxy;
  37. Index = index;
  38. Socket = doorwayComponent.Socket;
  39. DoorwayComponent = doorwayComponent;
  40. LocalPosition = localPosition;
  41. LocalRotation = localRotation;
  42. }
  43. public static void Connect(DoorwayProxy a, DoorwayProxy b)
  44. {
  45. Debug.Assert(a.ConnectedDoorway == null, "Doorway 'a' is already connected to something");
  46. Debug.Assert(b.ConnectedDoorway == null, "Doorway 'b' is already connected to something");
  47. a.ConnectedDoorway = b;
  48. b.ConnectedDoorway = a;
  49. }
  50. public void Disconnect()
  51. {
  52. if (ConnectedDoorway == null)
  53. return;
  54. ConnectedDoorway.ConnectedDoorway = null;
  55. ConnectedDoorway = null;
  56. }
  57. }
  58. public sealed class TileProxy
  59. {
  60. public GameObject Prefab { get; private set; }
  61. public Tile PrefabTile { get; private set; }
  62. public TilePlacementData Placement { get; internal set; }
  63. public List<DoorwayProxy> Entrances { get; private set; }
  64. public List<DoorwayProxy> Exits { get; private set; }
  65. public ReadOnlyCollection<DoorwayProxy> Doorways { get; private set; }
  66. public IEnumerable<DoorwayProxy> UsedDoorways { get { return doorways.Where(d => d.Used); } }
  67. public IEnumerable<DoorwayProxy> UnusedDoorways { get { return doorways.Where(d => !d.Used); } }
  68. public TagContainer Tags { get; private set; }
  69. private readonly List<DoorwayProxy> doorways = new List<DoorwayProxy>();
  70. public TileProxy(TileProxy existingTile)
  71. {
  72. Prefab = existingTile.Prefab;
  73. PrefabTile = existingTile.PrefabTile;
  74. Placement = new TilePlacementData(existingTile.Placement);
  75. Tags = new TagContainer(existingTile.Tags);
  76. // Copy proxy doorways
  77. Doorways = new ReadOnlyCollection<DoorwayProxy>(doorways);
  78. Entrances = new List<DoorwayProxy>(existingTile.Entrances.Count);
  79. Exits = new List<DoorwayProxy>(existingTile.Exits.Count);
  80. foreach(var existingDoorway in existingTile.doorways)
  81. {
  82. var doorway = new DoorwayProxy(this, existingDoorway);
  83. doorways.Add(doorway);
  84. if (existingTile.Entrances.Contains(existingDoorway))
  85. Entrances.Add(doorway);
  86. if(existingTile.Exits.Contains(existingDoorway))
  87. Exits.Add(doorway);
  88. }
  89. }
  90. public TileProxy(GameObject prefab, Func<Doorway, int, bool> allowedDoorwayPredicate = null)
  91. {
  92. prefab.transform.localPosition = Vector3.zero;
  93. prefab.transform.localRotation = Quaternion.identity;
  94. Prefab = prefab;
  95. PrefabTile = prefab.GetComponent<Tile>();
  96. if (PrefabTile == null)
  97. PrefabTile = prefab.AddComponent<Tile>();
  98. Placement = new TilePlacementData();
  99. Tags = new TagContainer(PrefabTile.Tags);
  100. // Add proxy doorways
  101. Doorways = new ReadOnlyCollection<DoorwayProxy>(doorways);
  102. Entrances = new List<DoorwayProxy>();
  103. Exits = new List<DoorwayProxy>();
  104. var allDoorways = prefab.GetComponentsInChildren<Doorway>();
  105. for (int i = 0; i < allDoorways.Length; i++)
  106. {
  107. var doorway = allDoorways[i];
  108. Vector3 localPosition = doorway.transform.position;
  109. Quaternion localRotation = doorway.transform.rotation;
  110. var proxyDoorway = new DoorwayProxy(this, i, doorway, localPosition, localRotation);
  111. doorways.Add(proxyDoorway);
  112. if (PrefabTile.Entrances.Contains(doorway))
  113. Entrances.Add(proxyDoorway);
  114. if (PrefabTile.Exits.Contains(doorway))
  115. Exits.Add(proxyDoorway);
  116. if (allowedDoorwayPredicate != null && !allowedDoorwayPredicate(doorway, i))
  117. proxyDoorway.IsDisabled = true;
  118. }
  119. // Calculate bounds if missing
  120. if (!PrefabTile.HasValidBounds)
  121. PrefabTile.RecalculateBounds();
  122. Placement.LocalBounds = PrefabTile.Placement.LocalBounds;
  123. }
  124. public void PositionBySocket(DoorwayProxy myDoorway, DoorwayProxy otherDoorway)
  125. {
  126. Quaternion targetRotation = Quaternion.LookRotation(-otherDoorway.Forward, otherDoorway.Up);
  127. Placement.Rotation = targetRotation * Quaternion.Inverse(Quaternion.Inverse(Placement.Rotation) * (Placement.Rotation * myDoorway.LocalRotation));
  128. Vector3 targetPosition = otherDoorway.Position;
  129. Placement.Position = targetPosition - (myDoorway.Position - Placement.Position);
  130. }
  131. public bool IsOverlapping(TileProxy other, float maxOverlap)
  132. {
  133. return UnityUtil.AreBoundsOverlapping(Placement.Bounds, other.Placement.Bounds, maxOverlap);
  134. }
  135. public bool IsOverlappingOrOverhanging(TileProxy other, AxisDirection upDirection, float maxOverlap)
  136. {
  137. return UnityUtil.AreBoundsOverlappingOrOverhanging(Placement.Bounds, other.Placement.Bounds, upDirection, maxOverlap);
  138. }
  139. }
  140. }