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

不少游戏中,你只需在屏幕上单击一下,角色就可以向那个地方奔跑,然后到达目的地停了下来 ,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();
            //实例化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();//实例化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时设置导航网格代理的目的地,这个应该是很好实现的。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值