前言

前阵子用Unity3d做的那个模拟收费的动画,主要是模拟了一个项目中的场景,让人看到更直观一些,最主要的目的还是最近在学习Unity3d,直接以实际项目应用的方式去学 习,这样掌握的会更快,本篇就是来拆解讲一下实现动画中车辆自动行驶的实现方法。

unity实景ar导航 unity 地图导航_js

实现效果

unity实景ar导航 unity 地图导航_html_02

上图中三辆汽车会沿着道路一直不停地行驶,实现永动的状态,我们就来看看达到上面的效果是怎么实现的。

实现思路

1.  把道路设置实现自动导航的效果

2.  设置行驶的路线点,生成一个行驶路线

3.  根据车辆当前位置计算初始要到的路线

4.  开始行驶

具体实现方法



unity实景ar导航 unity 地图导航_css_03

微卡智享

01

设置导航路线

unity实景ar导航 unity 地图导航_unity_04

我们把道路的预制模型在视口中先摆放起来,完成我们道路的搭建。

unity实景ar导航 unity 地图导航_css_05

新建一个Road的空组件,把所有的道路都一起放到这里,方便管理。

划重点

unity实景ar导航 unity 地图导航_js_06

在Road的检查器右上角的静态的里中,要把Navigation static这个打上勾,只有这个打上勾后 ,导航组件才能进行烘焙,否则是无用的。

unity实景ar导航 unity 地图导航_html_07

然后在window--AI--导航中点开组件,这样就会出来导航的设置界面

unity实景ar导航 unity 地图导航_css_08

然后我们在烘焙项里把代理半径设置好,点击右下角的buke后,整个导航的路径就在左边渲染出来了,看上图左上角的蓝色区域就是,区域可以自己设置参数重新Clear和Buke进行调整,这样整个导航的路径我们就已经设置完成了。

02

车辆导航设置

unity实景ar导航 unity 地图导航_unity_09

我们在车的模型Car_21A中添加一个Nav Mesh Agent组件,在此组件中可以设置车辆的行驶速度,角速度等基本的参数,这里设置好后,车辆就可以实现导航的方式了。

但是如果只是这样直接运行,车辆是不会动的,要在代码中加入NavMeshAgent的使用,如下:

private NavMeshAgent nav;


   void Start()
    {
        nav = this.transform.GetComponent<NavMeshAgent>();
        nav.SetDestination(目录点);
    }

这样我们的车就会根据导航的线路直接过去了。

03

设置行驶线路

上面介绍的就是Unity3d里导航路线的简单使用,像我们项目中要实现无限循环的行驶,这样我们就要自己写实现方式了。

本身我们建模的道路就是建了一个环形的道理,所以我们想到实现路线,可以考虑在我们的道路上设置行驶的顺序点,生成一个列表,每当达到一个点后我们就再往列表中的下一个点进行行驶,当我们运行到列表点终点后,下一个点就是列表的起点,这个在基础的算法课中应该有讲过。

unity实景ar导航 unity 地图导航_unity实景ar导航_10

如上图中,我们把道路上四个直行的道路模型,按照车运行的顺时针方向标出了0-3的顺序记号,并且在右边把这四个模型也改了相应的名称加后面的序号,下面我们就开始在代码中开始实现。

需要注意

 设置运行线路的脚本挂载到我们的车辆上,当程序运行时,找到当前的车的坐标离设置的路线中坐标最近的为初始目标点,判断这个初始目标点需要注意的是,首先要判断车辆运行方向内最近的,如果行驶的点在车的后方,我们就不再判断,防止车辆调头后行驶成反方向了。如下图

unity实景ar导航 unity 地图导航_js_11

车离的0点最近,如果只按最近距离计算,会先去0点,再从一点过去,这样开始行驶时会直接调头往0点的方向行驶,当到达时再调头往一的方向行驶,所以我们这里要考虑是按车头方向判断最近距离的点 ,就是直接去找1点的坐标,忽略到背后的点。

unity实景ar导航 unity 地图导航_unity实景ar导航_12

新建一个NavCar的C#脚本,然后增加到车的预制件中,我们用VS2019打开脚本后进行编辑。

public class NavCar : MonoBehaviour
{
    //定义接收导航网络组件
    private NavMeshAgent nav;
    //坐标点列表
    private List<Vector3> destpoints;
    //导航下一个坐标点
    private int nextindex;
    //离导航坐标点的距离 
    private float calcdist = 5f;
    private float dist = 0f;
    
    void Start()
    {
        //将定义的路线加入到List列表中
        destpoints = new List<Vector3>();
        destpoints.Add(GameObject.Find("RoadPoint0").transform.position);
        destpoints.Add(GameObject.Find("RoadPoint1").transform.position);
        destpoints.Add(GameObject.Find("RoadPoint2").transform.position);
        destpoints.Add(GameObject.Find("RoadPoint3").transform.position);
        //获取当前车辆的NavMeshAgent
        nav = this.transform.GetComponent<NavMeshAgent>();


        //计算最近的点,获取下一点的序号
        Vector3 navpoint = this.transform.position;
        for (int i = 0; i < destpoints.Count; ++i)
        {
            //首先判断点在当前位置的前方还是后方,如果是后方不做计算
            Vector3 dir = destpoints[i] - navpoint;
            float dot = Vector3.Dot(transform.forward, dir);
            //判断点在前方时才计算最近的点的距离
            if (dot > 0)
            {
                float tmpdist = Vector3.Distance(destpoints[i], navpoint);
                if (dist == 0)
                {
                    dist = tmpdist;
                    nextindex = i;
                }
                else if (dist > tmpdist)
                {
                    dist = tmpdist;
                    nextindex = i;
                }
            }
        }
    }
    
    void Update()
    {
        //判断距离是否在到达范围内,如果在走到一下个点
        if (Vector3.Distance(this.transform.position, destpoints[nextindex])< calcdist)
        {
            if (nextindex == destpoints.Count - 1)
            {
                nextindex = 0;
            }
            else
            {
                nextindex++;
            }
        }


        nav.SetDestination(destpoints[nextindex]);
    }
}

上面的Start函数中我们就是开始计算当前车辆离我们线路中最近的点,然后在update的中判断是否到达目标点了,如果目标点到达则继续行驶到下一个目标点。

这样我们导航的循环行驶就实现了。

unity实景ar导航 unity 地图导航_html_02