前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学习|Unity3d的导航实现循环线路移动

学习|Unity3d的导航实现循环线路移动

作者头像
Vaccae
发布2020-08-25 11:48:34
2K0
发布2020-08-25 11:48:34
举报
文章被收录于专栏:微卡智享微卡智享

前言

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

实现效果

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

实现思路

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

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

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

4. 开始行驶

具体实现方法

微卡智享

01

设置导航路线

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

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

划重点

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

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

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

02

车辆导航设置

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

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

代码语言:javascript
复制
private NavMeshAgent nav;

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

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

03

设置行驶线路

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

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

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

需要注意

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

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

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

代码语言:javascript
复制
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的中判断是否到达目标点了,如果目标点到达则继续行驶到下一个目标点。

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档