123 第1页 | 共3 页下一页
返回列表 发新帖
查看: 40233|回复: 20
打印 上一主题 下一主题

[教程] Unity里面的自动寻路(一)

[复制链接]

21

主题

7

听众

651

积分

初级设计师

Rank: 3Rank: 3

纳金币
0
精华
3

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2012-11-20 23:26:27 |只看该作者 |倒序浏览
            众所周知,自动寻路是所有游戏的一个难点,属于AI(人工智能)的范畴。一个游戏的AI的设计是否足够完美,可能决定了这个游戏的命运。然而自动寻路就是AI中的一个十分重要的分支,其算法异常复杂。然而unity3d中提供了一套非常成熟的组件来为我们解决这一难题。今天,我们就来一起欣赏一下Unity3d自带的自动寻路系统。

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



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


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


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



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



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



最后我们该编写脚本了。我还是新建一个文件夹: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作为它的子对象被其管理,如下:




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



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



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









从图中我们可以看出,我们的robot在不断的跑步,每次跑到目标点之后停下来,然后转身朝向下一个目标点,如果工程没有停止,那么它周而复始的循环下去,这对于编写NPC的AI很有帮助。
是不是很神奇呢?有没有想要将这部分知识融会贯通的冲动?我把工程一起献上吧。这个星期我的连续几篇文章,会深入的介绍这一系列的知识。敬请期待,不过我建议一下读者实现最好了解一些这个组件,看看与我的理解有什么不同,我们一同探讨,共同切磋。


分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏2 支持支持0 反对反对0
回复

使用道具 举报

2317

主题

54

听众

2万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
20645
精华
62

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2012-11-21 00:49:11 |只看该作者
好教程啊,学习了!
回复

使用道具 举报

955

主题

164

听众

7万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
59338
精华
28

活跃会员 荣誉管理 突出贡献 优秀版主 论坛元老

板凳
发表于 2012-11-21 10:27:23 |只看该作者
顶下,这个教程很有帮助!
回复

使用道具 举报

Zack    

459

主题

1

听众

5478

积分

高级设计师

Rank: 6Rank: 6

纳金币
5531
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-11-21 19:26:11 |只看该作者
学习了,谢谢!
回复

使用道具 举报

2317

主题

54

听众

2万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
20645
精华
62

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

5#
发表于 2012-11-26 21:11:10 |只看该作者
支持一下
回复

使用道具 举报

may    

8830

主题

81

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
52336
精华
343

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

6#
发表于 2012-11-30 16:57:49 |只看该作者
  支持楼主的帖子
回复

使用道具 举报

0

主题

1

听众

122

积分

设计实习生

Rank: 2

纳金币
43
精华
0

最佳新人

7#
发表于 2013-5-2 15:31:02 |只看该作者
不错,很好很强大,我这里也能自动寻路
回复

使用道具 举报

9903

主题

126

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
53488
精华
316

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

8#
发表于 2013-5-2 19:31:42 |只看该作者
这个寻路可以做出动态的修改吗?
回复

使用道具 举报

heise    

4

主题

3

听众

4249

积分

中级设计师

Rank: 5Rank: 5

纳金币
105
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

9#
发表于 2013-6-10 23:16:36 |只看该作者
回复顶一下
回复

使用道具 举报

1

主题

1

听众

211

积分

设计实习生

Rank: 2

纳金币
22
精华
0

最佳新人

10#
发表于 2013-7-31 20:34:02 |只看该作者
如何在人物走的半截后挺下来让直接坐标归到初始状态再重新开始我直接用player.position = Vector3(0,0,0);结果是如果离的近就归位了 离的远就归不了位
回复

使用道具 举报

123 第1页 | 共3 页下一页
返回列表 发新帖
您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-10 14:16 , Processed in 4.157557 second(s), 31 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部