unity3d navmesh 如何动态寻路

2015年01月21日 09:41 0 点赞 0 评论 更新于 2017-05-07 13:21

领导要求实现一个动态寻路的效果,而非简单的自动寻路。具体来说,首先让 Monster 检测 Hero 的位置并进行自动寻路。若 Hero 的位置未改变,说明之前的寻路路径是正确的;若 Hero 位置改变,但改变后的位置仍在旧的寻路路径上,那么旧的寻路路径依然可用;但如果 Hero 的位置改变且不在刚才的寻路路径上,则需要重新进行寻路。

明确了需求后,关键在于获取旧的寻路路径,获取后遍历该路径即可。此前询问过一些群里的大神,得知这属于动态寻路,可以使用一个插件(这里提供链接,大家可自行研究),不过实际上我们也能自己实现。

在我之前的 Nav 教程中,介绍了许多关于 NavMeshPath 的属性,但那是别人翻译过来的,内容并不全面,建议大家阅读原 API,链接如下: Unity3D NavMeshAgent API 文档

在该文档中,你会找到 NavMeshAgent.path,它代表自动寻路的路径。打开后会发现,它返回一个 NavMeshPath 类型的路径。接着查看 NavMeshPath 类,该类有一个 corners 属性,文档中给出了一个计算自动寻路路径长度的示例代码:

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
float PathLength(NavMeshPath path) {
if (path.corners.Length < 2) {
return 0;
}

Vector3 previousCorner = path.corners[0];
float lengthSoFar = 0.0F;
int i = 1;
while (i < path.corners.Length) {
Vector3 currentCorner = path.corners[i];
lengthSoFar += Vector3.Distance(previousCorner, currentCorner);
previousCorner = currentCorner;
i++;
}
return lengthSoFar;
}
}

通过这个示例,我们可以了解到 corners 是一个数组,它记录了路径上的几个关键点(注意,路径并非简单的线,而是由几个关键点构成,线段是由点连接而成的)。

下面我对代码进行了一些改进,在自己的脚本中打印路径信息:

using System.Collections;
using UnityEngine;

public class MonsterRun : MonoBehaviour {
private NavMeshAgent agent;
private GameObject hero;

// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
hero = GameObject.Find ("Hero");
}

// Update is called once per frame
void Update () {
//Debug.Log ("Monster find hero's point :" + hero.transform.position.x + " " + hero.transform.position.z);
Vector3 vector = new Vector3 (hero.transform.position.x - 1, transform.position.y, hero.transform.position.z - 1);
//Vector3 vector = hero.transform.position;
transform.LookAt (vector);
agent.SetDestination(vector);
NavMeshPath path = agent.path;
Debug.Log (vector + " " + path.corners.Length + " " + path.status);
for (int i = 0; i < path.corners.Length; i++) {
Debug.Log(i + "= " + path.corners[i]);
}
}
}

运行上述代码后,以目标点为(29, 1.2, 29)为例,会绘制出 8 个点,这些点会依次向目标点靠近。

需要注意的是,如果 MonsterHero 的距离很近,可能路径数组中只存储起始位置,即 length = 1,这种情况在我的测试中经常出现,我会自动将其屏蔽。

至此,最核心的一步——获取路径已经完成,接下来需要做的是判断是否需要更新路径。

作者信息

boke

boke

共发布了 1025 篇文章