NavMeshLink.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.AI;
  4. #pragma warning disable IDE1006 // Unity-specific lower case public property names
  5. namespace Unity.AI.Navigation
  6. {
  7. /// <summary> Component used to create a navigable link between two NavMesh locations. </summary>
  8. [ExecuteAlways]
  9. [DefaultExecutionOrder(-101)]
  10. [AddComponentMenu("Navigation/NavMeshLink", 33)]
  11. [HelpURL(HelpUrls.Manual + "NavMeshLink.html")]
  12. public class NavMeshLink : MonoBehaviour
  13. {
  14. [SerializeField]
  15. int m_AgentTypeID;
  16. [SerializeField]
  17. Vector3 m_StartPoint = new Vector3(0.0f, 0.0f, -2.5f);
  18. [SerializeField]
  19. Vector3 m_EndPoint = new Vector3(0.0f, 0.0f, 2.5f);
  20. [SerializeField]
  21. float m_Width;
  22. [SerializeField]
  23. int m_CostModifier = -1;
  24. [SerializeField]
  25. bool m_Bidirectional = true;
  26. [SerializeField]
  27. bool m_AutoUpdatePosition;
  28. [SerializeField]
  29. int m_Area;
  30. /// <summary> Gets or sets the type of agent that can use the link. </summary>
  31. public int agentTypeID { get { return m_AgentTypeID; } set { m_AgentTypeID = value; UpdateLink(); } }
  32. /// <summary> Gets or sets the position at the middle of the link's start edge. </summary>
  33. /// <remarks> The position is relative to the GameObject transform. </remarks>
  34. public Vector3 startPoint { get { return m_StartPoint; } set { m_StartPoint = value; UpdateLink(); } }
  35. /// <summary> Gets or sets the position at the middle of the link's end edge. </summary>
  36. /// <remarks> The position is relative to the GameObject transform. </remarks>
  37. public Vector3 endPoint { get { return m_EndPoint; } set { m_EndPoint = value; UpdateLink(); } }
  38. /// <summary> The width of the segments making up the ends of the link. </summary>
  39. /// <remarks> The segments are created perpendicular to the line from start to end,in the XZ plane of the GameObject. </remarks>
  40. public float width { get { return m_Width; } set { m_Width = value; UpdateLink(); } }
  41. /// <summary> Gets or sets a value that determines the cost of traversing the link.</summary>
  42. /// <remarks> A negative value implies that the traversal cost is obtained based on the area type.
  43. /// A positive or zero value applies immediately, overriding the cost associated with the area type.</remarks>
  44. public int costModifier { get { return m_CostModifier; } set { m_CostModifier = value; UpdateLink(); } }
  45. /// <summary> Gets or sets whether the link can be traversed in both directions. </summary>
  46. /// <remarks> A link that connects to NavMeshes at both ends can always be traversed from the start position to the end position. When this property is set to `true` it allows the agents to traverse the link also in the direction from end to start. When the value is `false` the agents will never move over the link from the end position to the start position.</remarks>
  47. public bool bidirectional { get { return m_Bidirectional; } set { m_Bidirectional = value; UpdateLink(); } }
  48. /// <summary> Gets or sets whether the world positions of the link's edges update whenever
  49. /// the GameObject transform changes at runtime. </summary>
  50. public bool autoUpdate { get { return m_AutoUpdatePosition; } set { SetAutoUpdate(value); } }
  51. /// <summary> The area type of the link. </summary>
  52. public int area { get { return m_Area; } set { m_Area = value; UpdateLink(); } }
  53. NavMeshLinkInstance m_LinkInstance = new NavMeshLinkInstance();
  54. Vector3 m_LastPosition = Vector3.zero;
  55. Quaternion m_LastRotation = Quaternion.identity;
  56. static readonly List<NavMeshLink> s_Tracked = new List<NavMeshLink>();
  57. void OnEnable()
  58. {
  59. AddLink();
  60. if (m_AutoUpdatePosition && m_LinkInstance.valid)
  61. AddTracking(this);
  62. }
  63. void OnDisable()
  64. {
  65. RemoveTracking(this);
  66. m_LinkInstance.Remove();
  67. }
  68. /// <summary> Replaces the link with a new one using the current settings. </summary>
  69. public void UpdateLink()
  70. {
  71. m_LinkInstance.Remove();
  72. AddLink();
  73. }
  74. static void AddTracking(NavMeshLink link)
  75. {
  76. #if UNITY_EDITOR
  77. if (s_Tracked.Contains(link))
  78. {
  79. Debug.LogError("Link is already tracked: " + link);
  80. return;
  81. }
  82. #endif
  83. if (s_Tracked.Count == 0)
  84. NavMesh.onPreUpdate += UpdateTrackedInstances;
  85. s_Tracked.Add(link);
  86. }
  87. static void RemoveTracking(NavMeshLink link)
  88. {
  89. s_Tracked.Remove(link);
  90. if (s_Tracked.Count == 0)
  91. NavMesh.onPreUpdate -= UpdateTrackedInstances;
  92. }
  93. void SetAutoUpdate(bool value)
  94. {
  95. if (m_AutoUpdatePosition == value)
  96. return;
  97. m_AutoUpdatePosition = value;
  98. if (value)
  99. AddTracking(this);
  100. else
  101. RemoveTracking(this);
  102. }
  103. void AddLink()
  104. {
  105. #if UNITY_EDITOR
  106. if (m_LinkInstance.valid)
  107. {
  108. Debug.LogError("Link is already added: " + this);
  109. return;
  110. }
  111. #endif
  112. var link = new NavMeshLinkData();
  113. link.startPosition = m_StartPoint;
  114. link.endPosition = m_EndPoint;
  115. link.width = m_Width;
  116. link.costModifier = m_CostModifier;
  117. link.bidirectional = m_Bidirectional;
  118. link.area = m_Area;
  119. link.agentTypeID = m_AgentTypeID;
  120. m_LinkInstance = NavMesh.AddLink(link, transform.position, transform.rotation);
  121. if (m_LinkInstance.valid)
  122. m_LinkInstance.owner = this;
  123. m_LastPosition = transform.position;
  124. m_LastRotation = transform.rotation;
  125. }
  126. bool HasTransformChanged()
  127. {
  128. if (m_LastPosition != transform.position)
  129. return true;
  130. if (m_LastRotation != transform.rotation)
  131. return true;
  132. return false;
  133. }
  134. void OnDidApplyAnimationProperties()
  135. {
  136. UpdateLink();
  137. }
  138. static void UpdateTrackedInstances()
  139. {
  140. foreach (var instance in s_Tracked)
  141. {
  142. if (instance.HasTransformChanged())
  143. instance.UpdateLink();
  144. }
  145. }
  146. #if UNITY_EDITOR
  147. void OnValidate()
  148. {
  149. m_Width = Mathf.Max(0.0f, m_Width);
  150. if (!m_LinkInstance.valid)
  151. return;
  152. UpdateLink();
  153. if (!m_AutoUpdatePosition)
  154. {
  155. RemoveTracking(this);
  156. }
  157. else if (!s_Tracked.Contains(this))
  158. {
  159. AddTracking(this);
  160. }
  161. }
  162. #endif
  163. }
  164. }