Unity里面的自动寻路(一)

摘要:
Mod=viewthread&tid=269146&highlight=Unity%E9%87%8C%E9%9D%A2%E7%9A%84%E8%87%AA%E5%8A%A8%E5%AF%BB%E8%B7%AF众所周知,自动寻路在所有游戏中都是一个难点,属于AI。然而,自动寻路是人工智能的一个非常重要的分支,其算法极其复杂。然而,unity3d为我们提供了一套非常成熟的组件来解决这个问题。今天,让我们欣赏Unity3d的自动寻路系统。在Unity3d编辑器的菜单下:Window-˃Navigation,我们可以发现一个Navigation窗口出现在编辑器的某个部分。例如,请注意此图右下角的“烘焙”按钮。

来自:http://www.narkii.com/club/forum.php?mod=viewthread&tid=269146&highlight=Unity%E9%87%8C%E9%9D%A2%E7%9A%84%E8%87%AA%E5%8A%A8%E5%AF%BB%E8%B7%AF

            众所周知,自动寻路是所有游戏的一个难点,属于AI(人工智能)的范畴。一个游戏的AI的设计是否足够完美,可能决定了这个游戏的命运。然而自动寻路就是AI中的一个十分重要的分支,其算法异常复杂。然而unity3d中提供了一套非常成熟的组件来为我们解决这一难题。今天,我们就来一起欣赏一下Unity3d自带的自动寻路系统。

        我们在学习一个陌生的知识时,免不了要记一些令人烦恼的概念,自动寻路也是一样的。但是记东西也是有技巧的,我认为我们应该先看到一点惊喜再学东西,这样兴趣有了,学东西就不那么抵触了。所以我现在先列举举一个简单的例子,记住,先不要思考为什么我要这样做,如果你是初次学习这个自动寻路的话最好这样,不然你会走很多弯路的。我们需要新建一个工程,将其起名为:NavMeshProject。然后我们可以制作场景了。
        像往常一样,先做一个地面,这里我用的是Cube。然后我将我们的朋友Robot也请来了,看这:

Unity里面的自动寻路(一)第1张

是不是很帅啊!我特意加了个灯光,给地面换了个柔和的颜色,看起来就不那么单调了。然后我们保存一下整个场景,该场景取名为:TestNavgation1。
下面我来烘焙场景,但是记住,先不要想为什么。Unity3d编辑器的菜单下:Window->Navigation,这是我们可以发现编辑器的某一部分出现了一个Navigation窗口,如:
Unity里面的自动寻路(一)第2张

请注意一下此图的右下角的一个Bake按钮。
在Hierarchy下选中Plane(就是那个地面),然后我们在Navigation面板中的Object选项卡下找到Navigation Static复选框,勾选它,然后点击Navigation面板右下角的Bake按钮:
Unity里面的自动寻路(一)第3张

此时我们可以发现Project面板下面多出了一个文件夹,且此文件夹出现了一个子文件NavMesh: 

Unity里面的自动寻路(一)第4张

并且Scene窗口中的地面上出现了一下变化: 

Unity里面的自动寻路(一)第5张

然后我们跟robot添加一个组件:NavMeshAgent。具体做法是 :  在Hierarchy面板下选中robot,然后在Unity3d菜单下:Component->Navigation->NavMeshAgent,你会发现robot身上出现了一个类似胶囊体碰撞器的绿色线框的包围体,调节一下盖NavMeshAgent组件中的一些参数:Height,BaseOffset等,如图: 

Unity里面的自动寻路(一)第6张Unity里面的自动寻路(一)第7张

最后我们该编写脚本了。我还是新建一个文件夹:Scripts。然后编写两个脚本:
脚本一,专门设置导航网格代理的目的地的:

using UnityEngine;
using System.Collections;

public class NavMeshMove : MonoBehaviour {

    public Transform[] NavMeshTransforms;//导航网格的目的地组。

    private NavMeshAgent nma;//Robot的导航网格代理

void Start () {
        if(NavMeshTransforms == null)
        {
            return;
        }
    nma = gameObject.GetComponent<NavMeshAgent>();
            nma.SetDestination(NavMeshTransforms[0].position);//初始时刻设置的导航网格代理的目的地
}

void Update () {

        if(nma.remainingDistance == 0){
            //当导航网格代理到达了目的地时,更换目的地,且是随机的更换
            nma.SetDestination(NavMeshTransforms[Random.Range(0,NavMeshTransforms.Length)].position);
        }
   }
}

脚本二,是专门为导航网格代理编写的动画控制脚本:

using UnityEngine;
using System.Collections;

public class NavNeshAnimation : MonoBehaviour {

    public float***nAnimaitonSpeed = 4.0f;//定义最大的跑步速度,一般为导航网格代理的速度
    public float speedThreshold = 0.1f;//定义动画从idle***n过渡的临界速度

    private string loadAnimation = "load_Idle";//定义需要执行的协同函数名
    private NavMeshAgent nma;//定义导航网格代理

IEnumerator Start () {
    nma = gameObject.GetComponent<NavMeshAgent>();
        AnimationSetup();//简单的设定一下动画。

        while(Application.isPlaying) {
            yield return StartCoroutine(loadAnimation);//执行协同函数
    }
    }

