NavMesh-动态生成寻路数据

实现效果

NavMesh-动态生成寻路数据

地面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)]

NavMesh-动态生成寻路数据

【参考】

GitHub – Unity-Technologies/NavMeshComponents: High Level API Components for Runtime NavMesh Building

Unity3D新版NavMesh系统功能初步探索 – 知乎 (zhihu.com)

Original: https://www.cnblogs.com/sailJs/p/16366797.html
Author: yanghui01
Title: NavMesh-动态生成寻路数据

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/583504/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球