説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

NavMeshLinkEditor.cs 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. using UnityEditor;
  2. using UnityEngine;
  3. namespace Unity.AI.Navigation.Editor
  4. {
  5. [CanEditMultipleObjects]
  6. [CustomEditor(typeof(NavMeshLink))]
  7. class NavMeshLinkEditor : UnityEditor.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. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  17. SerializedProperty m_EndTransform;
  18. SerializedProperty m_StartTransform;
  19. SerializedProperty m_Activated;
  20. #endif
  21. SerializedProperty m_Width;
  22. static int s_SelectedID;
  23. static int s_SelectedPoint = -1;
  24. static Color s_HandleColor = new Color(255f, 167f, 39f, 210f) / 255;
  25. static Color s_HandleColorDisabled = new Color(255f * 0.75f, 167f * 0.75f, 39f * 0.75f, 100f) / 255;
  26. void OnEnable()
  27. {
  28. m_AgentTypeID = serializedObject.FindProperty("m_AgentTypeID");
  29. m_Area = serializedObject.FindProperty("m_Area");
  30. m_CostModifier = serializedObject.FindProperty("m_CostModifier");
  31. m_AutoUpdatePosition = serializedObject.FindProperty("m_AutoUpdatePosition");
  32. m_Bidirectional = serializedObject.FindProperty("m_Bidirectional");
  33. m_EndPoint = serializedObject.FindProperty("m_EndPoint");
  34. m_StartPoint = serializedObject.FindProperty("m_StartPoint");
  35. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  36. m_EndTransform = serializedObject.FindProperty("m_EndTransform");
  37. m_StartTransform = serializedObject.FindProperty("m_StartTransform");
  38. m_Activated = serializedObject.FindProperty("m_Activated");
  39. #endif
  40. m_Width = serializedObject.FindProperty("m_Width");
  41. s_SelectedID = 0;
  42. s_SelectedPoint = -1;
  43. #if !UNITY_2022_2_OR_NEWER
  44. NavMeshVisualizationSettings.showNavigation++;
  45. #endif
  46. }
  47. #if !UNITY_2022_2_OR_NEWER
  48. void OnDisable()
  49. {
  50. NavMeshVisualizationSettings.showNavigation--;
  51. }
  52. #endif
  53. static Matrix4x4 UnscaledLocalToWorldMatrix(Transform t)
  54. {
  55. return Matrix4x4.TRS(t.position, t.rotation, Vector3.one);
  56. }
  57. static void AlignTransformToEndPoints(NavMeshLink navLink)
  58. {
  59. var mat = UnscaledLocalToWorldMatrix(navLink.transform);
  60. var worldStartPt = mat.MultiplyPoint(navLink.localStartPosition);
  61. var worldEndPt = mat.MultiplyPoint(navLink.localEndPosition);
  62. var forward = worldEndPt - worldStartPt;
  63. var up = navLink.transform.up;
  64. // Flatten
  65. forward -= Vector3.Dot(up, forward) * up;
  66. var transform = navLink.transform;
  67. transform.rotation = Quaternion.LookRotation(forward, up);
  68. transform.position = (worldEndPt + worldStartPt) * 0.5f;
  69. transform.localScale = Vector3.one;
  70. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  71. if (navLink.startRelativeToThisGameObject)
  72. navLink.startPoint = transform.InverseTransformPoint(worldStartPt);
  73. if (navLink.endRelativeToThisGameObject)
  74. navLink.endPoint = transform.InverseTransformPoint(worldEndPt);
  75. #else
  76. navLink.startPoint = transform.InverseTransformPoint(worldStartPt);
  77. navLink.endPoint = transform.InverseTransformPoint(worldEndPt);
  78. #endif
  79. }
  80. public override void OnInspectorGUI()
  81. {
  82. serializedObject.Update();
  83. NavMeshComponentsGUIUtility.AgentTypePopup("Agent Type", m_AgentTypeID);
  84. EditorGUILayout.Space();
  85. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  86. m_StartPoint.isExpanded = EditorGUILayout.Foldout(m_StartPoint.isExpanded, "Positions");
  87. if (m_StartPoint.isExpanded)
  88. {
  89. EditorGUI.indentLevel++;
  90. EditorGUI.BeginChangeCheck();
  91. EditorGUILayout.PropertyField(m_StartTransform);
  92. if (EditorGUI.EndChangeCheck())
  93. m_StartPoint.vector3Value = Vector3.zero;
  94. EditorGUILayout.PropertyField(m_StartPoint);
  95. EditorGUI.BeginChangeCheck();
  96. EditorGUILayout.PropertyField(m_EndTransform);
  97. if (EditorGUI.EndChangeCheck())
  98. m_EndPoint.vector3Value = Vector3.zero;
  99. EditorGUILayout.PropertyField(m_EndPoint);
  100. GUILayout.BeginHorizontal();
  101. GUILayout.Space(EditorGUIUtility.labelWidth);
  102. if (GUILayout.Button(new GUIContent("Swap", "Alter link direction by swapping the start and end")))
  103. {
  104. Swap(targets);
  105. SceneView.RepaintAll();
  106. }
  107. if (GUILayout.Button(new GUIContent("Re-Center Origin",
  108. "Place this GameObject at the middle point between the start and end of this link.")))
  109. {
  110. foreach (var nml in targets)
  111. {
  112. var navLink = (NavMeshLink)nml;
  113. Undo.RecordObject(navLink.transform, "Align Transform to End Points");
  114. Undo.RecordObject(navLink, "Align Transform to End Points");
  115. AlignTransformToEndPoints(navLink);
  116. }
  117. SceneView.RepaintAll();
  118. }
  119. GUILayout.EndHorizontal();
  120. EditorGUI.indentLevel--;
  121. }
  122. #else
  123. EditorGUILayout.PropertyField(m_StartPoint);
  124. EditorGUILayout.PropertyField(m_EndPoint);
  125. GUILayout.BeginHorizontal();
  126. GUILayout.Space(EditorGUIUtility.labelWidth);
  127. if (GUILayout.Button("Swap"))
  128. {
  129. foreach (NavMeshLink navLink in targets)
  130. {
  131. var tmp = navLink.startPoint;
  132. navLink.startPoint = navLink.endPoint;
  133. navLink.endPoint = tmp;
  134. }
  135. SceneView.RepaintAll();
  136. }
  137. if (GUILayout.Button("Align Transform"))
  138. {
  139. foreach (NavMeshLink navLink in targets)
  140. {
  141. Undo.RecordObject(navLink.transform, "Align Transform to End Points");
  142. Undo.RecordObject(navLink, "Align Transform to End Points");
  143. AlignTransformToEndPoints(navLink);
  144. }
  145. SceneView.RepaintAll();
  146. }
  147. GUILayout.EndHorizontal();
  148. #endif
  149. EditorGUILayout.Space();
  150. EditorGUILayout.PropertyField(m_Width);
  151. EditorGUILayout.PropertyField(m_CostModifier);
  152. EditorGUILayout.PropertyField(m_AutoUpdatePosition);
  153. EditorGUILayout.PropertyField(m_Bidirectional);
  154. NavMeshComponentsGUIUtility.AreaPopup("Area Type", m_Area);
  155. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  156. EditorGUILayout.PropertyField(m_Activated);
  157. #endif
  158. serializedObject.ApplyModifiedProperties();
  159. EditorGUILayout.Space();
  160. }
  161. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  162. private static void Swap(Object[] targets)
  163. {
  164. foreach (NavMeshLink navLink in targets)
  165. {
  166. var tmpStartPoint = navLink.startPoint;
  167. var tmpStartTransform = navLink.startTransform;
  168. navLink.startTransform = navLink.endTransform;
  169. navLink.startPoint = navLink.endPoint;
  170. navLink.endTransform = tmpStartTransform;
  171. navLink.endPoint = tmpStartPoint;
  172. }
  173. }
  174. #endif
  175. static Vector3 CalcLinkRight(NavMeshLink navLink)
  176. {
  177. var dir = navLink.localEndPosition - navLink.localStartPosition;
  178. return (new Vector3(-dir.z, 0.0f, dir.x)).normalized;
  179. }
  180. static void DrawLink(NavMeshLink navLink)
  181. {
  182. var right = CalcLinkRight(navLink);
  183. var rad = navLink.width * 0.5f;
  184. var edgeRadius = right * rad;
  185. var startPos = navLink.localStartPosition;
  186. var endPos = navLink.localEndPosition;
  187. var corners = new Vector3[4]
  188. {
  189. startPos - edgeRadius,
  190. startPos + edgeRadius,
  191. endPos + edgeRadius,
  192. endPos - edgeRadius
  193. };
  194. Gizmos.DrawLineStrip(corners, true);
  195. }
  196. #if !UNITY_2022_2_OR_NEWER
  197. [DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
  198. #else
  199. [DrawGizmo(GizmoType.InSelectionHierarchy | GizmoType.Active | GizmoType.Pickable)]
  200. #endif
  201. static void RenderBoxGizmo(NavMeshLink navLink, GizmoType gizmoType)
  202. {
  203. if (!EditorApplication.isPlaying && navLink.isActiveAndEnabled && navLink.HaveTransformsChanged())
  204. navLink.UpdateLink();
  205. var color = s_HandleColor;
  206. if (!navLink.enabled)
  207. color = s_HandleColorDisabled;
  208. var oldColor = Gizmos.color;
  209. var oldMatrix = Gizmos.matrix;
  210. Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
  211. Gizmos.color = color;
  212. DrawLink(navLink);
  213. Gizmos.matrix = oldMatrix;
  214. Gizmos.color = oldColor;
  215. Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
  216. }
  217. [DrawGizmo(GizmoType.NotInSelectionHierarchy | GizmoType.Pickable)]
  218. static void RenderBoxGizmoNotSelected(NavMeshLink navLink, GizmoType gizmoType)
  219. {
  220. if (!EditorApplication.isPlaying && navLink.isActiveAndEnabled && navLink.HaveTransformsChanged())
  221. navLink.UpdateLink();
  222. #if !UNITY_2022_2_OR_NEWER
  223. if (NavMeshVisualizationSettings.showNavigation > 0)
  224. #endif
  225. {
  226. var color = s_HandleColor;
  227. if (!navLink.enabled)
  228. color = s_HandleColorDisabled;
  229. var oldColor = Gizmos.color;
  230. var oldMatrix = Gizmos.matrix;
  231. Gizmos.matrix = UnscaledLocalToWorldMatrix(navLink.transform);
  232. Gizmos.color = color;
  233. DrawLink(navLink);
  234. Gizmos.matrix = oldMatrix;
  235. Gizmos.color = oldColor;
  236. }
  237. Gizmos.DrawIcon(navLink.transform.position, "NavMeshLink Icon", true);
  238. }
  239. public void OnSceneGUI()
  240. {
  241. var navLink = (NavMeshLink)target;
  242. if (!navLink.enabled)
  243. return;
  244. var mat = UnscaledLocalToWorldMatrix(navLink.transform);
  245. var worldStartPt = mat.MultiplyPoint(navLink.localStartPosition);
  246. var worldEndPt = mat.MultiplyPoint(navLink.localEndPosition);
  247. var worldMidPt = Vector3.Lerp(worldStartPt, worldEndPt, 0.35f);
  248. var startSize = HandleUtility.GetHandleSize(worldStartPt);
  249. var endSize = HandleUtility.GetHandleSize(worldEndPt);
  250. var midSize = HandleUtility.GetHandleSize(worldMidPt);
  251. var zup = Quaternion.FromToRotation(Vector3.forward, Vector3.up);
  252. var right = mat.MultiplyVector(CalcLinkRight(navLink));
  253. var oldColor = Handles.color;
  254. Handles.color = s_HandleColor;
  255. Vector3 newWorldPos;
  256. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  257. var startRelativeToThisGameObject = navLink.startRelativeToThisGameObject;
  258. if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 0)
  259. {
  260. EditorGUI.BeginChangeCheck();
  261. if (startRelativeToThisGameObject)
  262. Handles.CubeHandleCap(0, worldStartPt, zup, 0.1f * startSize, Event.current.type);
  263. else
  264. Handles.SphereHandleCap(0, worldStartPt, zup, 0.1f * startSize, Event.current.type);
  265. newWorldPos = Handles.PositionHandle(worldStartPt, navLink.transform.rotation);
  266. if (EditorGUI.EndChangeCheck())
  267. {
  268. Undo.RecordObject(navLink, "Move link start point");
  269. if (startRelativeToThisGameObject)
  270. navLink.startPoint = mat.inverse.MultiplyPoint(newWorldPos);
  271. else
  272. navLink.startPoint = newWorldPos - navLink.startTransform.position;
  273. }
  274. }
  275. else
  276. {
  277. if (Handles.Button(worldStartPt, zup, 0.1f * startSize, 0.1f * startSize,
  278. startRelativeToThisGameObject ? Handles.CubeHandleCap : Handles.SphereHandleCap))
  279. {
  280. s_SelectedPoint = 0;
  281. s_SelectedID = navLink.GetInstanceID();
  282. }
  283. }
  284. #else
  285. if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 0)
  286. {
  287. EditorGUI.BeginChangeCheck();
  288. Handles.CubeHandleCap(0, worldStartPt, zup, 0.1f * startSize, Event.current.type);
  289. newWorldPos = Handles.PositionHandle(worldStartPt, navLink.transform.rotation);
  290. if (EditorGUI.EndChangeCheck())
  291. {
  292. Undo.RecordObject(navLink, "Move link point");
  293. navLink.startPoint = mat.inverse.MultiplyPoint(newWorldPos);
  294. }
  295. }
  296. else
  297. {
  298. if (Handles.Button(worldStartPt, zup, 0.1f * startSize, 0.1f * startSize, Handles.CubeHandleCap))
  299. {
  300. s_SelectedPoint = 0;
  301. s_SelectedID = navLink.GetInstanceID();
  302. }
  303. }
  304. #endif
  305. #if ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK
  306. var endRelativeToThisGameObject = navLink.endRelativeToThisGameObject;
  307. if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 1)
  308. {
  309. EditorGUI.BeginChangeCheck();
  310. if (endRelativeToThisGameObject)
  311. Handles.CubeHandleCap(0, worldEndPt, zup, 0.1f * endSize, Event.current.type);
  312. else
  313. Handles.SphereHandleCap(0, worldEndPt, zup, 0.1f * endSize, Event.current.type);
  314. newWorldPos = Handles.PositionHandle(worldEndPt, navLink.transform.rotation);
  315. if (EditorGUI.EndChangeCheck())
  316. {
  317. Undo.RecordObject(navLink, "Move link end point");
  318. if (endRelativeToThisGameObject)
  319. navLink.endPoint = mat.inverse.MultiplyPoint(newWorldPos);
  320. else
  321. navLink.endPoint = newWorldPos - navLink.endTransform.position;
  322. }
  323. }
  324. else
  325. {
  326. if (Handles.Button(worldEndPt, zup, 0.1f * endSize, 0.1f * endSize,
  327. endRelativeToThisGameObject ? Handles.CubeHandleCap : Handles.SphereHandleCap))
  328. {
  329. s_SelectedPoint = 1;
  330. s_SelectedID = navLink.GetInstanceID();
  331. }
  332. }
  333. #else
  334. if (navLink.GetInstanceID() == s_SelectedID && s_SelectedPoint == 1)
  335. {
  336. EditorGUI.BeginChangeCheck();
  337. Handles.CubeHandleCap(0, worldEndPt, zup, 0.1f * endSize, Event.current.type);
  338. newWorldPos = Handles.PositionHandle(worldEndPt, navLink.transform.rotation);
  339. if (EditorGUI.EndChangeCheck())
  340. {
  341. Undo.RecordObject(navLink, "Move link point");
  342. navLink.endPoint = mat.inverse.MultiplyPoint(newWorldPos);
  343. }
  344. }
  345. else
  346. {
  347. if (Handles.Button(worldEndPt, zup, 0.1f * endSize, 0.1f * endSize, Handles.CubeHandleCap))
  348. {
  349. s_SelectedPoint = 1;
  350. s_SelectedID = navLink.GetInstanceID();
  351. }
  352. }
  353. #endif
  354. EditorGUI.BeginChangeCheck();
  355. newWorldPos = Handles.Slider(worldMidPt + right * navLink.width * 0.5f, right, midSize * 0.03f, Handles.DotHandleCap, 0);
  356. if (EditorGUI.EndChangeCheck())
  357. {
  358. Undo.RecordObject(navLink, "Adjust link width");
  359. navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(right, (newWorldPos - worldMidPt)));
  360. }
  361. EditorGUI.BeginChangeCheck();
  362. newWorldPos = Handles.Slider(worldMidPt - right * navLink.width * 0.5f, -right, midSize * 0.03f, Handles.DotHandleCap, 0);
  363. if (EditorGUI.EndChangeCheck())
  364. {
  365. Undo.RecordObject(navLink, "Adjust link width");
  366. navLink.width = Mathf.Max(0.0f, 2.0f * Vector3.Dot(-right, (newWorldPos - worldMidPt)));
  367. }
  368. Handles.color = oldColor;
  369. }
  370. [MenuItem("GameObject/AI/NavMesh Link", false, 2002)]
  371. public static void CreateNavMeshLink(MenuCommand menuCommand)
  372. {
  373. var parent = menuCommand.context as GameObject;
  374. GameObject go = NavMeshComponentsGUIUtility.CreateAndSelectGameObject("NavMesh Link", parent);
  375. go.AddComponent<NavMeshLink>();
  376. var view = SceneView.lastActiveSceneView;
  377. if (view != null)
  378. view.MoveToView(go.transform);
  379. }
  380. }
  381. }