12 第1页 | 共2 页下一页
返回列表 发新帖
查看: 8584|回复: 10
打印 上一主题 下一主题

利用Unity3d中的自动寻路来为角色设置目的地

[复制链接]

21

主题

7

听众

651

积分

初级设计师

Rank: 3Rank: 3

纳金币
0
精华
3

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

跳转到指定楼层
楼主
发表于 2012-11-16 10:02:14 |只看该作者 |倒序浏览
         不少游戏中,你只需在屏幕上单击一下,角色就可以向那个地方奔跑,然后到达目的地停了下来 ,Dota里面就是这样的 。今天,就让我们来实现这一功能吧。我们这次是借助unity3d里面的自动寻路组件来实现这一功能,所以对此组件不熟悉的读者我希望您事先看一下这方面的资料,不会花你多长时间的。好了,让我们开始吧!

        首先,我们得有一个工作目录,所以我们得新建一个工程,我把它命名为:TestNavMeshAgent,然后保存当前的Scene,给它一个名字:RobotNavMesh。接下来我们开始搭建我们的场景了。因为我不会做模型,所以像往常一样,我从别的工程里面抠出了一个角色:Robot,还是官方的CharacterAnimation这个工程里的一个机器人模型。我们得新建一个平面(用Cube做的)作为Robot落脚的地方,还是给这个平面一个颜色吧,并且加一个灯光吧。调节一下摄像机的位置与旋转角到一个比较合适的程度,就像下面这样:



我们接下来该烘焙平面,生成导航网格了。如果读者对此部分不是很熟悉,建议认真研究一下,也没什么难度,如果不熟悉英文,就到Unity圣典上看中文算了。
        好了,我们开始烘焙场景了。选中我们的地面,然后打开Navigation窗口:Window->Navigation。勾选Navigation Static 这个选项,并且打开Navigation Layer下拉菜单,然后选择Default,最后单击Navigation窗口的右下角的Bake按钮。我们可以发现,Scene中的地面颜色发生了改变,如:

这就是导航网格生成后的场景。然后我们往Robot身上添加一个组件:NavMeshAgent,即:Unity菜单栏:Component->Navigation->Nav Mesh Agent。这个组件就是寻路系统的核心组件,我们接下来将利用这个组件来完成Robot的移动了。接下来我们必须写几个脚本,我写了3个脚本:RayCastPerFrame.cs,    NavMeshController.cs,       RobotNavAnimaiton.cs。RayCastPerFrame.cs的代码如下:


using UnityEngine;
using System.Collections;

public class RayCastPerFrame : MonoBehaviour {//这个脚本将要被附着到Robot身上

    private RaycastHit hitInfo ;
   
    void Update () {
        if(Input.GetMouseButtonDown(1)){//当我们点击鼠标右键时,
             Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hitInfo);
            //以摄像机为原点,向鼠标光标世界坐标点发射射线投射碰撞
         }
     }

    public RaycastHit GetHitInfo()
    {
        return hitInfo;//得到碰撞信息
    }
}

这个脚本比较简单,是专门获取射线碰撞信息hitInfo的。

NavMeshController.cs的代码如下:

using UnityEngine;
using System.Collections;

public class NavMeshController : MonoBehaviour {//此脚本将附着到Robot上

    public RayCastPerFrame rcpf;//待会会将Robot拖拽到这个变量上,为的是直接访问Robot身上的RayCastFrame脚本。

    private NavMeshAgent nma;//用于存储Robot身上附带的NavMeshAgent组件

void Start () {
    nma = gameObject.GetComponent<NavMeshAgent>();
            //实例化nma
}

void Update () {


        if(!rcpf){
            return;
        }



        RaycastHit hit = rcpf.GetHitInfo();//获取碰撞点

        if (hit.transform)
        {
            nma.SetDestination(hit.point);//设置目的地位射线与平面的碰撞点
        }


}
}


RobotNavAnimaiton.cs的代码如下:

using UnityEngine;
using System.Collections;

public class RobotNavAnimation : MonoBehaviour {//此脚本呢附着在Robot身上

