实现效果
地面ground, 连接地面的bridge, 寻路数据都是在运行时生成的,而不是一开始bake生成好的
动态生成寻路数据的核心类NavMeshBuilder
使用NavMeshBuilder.UpdateNavMeshData来生成寻路数据。对于物体很多的情况建议使用异步版本UpdateNavMeshDataAsync来避免卡顿
其他涉及的类
NavMeshData
NavMeshDataInstance
NavMeshBuildSource
NavMeshBuildSettings
这边还用到了相机控制和角色行走的代码(参考之前的博文,分别挂在Main Camera和Player/Capsule上了),下面的脚本挂在NavMeshBuild上了
鼠标左键点击ground之间的柱子,就可以生成两个地面之间的桥梁(黄色)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[DefaultExecutionOrder(-102)]
public class NavMeshTest2 : MonoBehaviour
{
public Transform bridgePrefab;
public Vector3 _navMeshSize = new Vector3(10, 10, 10);
public Transform _navMeshBuildSource;
private Bounds _tempBounds = new Bounds();
private NavMeshData _navMeshData;
private NavMeshDataInstance _navMeshDataInst;
private List _meshFilterList = new List();
private List _navMeshBuildSourceList = new List();
private AsyncOperation _operation;
void OnEnable()
{
if (null == _navMeshData)
{
_navMeshData = new NavMeshData();
_navMeshDataInst = NavMesh.AddNavMeshData(_navMeshData);
}
UpdateNavMeshBuildSource();
UpdateNavMesh();
}
private void UpdateNavMeshBuildSource()
{
_meshFilterList.Clear();
_navMeshBuildSourceList.Clear();
_navMeshBuildSource.GetComponentsInChildren(false, _meshFilterList);
for (var i = 0; i < _meshFilterList.Count; ++i)
{
var meshFilter = _meshFilterList[i];
if (meshFilter == null) continue;
var mesh = meshFilter.sharedMesh;
if (mesh == null) continue;
var s = new NavMeshBuildSource();
s.shape = NavMeshBuildSourceShape.Mesh;
s.sourceObject = mesh;
s.transform = meshFilter.transform.localToWorldMatrix;
s.area = 0;
_navMeshBuildSourceList.Add(s);
}
}
private void UpdateNavMesh()
{
var defaultSettings = NavMesh.GetSettingsByID(0);
_tempBounds.center = transform.position;
_tempBounds.size = _navMeshSize;
NavMeshBuilder.UpdateNavMeshData(_navMeshData, defaultSettings, _navMeshBuildSourceList, _tempBounds);
//var operation = NavMeshBuilder.UpdateNavMeshDataAsync(_navMeshData, defaultSettings, _navMeshBuildSourceList, _navMeshBuildBounds);
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
const int maxDistance = 300;
var ray = Camera.main.ScreenPointToRay(Input.mousePosition); //摄像机方向发射1条射线
if (Physics.Raycast(ray, out var hit, maxDistance, 1 << LayerMask.NameToLayer("bridge raycast")))
{
if (null == _navMeshBuildSource.Find(hit.transform.name))
{
var bridgeTrans = GameObject.Instantiate(bridgePrefab, _navMeshBuildSource, false);
bridgeTrans.gameObject.SetActive(true);
var pos = hit.point;
pos.y = bridgeTrans.position.y;
bridgeTrans.position = pos;
bridgeTrans.name = hit.transform.name;
UpdateNavMeshBuildSource();
UpdateNavMesh();
}
return;
}
}
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube(transform.position, _navMeshSize);
}
}
一定要把脚本的执行顺序设置的比NavMeshAgent先执行,否则会有以下警告信息。这边设置了[DefaultExecutionOrder(-102)]
【参考】
Unity3D新版NavMesh系统功能初步探索 – 知乎 (zhihu.com)
Original: https://www.cnblogs.com/sailJs/p/16366797.html
Author: yanghui01
Title: NavMesh-动态生成寻路数据
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/583504/
转载文章受原作者版权保护。转载请注明原作者出处!