unity2019.2 navigation navmeshagent ai寻路 静态烘焙,动态烘焙 动态障碍物 路径画线 使用教程

一 使用默认组件静态烘焙路径

静态烘焙,顾名思义,一切数据必须实现准备好,无法做到动态烘焙。实际上目前最新版本2019.3f 默认组件只支持这个。好处在于运行时速度快一些,不用即时烘焙。缺点,当然是不能即时烘焙。不够灵活。 后面还有介绍动态烘焙。

简单介绍

unity的 AI Navigation 由四部分组成:

NavMesh :数据结构。可导航的地面数据结构。
NavMesh Agent :寻路的角色需要附加此组件
NavMesh Obstacle :动态障碍物组件。
Off-Mesh Link :用于跳过的河流或障碍物,开门或解机关。

使用方法

一、创建地面

在scene中添加一个plane 或放置一个被拉成地板样子的矩形当作地面
点击地面,然后点击unity菜单栏-> windows-> AI -> Navigation
这时右面的工具栏已经打开了navigation窗口,
点击地面,再点击object分栏中的navigation static,然后再切换到bake选项卡,点击bake即可完成路线烘焙。

二、添加障碍物

在scene中创建几个方块,接着在navigation 的object分栏中的navigation static,然后点击bake按钮重新处理寻路网格。

三、添加角色

添加一个球,为其添加 navigation agent 组件。
新建一个脚本写入下列代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;//需引入此库

public class player : MonoBehaviour
{
    private NavMeshAgent agent;
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();//获取player agent组件
    }

    void Update()
    {
        if (Input.GetMouseButton(0)) {
        	//将鼠标点击的2维屏幕坐标转换为世界坐标,并发射射线
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            Physics.Raycast(ray, out hit);
            //如果射线扫到了物体,就向被扫到的点移动
            if (hit.collider != null)
                agent.destination = hit.point;
        }
    }
}

点击运行,此时你的鼠标点地面的任何位置,角色都会绕过障碍物跑过来与你相见。

四、添加画线路径

在 场景中新建一个物体,
添加 line renderer组件,
添加适当的materials
修改脚本如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class tartget : MonoBehaviour
{
    //线段 
    public Transform line;
    private LineRenderer _lineRenderer;
    //获取代理
    private NavMeshAgent agent;
    void Start()
    {
        _lineRenderer = line.GetComponent<LineRenderer>();//LineRenderer 组件
        agent = GetComponent<NavMeshAgent>();//获取player agent组件
    }
    private Vector3 targetPosition;
    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            //寻路速度
            agent.speed = 15;
            //将鼠标点击的2维屏幕坐标转换为世界坐标,并发射射线
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            Physics.Raycast(ray, out hit);
            //如果射线扫到了物体,就向被扫到的点移动
            if (hit.collider != null) {
                //跟随
                agent.destination = hit.point;

                //画线部分
                Vector3[] _path = agent.path.corners;//储存路径
                //_lineRenderer.SetVertexCount(_path.Length);//这是过时的
                _lineRenderer.positionCount = _path.Length;//设置线段数
                for (int i = 0; i < _path.Length; i++)
                {
                    _lineRenderer.SetPosition(i, _path[i]);//设置线段顶点坐标
                }
            }
        }
    }
}

然后将新建的路径物体拖入inspactor中的line对象,然后运行
可以看到,点击地面后,出现了相应的路线

五、添加可跳越或开门等触发特殊行为的点

在两个独立的地面,上各自创建一个物体(也可以是空物体)
为空物体添加navigation link组件
在link组件中,添加头尾start end 的刚才两个空物体,
这时点击角色不在的另一个地面,角色就会跑过去,别忘了设置高度。

动态障碍物

添加动态障碍物,需要添加nav mesh obstacle组件,需要注意的是该物体的navmesh设置 一定不能是static。否则烘培的时候就会影响地面结构了。

动态烘焙

非常重要的组件, 比静态烘焙重要,因为更灵活。
1 首先去git 官网下载 最新的寻路组件
https://github.com/Unity-Technologies/NavMeshComponents

2,将里面的exemple和components 文件夹拖到unity的asset目录下。
3,先建立一个空白物体。然后加入Local Nav Mesh Builder。并设置好size。需要注意的是,这个size 必须包含所有的路径物体。所有在这个size盒范围内才能生成动态路径。另外,一个场景只需要有一个这个。不需要设置多个。

4,为所有的地面、障碍物加上Nav Mesh Source Tag。地面和障碍物都要加。
5,如果你希望可以在编辑状态下预览路径的情况,可以添加Nav Mesh Surface。 但正常情况下不用加。
6,和静态设置一样,添加agent 。并做好相关设置。这样在运行但时候就可以跑起来了。

获取路径上但随机点。

做怪物自动巡航或npc自移动 非常有用

 public Vector3 GetRandomLocation()
    {
        NavMeshTriangulation navMeshData = NavMesh.CalculateTriangulation();

        int t = Random.Range(0, navMeshData.indices.Length - 3);

        Vector3 point = Vector3.Lerp(navMeshData.vertices[navMeshData.indices[t]], navMeshData.vertices[navMeshData.indices[t + 1]], Random.value);
        point = Vector3.Lerp(point, navMeshData.vertices[navMeshData.indices[t + 2]], Random.value);

        return point;
    }

该段代码可以加载任意物体任意位置。它获取的都是全局路径点。相邻的三个点 就是三角形的三个顶点,所以也可以用来生成面。

点击地面 让人物按路线移动

       NavMeshAgent navmeshagent;
   public LineRenderer lineRenderer;
   public GameObject target;
   public PathController pathController;
   // Update is called once per frame
   void Update()
   {
   //跟随鼠标点击
       if(Input.GetMouseButtonDown(1))
       {
           Vector3 mousePosition = Input.mousePosition;
           //从点击屏幕的位置发射射线
           Ray ray = Camera.main.ScreenPointToRay(mousePosition);
           //获取射线打中物体,通常或取地面信息
           RaycastHit hitInfo;
           if(Physics.Raycast(ray, out hitInfo))
           {
               Debug.Log(hitInfo.collider.transform.name);
               if (hitInfo.collider.tag == "ground") {
                   Vector3 endPoint = hitInfo.point;
                   navmeshagent.SetDestination(hitInfo.point);
                   //路径画线
                   lineRenderer.SetPositions(navmeshagent.path.corners);
                   hitInfo.point.
               }
           }
       }
//跟随指定物体
//不停跟随物体
       navmeshagent.SetDestination(target.transform.position);
       if (navmeshagent.path.corners.Length > 2)
       {//画线
           lineRenderer.SetPositions(navmeshagent.path.corners);
       }
   }

有点乱啊。有时间再整理 又问题随便问

参考文章
https://blog.csdn.net/zhen2_/article/details/78556142

你可能感兴趣的:(#,unity3D,使用,技巧笔记,游戏,视觉相关)