Demo:https://download.csdn.net/download/fireworksflower/11594547
如果你去查找资料,可以找到一堆关于NavMeshComponents的内容(都是一些5.4左右版本),但是对于NavMeshPrefabInstance(unity2018)几乎没有(本人找到了官方的但是都是英文,而且很麻烦)所以,我就自己找问题。
1.想要将预制体和NavMeshDate绑定在一起肯定少不了NavMeshPrefabInstance.cs脚本。
就自己修改了一下代码:
1.找到脚本NavMeshPrefabInstanceEditor.cs
源码是这样的:
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
[CanEditMultipleObjects]
[CustomEditor(typeof(NavMeshPrefabInstance))]
class NavMeshPrefabInstanceEditor : Editor
{
SerializedProperty m_FollowTransformProp;
SerializedProperty m_NavMeshDataProp;
public void OnEnable()
{
m_FollowTransformProp = serializedObject.FindProperty("m_FollowTransform");
m_NavMeshDataProp = serializedObject.FindProperty("m_NavMesh");
}
public override void OnInspectorGUI()
{
var instance = (NavMeshPrefabInstance)target;
var go = instance.gameObject;
serializedObject.Update();
GUI.enabled = false;
EditorGUILayout.PropertyField(m_NavMeshDataProp);
GUI.enabled = true;
EditorGUILayout.PropertyField(m_FollowTransformProp);
EditorGUILayout.Space();
OnInspectorGUIPrefab(go);
serializedObject.ApplyModifiedProperties();
}
void OnInspectorGUIPrefab(GameObject go)
{
var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
var path = AssetDatabase.GetAssetPath(prefab);
if (prefab && string.IsNullOrEmpty(path))
{
if (GUILayout.Button("Select the Prefab asset to bake or clear the navmesh", EditorStyles.helpBox))
{
Selection.activeObject = PrefabUtility.GetCorrespondingObjectFromSource(go);
EditorGUIUtility.PingObject(Selection.activeObject);
}
}
if (string.IsNullOrEmpty(path))
return;
GUILayout.BeginHorizontal();
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button("Clear"))
OnClear();
if (GUILayout.Button("Bake"))
OnBake();
GUILayout.EndHorizontal();
}
NavMeshData Build(NavMeshPrefabInstance instance)
{
var root = instance.transform;
var sources = new List<NavMeshBuildSource>();
var markups = new List<NavMeshBuildMarkup>();
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
root, ~0, NavMeshCollectGeometry.RenderMeshes, 0, markups, instance.gameObject.scene, sources);
var settings = NavMesh.GetSettingsByID(0);
var bounds = new Bounds(Vector3.zero, 1000.0f * Vector3.one);
var navmesh = NavMeshBuilder.BuildNavMeshData(settings, sources, bounds, root.position, root.rotation);
navmesh.name = "Navmesh";
return navmesh;
}
void OnClear()
{
foreach (var tgt in targets)
{
var instance = (NavMeshPrefabInstance)tgt;
var go = instance.gameObject;
var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
var path = AssetDatabase.GetAssetPath(prefab);
if (string.IsNullOrEmpty(path))
{
Debug.LogError("GameObject: " + go + " has no valid prefab path");
continue;
}
DestroyNavMeshData(path);
AssetDatabase.SaveAssets();
}
}
void OnBake()
{
foreach (var tgt in targets)
{
var instance = (NavMeshPrefabInstance)tgt;
var go = instance.gameObject;
var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
var path = AssetDatabase.GetAssetPath(prefab);
if (string.IsNullOrEmpty(path))
{
Debug.LogError("GameObject: " + go + " has no valid prefab path");
continue;
}
DestroyNavMeshData(path);
// Store navmesh as a sub-asset of the prefab
var navmesh = Build(instance);
AssetDatabase.AddObjectToAsset(navmesh, prefab);
instance.navMeshData = navmesh;
AssetDatabase.SaveAssets();
}
}
void DestroyNavMeshData(string path)
{
// Destroy and remove all existing NavMeshData sub-assets
var assets = AssetDatabase.LoadAllAssetsAtPath(path);
foreach (var o in assets)
{
var data = o as NavMeshData;
if (data != null)
DestroyImmediate(o, true);
}
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
static void RenderGizmo(NavMeshPrefabInstance instance, GizmoType gizmoType)
{
if (!EditorApplication.isPlaying)
instance.UpdateInstance();
}
}
修改后:
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
[CanEditMultipleObjects]
[CustomEditor(typeof(NavMeshPrefabInstance))]
class NavMeshPrefabInstanceEditor : Editor
{
SerializedProperty m_FollowTransformProp;
SerializedProperty m_NavMeshDataProp;
public void OnEnable()
{
m_FollowTransformProp = serializedObject.FindProperty("m_FollowTransform");
m_NavMeshDataProp = serializedObject.FindProperty("m_NavMesh");
}
public override void OnInspectorGUI()
{
var instance = (NavMeshPrefabInstance)target;
var go = instance.gameObject;
serializedObject.Update();
GUI.enabled = true;
EditorGUILayout.PropertyField(m_NavMeshDataProp);
GUI.enabled = true;
EditorGUILayout.PropertyField(m_FollowTransformProp);
EditorGUILayout.Space();
OnInspectorGUIPrefab(go);
serializedObject.ApplyModifiedProperties();
}
string path = null;
void OnInspectorGUIPrefab(GameObject go)
{
if (GUILayout.Button( "Select the Prefab asset to bake or clear the navmesh", EditorStyles.helpBox ))
{
var prefab = PrefabUtility.GetCorrespondingObjectFromSource( Selection.activeObject );
path = AssetDatabase.GetAssetPath( prefab );
}
if (string.IsNullOrEmpty( path ))
return;
GUILayout.BeginHorizontal( );
GUILayout.Space( EditorGUIUtility.labelWidth );
if (GUILayout.Button( "Clear" ))
OnClear( );
if (GUILayout.Button( "Bake" ))
OnBake( );
GUILayout.EndHorizontal( );
}
NavMeshData Build(NavMeshPrefabInstance instance)
{
var root = instance.transform;
var sources = new List<NavMeshBuildSource>();
var markups = new List<NavMeshBuildMarkup>();
UnityEditor.AI.NavMeshBuilder.CollectSourcesInStage(
root, ~0, NavMeshCollectGeometry.PhysicsColliders, 0, markups, instance.gameObject.scene, sources);
var settings = NavMesh.GetSettingsByID(0);
var bounds = new Bounds(Vector3.zero, /*1000.0f * Vector3.one*/new Vector3(1000,5,1000));
var navmesh = NavMeshBuilder.BuildNavMeshData(settings, sources, bounds, root.position, root.rotation);
navmesh.name = "Navmesh";
return navmesh;
}
void OnClear()
{
foreach (var tgt in targets)
{
var instance = (NavMeshPrefabInstance)tgt;
var go = instance.gameObject;
//var prefab = PrefabUtility.GetPrefabInstanceHandle(go);
var prefab = PrefabUtility.GetCorrespondingObjectFromSource( Selection.activeObject );
var path = AssetDatabase.GetAssetPath(prefab);
if (string.IsNullOrEmpty(path))
{
Debug.LogError("GameObject: " + go + " has no valid prefab path");
continue;
}
DestroyNavMeshData(path);
AssetDatabase.SaveAssets();
}
}
void OnBake()
{
for (int i = 0 ; i < targets.Length ; i++)
{
var instance = (NavMeshPrefabInstance)targets[i];
var go = instance.gameObject;
// var prefab = PrefabUtility.GetPrefabInstanceHandle( go );
var prefab = PrefabUtility.GetCorrespondingObjectFromSource( Selection.activeObject );
var path = AssetDatabase.GetAssetPath( prefab );
if (string.IsNullOrEmpty( path ))
{
Debug.LogError( "GameObject: " + go + " has no valid prefab path" );
continue;
}
DestroyNavMeshData( path );
// Store navmesh as a sub-asset of the prefab
var navmesh = Build( instance );
AssetDatabase.AddObjectToAsset( navmesh, prefab );
GameObject TagetObj = prefab as GameObject;
TagetObj.GetComponent<NavMeshPrefabInstance>( ).navMeshData = navmesh;
AssetDatabase.SaveAssets( );
}
}
void DestroyNavMeshData(string path)
{
// Destroy and remove all existing NavMeshData sub-assets
var assets = AssetDatabase.LoadAllAssetsAtPath(path);
foreach (var o in assets)
{
var data = o as NavMeshData;
if (data != null)
DestroyImmediate(o, true);
}
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active | GizmoType.Pickable)]
static void RenderGizmo(NavMeshPrefabInstance instance, GizmoType gizmoType)
{
if (!EditorApplication.isPlaying)
instance.UpdateInstance();
}
}
主要原因是:
修改后代码:
下面两个方法也需要修改下:
下面这两行代码主要是赋值的时候出现问题了:没有赋值上,所以我小小的改动了下:
好了问题解决了
可以看看效果了
按钮出现了,点击烘焙就可以了
效果已实现。
这样就可以动态加载地图了(不是动态烘焙,它是游戏开始之前就烘焙好的)。
当然你还想要设置NavMeshDate的数据这里都是代码里:
OK。