    private NavMeshAgent nma;//用于存储Robot身上附带的NavMeshAgent组件
    void Start()
    {
        nma = gameObject.GetComponent<NavMeshAgent>();//实例化nma
        animation.AddClip(animation["shoot"].clip, "shootUpperBody");
        animation["shootUpperBody"].AddMixingTransform(transform.Find("mover/gun"));
        animation["shootUpperBody"].AddMixingTransform(transform.Find("mover/roothandle/spine1"));

        animation.wrapMode = WrapMode.Loop;
        
        animation["jump"].wrapMode = WrapMode.Clamp;
        animation["shoot"].wrapMode = WrapMode.Clamp;
        animation["shootUpperBody"].wrapMode = WrapMode.Clamp;

        animation["idle"].layer = -1;
        animation["***n"].layer = -1;
        animation.Stop();
    }

void Update () {

        if (nma.remainingDistance != 0)//如果导航代理还没有到达目的地,则播放跑的动画。
        {
            animation.CrossFade("***n");
            //animation["***n"].speed = Mathf.Sign(Input.GetAxis("Vertical"));
        }
        else //否则播放站立的动画
        {
            animation.CrossFade("idle");
        }
        if (Input.GetButtonDown("Jump"))
        {
            animation.CrossFade("jump", 0.3f);
        }

        if (Input.GetButtonDown("Fire1"))
        {
            if (animation["***n"].weight > 0.5f)
                animation.CrossFadeQueued("shootUpperBody", 0.3f, QueueMode.PlayNow);
            else
                animation.CrossFadeQueued("shoot", 0.3f, QueueMode.PlayNow);
        }

}
}


这个脚本涉及到了动画的混合,现在就先将就着看吧,我或许会在接下来的日子里写出我的第四篇有关与动画方面的文章,有兴趣的可以留意一下。
        最后,我们将这三个脚本绑定在Robot上面,并且在Hierarchy面板中将Robot拖拽到NavMeshController这个脚本中的Rcpf这个选项上,如下图:




寻路时的状态,已经达到了我们想要的效果。



我们还可以家一个障碍物,这个就留给读者自己添加吧。可是你有没有注意到一点,RayCastPerFrame .cs这个射线检测的脚本是每帧都在检测,NavMeshController.cs也是每帧都在获取碰撞信息,每帧设定目的地。这个就相当消耗性能。那么这个问题就留给读者自行解决吧!我提个思路,比如说当距离上次检测碰撞信息的时间超过0.1s时设置导航网格代理的目的地,这个应该是很好实现的。
我把工程给贡献出来,有兴趣的读者不妨下载下来研究一下。

TestNevMeshAgent.rar

0 Bytes, 下载次数: 253

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

使用道具 举报

2317

主题

54

听众

2万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
20645
精华
62

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

沙发
发表于 2012-11-16 15:56:20 |只看该作者
寻路系统很少有这方面的介绍,谢谢了!!
回复

使用道具 举报

8

主题

4

听众

1237

积分

助理设计师

Rank: 4

纳金币
61
精华
0
板凳
发表于 2012-11-16 23:23:03 |只看该作者
记得貌似有个啥专业A星寻路的插件。
回复

使用道具 举报

700

主题

1

听众

1万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
16564
精华
0

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

地板
发表于 2012-11-17 09:52:01 |只看该作者
好东西好东西!好东西好东西!
回复

使用道具 举报

2206

主题

2

听众

3万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
32449
精华
23

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

5#
发表于 2012-11-21 09:25:53 |只看该作者
来围观!!!
回复

使用道具 举报

498

主题

1

听众

1万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
13519
精华
0

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

6#
发表于 2012-11-23 16:05:50 |只看该作者
wed 3d 纳金网
回复

使用道具 举报

2317

主题

54

听众

2万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
20645
精华
62

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

7#
发表于 2012-11-24 02:15:18 |只看该作者
学习中!
回复

使用道具 举报

may    

8830

主题

81

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
52336
精华
343

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

8#
发表于 2012-11-24 03:01:29 |只看该作者
  lZ的回复很不错,支持!
回复

使用道具 举报

0

主题

1

听众

40

积分

设计初学者

Rank: 1

纳金币
16
精华
0
9#
发表于 2012-12-21 11:52:49 |只看该作者
认真学习中                        
回复

使用道具 举报

may    

8830

主题

81

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
52336
精华
343

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

10#
发表于 2012-12-24 05:25:42 |只看该作者
来支持一下楼主的帖子哦
回复

使用道具 举报

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

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

GMT+8, 2024-11-13 09:12 , Processed in 0.125756 second(s), 41 queries .

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

© 2008-2019 Narkii Inc.

回顶部