NavMeshLinkEditor.cs 10 KB

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