Unity3d 寻路功能 介绍及项目演示

               

2016/09/07更新

NavMeshAgent 默认是会有碰撞效果的,就是说 玩家和玩家是会有碰撞,不能重叠。

这是因为NavMeshAgent 默认设置了体积,而且开启了障碍物检测。


只要把 Radius 改成0,或者关闭 Obstacle Avoidance,人物就可以重叠了。


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Unity3d中的寻路,可以使用AStarPath 寻路插件。现在也可以使用Unity自带的 Navigation 功能来做。

来做一个例子:


上面的图片中,Cube 是阻碍物体,球 是代表玩家,要寻路。


设置Cube为不可通过物体

首先我们点击Window - Navigation 窗口,然后选中4个Cube,按照下图设置这4个Cube为不可通过,然后烘培



设置地面为可通过,然后烘培


我们给圆球也就是我们的主角加上控制脚本

using UnityEngine;using System.Collections;public class findpath : MonoBehaviour {    public NavMeshAgent agent;    Vector3 point;    Ray aray;    RaycastHit ahit; // Use this for initialization void Start () {  }  // Update is called once per frame void Update () if (Input.GetMouseButtonDown(0)) {        aray = Camera.main.ScreenPointToRay(Input.mousePosition);        if (Physics.Raycast(aray,out ahit))        {            point = ahit.point;        }        agent.SetDestination(point); }  }}

达到圆球朝鼠标点击的地方寻路效果 转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn


注意到在使用NavMesh的时候,发现 NavMeshAgent 的物体,是不能移除到 NavMesh 范围外的。


如果NavMeshAgent 在 NavMesh 范围之外,也会被自动的设置到NavMesh里面去。

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn


而且当执行一次寻路之后,如果我们改变Cube的位置,Cube又会寻路回到原来的目的地,感觉就像是这一次寻路没有完成。

这就需要我们增加判断,在Cube 移动到目的地之后,结束这一次的寻路。

代码修改如下

using UnityEngine;using System.Collections;public class NewBehaviourScript : MonoBehaviour {    public NavMeshAgent agent;    Vector3 point;    Ray aray;    RaycastHit ahit;    bool mDoFindPath = false;    // Use this for initialization      void Start()    {            }    // Update is called once per frame      void Update()    {        if (Input.GetMouseButtonDown(0))        {            aray = Camera.main.ScreenPointToRay(Input.mousePosition);            if (Physics.Raycast(aray, out ahit))            {                point = ahit.point;            }            agent.SetDestination(point);            mDoFindPath = true;        }        //增加已经寻路到目的地的判断,然后结束这一次寻路        if(mDoFindPath && !agent.pathPending&& agent.remainingDistance !=Mathf.Infinity && agent.pathStatus==NavMeshPathStatus.PathComplete && agent.remainingDistance<=agent.stoppingDistance)        {            Debug.Log("NavMeshAgent Pathfinding End");            mDoFindPath = false;            agent.ResetPath();         }    }}

主要是这个函数,清除这一次的寻路

NavMeshAgent.ResetPath();

比如在游戏寻路的过程中,我们可以中断寻路,自己操作,就可以调用。

现在寻路之后可以随意拖动了转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn




我们在玩3D游戏的时候,一般游戏里都有一个脱离卡死的按钮。

这是因为在玩游戏的过程中,可能会有各种原因,导致玩家走到地图之外,比如穿墙了,穿地了,一直往下面掉。点脱离卡死,就能重置玩家的位置。


上面说了,如果Cube 在 NavMesh 范围之外,那么运行游戏之后,Cube 会自动移动到 NavMesh 的范围内。

这是Cube 的 NavMeshAgent 产生的效果。


但是如果Cube离NavMesh比较远的话,就没有这个效果了

并且产生了一个警告。

Failed to create agent because it is not close enough to the NavMesh

意思就是说,Cube 离 NavMesh 范围外太远了,创建 NavMeshAgent 失败了……


这样的话,依靠NavMeshAgent ,是达不到 脱离卡死的目的的,距离稍微远点就不给力了。

这个时候只好自己到 NavMesh 中找一个点,然后把玩家 移动到这个点。

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

代码修改如下:

using UnityEngine;using System.Collections;public class NewBehaviourScript : MonoBehaviour{    NavMeshAgent agent = null;    Vector3 point;    Ray aray;    RaycastHit ahit;    bool mDoFindPath = false;    // Use this for initialization      void Start()    {        agent = gameObject.AddComponent<NavMeshAgent>();    }    void OnGUI()    {        if (GUILayout.Button("脱离卡死"))        {            //寻找导航网格上,距离玩家最近的点,然后把玩家设置为点的坐标,就脱离卡死了。            NavMeshHit tmpNavMeshHit;            if (NavMesh.SamplePosition(transform.position, out tmpNavMeshHit, 10000f, NavMesh.AllAreas))            {                transform.position = tmpNavMeshHit.position;                agent.enabled = false;                agent.enabled = true;            }        }    }    // Update is called once per frame      void Update()    {        if (agent == null)        {            return;        }        if (agent.isOnNavMesh == false && agent.isOnOffMeshLink == false)        {            return;        }        if (Input.GetMouseButtonDown(0))        {            aray = Camera.main.ScreenPointToRay(Input.mousePosition);            if (Physics.Raycast(aray, out ahit))            {                point = ahit.point;            }            agent.SetDestination(point);            mDoFindPath = true;        }        //增加已经寻路到目的地的判断,然后结束这一次寻路        if (mDoFindPath && !agent.pathPending && agent.remainingDistance != Mathf.Infinity && agent.pathStatus == NavMeshPathStatus.PathComplete && agent.remainingDistance <= agent.stoppingDistance)        {            Debug.Log("NavMeshAgent Pathfinding End");            mDoFindPath = false;            agent.ResetPath();        }    }}

效果



关于 OffMeshLinks

在游戏的场景中,可能会出现两个 Mesh 没有连在一起的情况。这个时候寻路会被中断。

Unity 提供了 OffMeshLinks 给我们使用,字面上的意思就是,分离  Mesh 的连接器。

只要提供一个 Start 和一个 End ,两个Mesh 就可以连接起来。


首先搭建下面的场景


并添加两个Cube,一个作为起点 Start,一个作为终点 End


然后在作为Player的Cube上再添加一个 OffMeshLink,并把 起点、终点的Cube 拖过去


然后Bake,在 Start 和 End 之间,生成了一条曲线,把 分离的两个 地板 连接起来

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

运行游戏测试


测试工程下载:

http://pan.baidu.com/s/1pLD3HEj


           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/qq_43667944/article/details/87858824
今日推荐