    IEnumerator load_Idle() 
    {
        do{
            UpdateAnimationBlend();
            yield return null;
            
        }while(nma.remainingDistance == 0);

        loadAnimation = "load_Run";
        yield return null;
    }

    IEnumerator load_Run()
    {
        do
        {
            UpdateAnimationBlend();
            yield return null;

        } while (nma.remainingDistance != 0);

        loadAnimation = "load_Idle";
        yield return null;

    }

    void AnimationSetup() 
    {
        animation["idle"].layer = 1 ;
        animation["***n"].layer = 1;
        animation.SyncLayer(1);

        animation.CrossFade("idle", 0.1f, PlayMode.StopAll);
    }
    
    void UpdateAnimationBlend() 
    {
        Vector3 velocityXZ = new Vector3(nma.velocity.x,0.0f,nma.velocity.z);
        float speed = velocityXZ.magnitude;
        animation["***n"].speed = speed /***nAnimaitonSpeed;

        if (speed > speedThreshold)
        {
            animation.CrossFade("***n");
        }
        else {
            animation.CrossFade("idle");
        }
    
    }
}

我们将这两个脚本绑定到robot身上,然后我们在Hierarchy面板中新建一个空的GameObject,重命名为:NavMeshPoint,并且新建5个spere作为它的子对象被其管理,如下:
Unity里面的自动寻路(一)第8张



然后将这5个spere分开到Plane上的不同位置,如下: 

Unity里面的自动寻路(一)第9张

选中robot,然后在Inspector下的NavMeshMove脚本上设置NavMeshTransforms的个数为5,并且将那5个spere分别拖拽到相应的位置,如下: 

Unity里面的自动寻路(一)第10张

好了,我们可以运行一下工程,看一下效果,这里只截了部分图片: 

Unity里面的自动寻路(一)第11张

Unity里面的自动寻路(一)第12张

Unity里面的自动寻路(一)第13张



从图中我们可以看出,我们的robot在不断的跑步,每次跑到目标点之后停下来,然后转身朝向下一个目标点,如果工程没有停止,那么它周而复始的循环下去,这对于编写NPC的AI很有帮助。

免责声明:文章转载自《Unity里面的自动寻路(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Prometheus实战之联邦+高可用+持久【引用】java处理SQL特殊字符转义 防止sql注入下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Unity学习——纹理、材质&amp;amp;着色器

Unity渲染使用的是材质(Materials)、着色器(Shaders)和纹理(Textures),它们有着紧密的联系。 材质定义了表面是如何被渲染的,通过包含它使用的纹理的引用,颜色色调等等。材质可用的选项取决于它使用的着色器。 着色器就是包含数学计算和算法的小脚本,它根据灯光输入和材质配置来计算每个渲染像素的颜色。 纹理就是 bitmap图像。材质...

unity中读写二进制文件

都半年没写博客了,自从上个项目开始,感觉时间好紧迫。在这感慨下[自从用了unity之后,代码架构能力越来越差。unity的一切对象都是component,要恶补coding]。 废话不说了。今天记录下用NPOI将excel写入二进制。unity中读取二进制内容。 go...... NPOI 不用多介绍了,一年前用过一次做打印,都是不深入的使用。 首先是规定...

unity, 设置帧率上限

用unity做了个demo,把所有开销大的特效都去了,在真机上运行仍然卡。显示帧率来看,最高到30。原来unity在ios设备上帧率默认限制为不超过30。 可以通过Application.targetFrameRate = 60;改成最高60。注意这个设置对编辑器无效。 参考: http://answers.unity3d.com/questions/32...

AssetPostprocessor.OnPreprocessModel

今天对工程中的模型做一些统一设置, 然后发现一个问题, 就是修改了设置点Apply之后, 又会被改回默认设置. 最后搜了一下, 处理方案是使用assetImport的userData进行判断. 参考文章: <Manage Default Asset Import Settings in Unity> http://www.cliffordroc...

Unity 数字孪生笔记 工具介绍

流程思考 数字孪生本质上一种基于实际物理数据的可视化方案,通过对接实际数据,在三维界面中展示孪生结果。那么这个流程就很简单了。整个流程分为三块:数据来源-》数据分析-》数据展示 输入数据 首先我们需要考虑我们能拿到什么。第一,实际物体的三维数据从哪里来,第二,实际数据怎么获取到。 模型数据 工业上常常会用到CAD模型,CAD模型具有精确、统一的特点,但...

tips

史上最全的Unity面试题(持续更新总结。。。。。。) 包含答案的Unity面试题 这个是我刚刚整理出的Unity面试题,为了帮助大家面试,同时帮助大家更好地复习Unity知识点,如果大家发现有什么错误,(包括错别字和知识点),或者发现哪里描述的不清晰,请在下面留言,我会重新更新,希望大家共同来帮助开发者 一:什么是协同程序? 在主线程运行的同时开启另...