NavMeshLinkEditor.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using UnityEditor;
  2. using UnityEditor.AI;
  3. using UnityEngine;
  4. using UnityEngine.AI;
  5. namespace Unity.AI.Navigation.Editor
  6. {
  7. [CanEditMultipleObjects]
  8. [CustomEditor(typeof(NavMeshLink))]
  9. class NavMeshLinkEditor : UnityEditor.Editor
  10. {
  11. SerializedProperty m_AgentTypeID;
  12. SerializedProperty m_Area;
  13. SerializedProperty m_CostModifier;
  14. SerializedProperty m_AutoUpdatePosition;
  15. SerializedProperty m_Bidirectional;
  16. SerializedProperty m_EndPoint;
  17. SerializedProperty m_StartPoint;
  18. SerializedProperty m_Width;
  19. static int s_SelectedID;
  20. static int s_SelectedPoint = -1;
  21. static Color s_HandleColor = new Color(255f, 167f, 39f, 210f) / 255;
  22. static Color s_HandleColorDisabled = new Color(255f * 0.75f, 167f * 0.75f, 39f * 0.75f, 100f) / 255;
  23. void OnEnable()
  24. {
  25. m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
  26. m_Area = serializedObject.FindProperty("m_Area");
  27. m_CostModifier = serializedObject.FindProperty("m_CostModifier");
  28. m_AutoUpdatePosition = serializedObject.FindProperty("m_AutoUpdatePosition");
  29. m_Bidirectional = serializedObject.FindProperty("m_Bidirectional");
  30. m_EndPoint = serializedObject.FindProperty("m_EndPoint");
  31. m_StartPoint = serializedObject.FindProperty("m_StartPoint");
  32. m_Width = serializedObject.FindProperty("m_Width");
  33. s_SelectedID = 0;
  34. s_SelectedPoint = -1;
  35. #if !UNITY_2022_2_OR_NEWER
  36. NavMeshVisualizationSettings.showNavigation++;
  37. #endif
  38. }
  39. #if !UNITY_2022_2_OR_NEWER
  40. void OnDisable()
  41. {
  42. NavMeshVisualizationSettings.showNavigation--;
  43. }
  44. #endif
  45. static Matrix4x4 UnscaledLocalToWorldMatrix(Transform t)
  46. {
  47. return Matrix4x4.TRS(t.position, t.rotation, Vector3.one);
  48. }
  49. static void AlignTransformToEndPoints(NavMeshLink navLink)
  50. {
  51. var mat = UnscaledLocalToWorldMatrix(navLink.transform);
  52. var worldStartPt = mat.MultiplyPoint(navLink.startPoint);
  53. var worldEndPt = mat.MultiplyPoint(navLink.endPoint);
  54. var forward = worldEndPt - worldStartPt;
  55. var up = navLink.transform.up;
  56. // Flatten
  57. forward -= Vector3.Dot(up, forward) * up;
  58. var transform = navLink.transform;
  59. transform.rotation = Quaternion.LookRotation(forward, up);
  60. transform.position = (worldEndPt + worldStartPt) * 0.5f;
  61. transform.localScale = Vector3.one;
  62. navLink.startPoint = transform.InverseTransformPoint(worldStartPt);
  63. navLink.endPoint = transform.InverseTransformPoint(worldEndPt);
  64. }
  65. public override void OnInspectorGUI()
  66. {
  67. serializedObject.Update();
  68. NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
  69. EditorGUILayout.Space();
  70. EditorGUILayout.PropertyField(m_StartPoint);
  71. EditorGUILayout.PropertyField(m_EndPoint);
  72. GUILayout.BeginHorizontal();
  73. GUILayout.Space(EditorGUIUtility.labelWidth);
  74. if (GUILayout.Button("Swap"))
  75. {
  76. foreach (NavMeshLink navLink in targets)
  77. {
  78. var tmp = navLink.startPoint;
  79. navLink.startPoint = navLink.endPoint;
  80. navLink.endPoint = tmp;
  81. }
  82. SceneView.RepaintAll();
  83. }
  84. if (GUILayout.Button("Align Transform"))
  85. {
  86. foreach (NavMeshLink navLink in targets)
  87. {
  88. Undo.RecordObject(navLink.transform, "Align Transform to End Points");
  89. Undo.RecordObject(navLink, "Align Transform to End Points");
  90. AlignTransformToEndPoints(navLink);
  91. }
  92. SceneView.RepaintAll();
  93. }
  94. GUILayout.EndHorizontal();
  95. EditorGUILayout.Space();
  96. EditorGUILayout.PropertyField(m_Width);
  97. EditorGUILayout.PropertyField(m_CostModifier);
  98. EditorGUILayout.PropertyField(m_AutoUpdatePosition);
  99. EditorGUILayout.PropertyField(m_Bidirectional);
  100. NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
  101. serializedObject.ApplyModifiedProperties();
  102. EditorGUILayout.Space();
  103. }
  104. static Vector3 CalcLinkRight(NavMeshLink navLink)
  105. {
  106. var dir = navLink.endPoint - navLink.startPoint;
  107. return (new Vector3(-dir.z, 0.0f, dir.x)).normalized;
  108. }
  109. static void DrawLink(NavMeshLink navLink)
  110. {
  111. var right = CalcLinkRight(navLink);
  112. var rad = navLink.width * 0.5f;
  113. Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.startPoint + right * rad);
  114. Gizmos.DrawLine(navLink.endPoint - right * rad, navLink.endPoint + right * rad);
  115. Gizmos.DrawLine(navLink.startPoint - right * rad, navLink.endPoint - right * rad);
  116. Gizmos.DrawLine(navLink.startPoint + right * rad, navLink.endPoint + right * rad);
  117. }
  118. #if !UNITY_2022_2_OR_NEWER
  119. [DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
  120. #else
  121. [DrawGizmo(GizmoType.InSelectionHierarchy | GizmoType.Active | GizmoType.Pickable)]
  122. #endif
  123. static void RenderBoxGizmo(NavMeshLink navLink, GizmoType gizmoType)
  124. {
  125. if (!EditorApplication.isPlaying && navLink.isActiveAndEnabled)
  126. navLink.UpdateLink();
  127. var color = s_HandleColor;
  128. if (!navLink.enabled)
  129. color = s_HandleColorDisabled;
  130. var oldColor = Gizmos.color;
  131. var oldMatrix = Gizmos.matrix;
  132. Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
  133. Gizmos.color = color;
  134. DrawLink(navLink);
  135. Gizmos.matrix = oldMatrix;
  136. Gizmos.color = oldColor;
  137. Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
  138. }
  139. [DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
  140. static void RenderBoxGizmoNotSelected(NavMeshLink navLink, GizmoType gizmoType)
  141. {
  142. #if !UNITY_2022_2_OR_NEWER
  143. if (NavMeshVisualizationSettings.showNavigation > 0)
  144. #endif
  145. {
  146. var color = s_HandleColor;
  147. if (!navLink.enabled)
  148. color = s_HandleColorDisabled;
  149. var oldColor = Gizmos.color;
  150. var oldMatrix = Gizmos.matrix;
  151. Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
  152. Gizmos.color = color;
  153. DrawLink(navLink);
  154. Gizmos.matrix = oldMatrix;
  155. Gizmos.color = oldColor;
  156. }
  157. Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
  158. }
  159. public void OnSceneGUI()
  160. {
  161. var navLink = (NavMeshLink)target;
  162. if (!navLink.enabled)
  163. return;
  164. var mat = UnscaledLocalToWorldMatrix(navLink.transform);
  165. var startPt = mat.MultiplyPoint(navLink.startPoint);
  166. var endPt = mat.MultiplyPoint(navLink.endPoint);
  167. var midPt = Vector3.Lerp(startPt, endPt, 0.35f);
  168. var startSize = HandleUtility.GetHandleSize(startPt);
  169. var endSize = HandleUtility.GetHandleSize(endPt);
  170. var midSize = HandleUtility.GetHandleSize(midPt);
  171. var zup = Quaternion.FromToRotation(Vector3.forward, Vector3.up);
  172. var right = mat.MultiplyVector(CalcLinkRight(navLink));
  173. var oldColor = Handles.color;
  174. Handles.color = s_HandleColor;
  175. Vector3 pos;
  176. if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 0)
  177. {
  178. EditorGUI.BeginChangeCheck();
  179. Handles.CubeHandleCap(0, startPt, zup, 0.1f * startSize, Event.current.type);
  180. pos = Handles.PositionHandle(startPt, navLink.transform.rotation);
  181. if (EditorGUI.EndChangeCheck())
  182. {
  183. Undo.RecordObject(navLink, "Move link point");
  184. navLink.startPoint = mat.inverse.MultiplyPoint(pos);
  185. }
  186. }
  187. else
  188. {
  189. if (Handles.Button(startPt, zup, 0.1f * startSize, 0.1f * startSize, Handles.CubeHandleCap))
  190. {
  191. s_SelectedPoint = 0;
  192. s_SelectedID = navLink.GetInstanceID();
  193. }
  194. }
  195. if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 1)
  196. {
  197. EditorGUI.BeginChangeCheck();
  198. Handles.CubeHandleCap(0, endPt, zup, 0.1f * startSize, Event.current.type);
  199. pos = Handles.PositionHandle(endPt, navLink.transform.rotation);
  200. if (EditorGUI.EndChangeCheck())
  201. {
  202. Undo.RecordObject(navLink, "Move link point");
  203. navLink.endPoint = mat.inverse.MultiplyPoint(pos);
  204. }
  205. }
  206. else
  207. {
  208. if (Handles.Button(endPt, zup, 0.1f * endSize, 0.1f * endSize, Handles.CubeHandleCap))
  209. {
  210. s_SelectedPoint = 1;
  211. s_SelectedID = navLink.GetInstanceID();
  212. }
  213. }
  214. EditorGUI.BeginChangeCheck();
  215. pos = Handles.Slider(midPt + right * navLink.width * 0.5f, right, midSize * 0.03f, Handles.DotHandleCap, 0);
  216. if (EditorGUI.EndChangeCheck())
  217. {
  218. Undo.RecordObject(navLink, "Adjust link width");
  219. navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(right, (pos - midPt)));
  220. }
  221. EditorGUI.BeginChangeCheck();
  222. pos = Handles.Slider(midPt - right * navLink.width * 0.5f, -right, midSize * 0.03f, Handles.DotHandleCap, 0);
  223. if (EditorGUI.EndChangeCheck())
  224. {
  225. Undo.RecordObject(navLink, "Adjust link width");
  226. navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(-right, (pos - midPt)));
  227. }
  228. Handles.color = oldColor;
  229. }
  230. [MenuItem("GameObject/AI/NavMesh Link", false, 2002)]
  231. public static void CreateNavMeshLink(MenuCommand menuCommand)
  232. {
  233. var parent = menuCommand.context as GameObject;
  234. GameObject go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Link", parent);
  235. go.AddComponent<NavMeshLink>();
  236. var view = SceneView.lastActiveSceneView;
  237. if (view != null)
  238. view.MoveToView(go.transform);
  239. }
  240. }
  241. }