NavMeshPrefabInstanceEditor.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using System.Collections.Generic;
  2. using UnityEditor;
  3. using UnityEngine;
  4. using UnityEngine.AI;
  5. [CanEditMultipleObjects]
  6. [CustomEditor(typeof(NavMeshPrefabInstance))]
  7. class NavMeshPrefabInstanceEditor : Editor
  8. {
  9. SerializedProperty m_FollowTransformProp;
  10. SerializedProperty m_NavMeshDataProp;
  11. public void OnEnable()
  12. {
  13. m_FollowTransformProp = serializedObject.FindProperty("m_FollowTransform");
  14. m_NavMeshDataProp = serializedObject.FindProperty("m_NavMesh");
  15. }
  16. public override void OnInspectorGUI()
  17. {
  18. var instance = (NavMeshPrefabInstance)target;
  19. var go = instance.gameObject;
  20. serializedObject.Update();
  21. GUI.enabled = false;
  22. EditorGUILayout.PropertyField(m_NavMeshDataProp);
  23. GUI.enabled = true;
  24. EditorGUILayout.PropertyField(m_FollowTransformProp);
  25. EditorGUILayout.Space();
  26. OnInspectorGUIPrefab(go);
  27. serializedObject.ApplyModifiedProperties();
  28. }
  29. void OnInspectorGUIPrefab(GameObject go)
  30. {
  31. var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
  32. var path = AssetDatabase.GetAssetPath(prefab);
  33. if (prefab && string.IsNullOrEmpty(path))
  34. {
  35. if (GUILayout.Button("Select the Prefab asset to bake or clear the navmesh", EditorStyles.helpBox))
  36. {
  37. Selection.activeObject = PrefabUtility.GetCorrespondingObjectFromSource(go);
  38. EditorGUIUtility.PingObject(Selection.activeObject);
  39. }
  40. }
  41. if (string.IsNullOrEmpty(path))
  42. return;
  43. GUILayout.BeginHorizontal();
  44. GUILayout.Space(EditorGUIUtility.labelWidth);
  45. if (GUILayout.Button("Clear"))
  46. OnClear();
  47. if (GUILayout.Button("Bake"))
  48. OnBake();
  49. GUILayout.EndHorizontal();
  50. }
  51. NavMeshData Build(NavMeshPrefabInstance instance)
  52. {
  53. var root = instance.transform;
  54. var sources = new List<NavMeshBuildSource>();
  55. var markups = new List<NavMeshBuildMarkup>();
  56. UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
  57. root, ~0, NavMeshCollectGeometry.RenderMeshes, 0, markups, instance.gameObject.scene, sources);
  58. var settings = NavMesh.GetSettingsByID(0);
  59. var bounds = new Bounds(Vector3.zero, 1000.0f * Vector3.one);
  60. var navmesh = NavMeshBuilder.BuildNavMeshData(settings, sources, bounds, root.position, root.rotation);
  61. navmesh.name = "Navmesh";
  62. return navmesh;
  63. }
  64. void OnClear()
  65. {
  66. foreach (var tgt in targets)
  67. {
  68. var instance = (NavMeshPrefabInstance)tgt;
  69. var go = instance.gameObject;
  70. var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
  71. var path = AssetDatabase.GetAssetPath(prefab);
  72. if (string.IsNullOrEmpty(path))
  73. {
  74. Debug.LogError("GameObject: " + go + " has no valid prefab path");
  75. continue;
  76. }
  77. DestroyNavMeshData(path);
  78. AssetDatabase.SaveAssets();
  79. }
  80. }
  81. void OnBake()
  82. {
  83. foreach (var tgt in targets)
  84. {
  85. var instance = (NavMeshPrefabInstance)tgt;
  86. var go = instance.gameObject;
  87. var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
  88. var path = AssetDatabase.GetAssetPath(prefab);
  89. if (string.IsNullOrEmpty(path))
  90. {
  91. Debug.LogError("GameObject: " + go + " has no valid prefab path");
  92. continue;
  93. }
  94. DestroyNavMeshData(path);
  95. // Store navmesh as a sub-asset of the prefab
  96. var navmesh = Build(instance);
  97. AssetDatabase.AddObjectToAsset(navmesh, prefab);
  98. instance.navMeshData = navmesh;
  99. AssetDatabase.SaveAssets();
  100. }
  101. }
  102. void DestroyNavMeshData(string path)
  103. {
  104. // Destroy and remove all existing NavMeshData sub-assets
  105. var assets = AssetDatabase.LoadAllAssetsAtPath(path);
  106. foreach (var o in assets)
  107. {
  108. var data = o as NavMeshData;
  109. if (data != null)
  110. DestroyImmediate(o, true);
  111. }
  112. }
  113. [DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
  114. static void RenderGizmo(NavMeshPrefabInstance instance, GizmoType gizmoType)
  115. {
  116. if (!EditorApplication.isPlaying)
  117. instance.UpdateInstance();
  118. }
  119. }