unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统

为什么要用导航网格系统?

前言:作为刚开始学习unity3d的菜鸟,将学习中觉得值得记笔记的地方分享给大家一起探讨,文中有理解错误的,勿怪哈!
我相信,许多同学刚开始接触unity3d,熟悉基本操作之后,都像我一样迫不及待地开始搭建一个自己的游戏场景,在游戏场景中畅游,享受一种创造世界的快感。当我们搭建好游戏场景后,要想在游戏中观赏我们的游戏地图,就不得不需要一个控制角色和摄像头移动的脚本。所以我们开始学习写的第一个脚本要么是通过wasd和方向键控制角色的脚本,要么是模仿RPG游戏,通过鼠标点击地图控制游戏角色走到指定位置的脚本。
当我学会写角色控制脚本后,再学习NavMesh导航网格这一章的时候,有一个疑问一直困扰我好久:我们既然可以通过一个简单的脚本就能控制角色移动,为什么需要用导航系统呢?下面我们就先搭建一个简单的场景,
unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统_第1张图片
场景中有一个Plane地板,一个绿色的坦克玩家,两个立方体障碍物。给坦克、两个立方体都加上刚体组件(Rigidbody),可以给两个立方体障碍物的Rigidbody组件勾选Is Kinematic,坦克不勾选,也可以反过来。如果坦克和障碍物都勾选了Is Kinematic,则坦克撞向障碍物时会穿过障碍物(穿模,相当于没有刚体效果),如果坦克和障碍物都不勾选Is Kinematic,则坦克撞向障碍物时会把障碍物推开。如果障碍物不勾选Is Kinemic,而且坦克不加刚体,坦克撞向障碍物时会穿模,但是会给障碍物一个力,障碍物会旋转个不停。这里模拟立方体障碍物是不能移动的,所以勾选Is Kinematic,坦克不勾选。接着给坦克编写一个鼠标控制移动的脚本MoveController.cs,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveController : MonoBehaviour
{
    public float speed = 2.0f;
    private Vector3 targetPos;
    private bool isAvalaibleTarget = false;
     // Start is called before the first frame update
    void Start()
    {
        
    }
    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit = new RaycastHit();
            if (Physics.Raycast(ray,out hit))
            {
                if (hit.collider.name == "Plane")
                {
                    targetPos = hit.point;
                    targetPos.y = transform.position.y;
                    isAvalaibleTarget = true;
                }
            }
        }
        if (isAvalaibleTarget)
        {
            Vector3 direction = (targetPos - transform.position).normalized;
            Quaternion dirQua = Quaternion.LookRotation(direction, Vector3.up);
            transform.rotation = Quaternion.Lerp(transform.rotation, dirQua, 0.5f);
            transform.position += direction * speed * Time.deltaTime;
            if (Vector3.Distance(targetPos,transform.position) < 0.1f)
            {
                transform.position = targetPos;
                isAvalaibleTarget = false;
            }
        }
    }
}

将MoveController.cs脚本放到hero对象上,运行游戏,可以看到我们鼠标右击哪里,坦克就会转向走到哪里。当坦克撞向障碍物时会被挡住,然后物理引擎计算抖动和滑动,直到滑出障碍物阻挡范围,继续向鼠标点击的目标移动。
unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统_第2张图片
注意代码中的这一行,表示物体寻路时通过脚本修改transform控制的。
unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统_第3张图片

下面使用NavMesh导航系统进行寻路,控制坦克移动。
首先将地板Plane、两个立方体障碍物都标识为Navigation Static,参与导航网格的烘焙。地板Plane的Navigation Area设置成Walkable,表示可以通行,两个立方体障碍物设置成Not Walkable,表示不可通行。然后点击Bake选项卡的Bake,按钮进行导航网格的烘焙。
unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统_第4张图片
接着给hero添加Nav Mesh Agent组件。然后编写NavMeshController.cs脚本,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class NavMeshController : MonoBehaviour
{
    public float speed = 2.0f;
    private Vector3 targetPos;
    private bool isAvalaibleTarget = false;
    // Start is called before the first frame update
    void Start()
    {
    
    }
    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit = new RaycastHit();
            if (Physics.Raycast(ray, out hit))
            {
                if (hit.collider.name == "Plane")
                {
                    targetPos = hit.point;
                    targetPos.y = transform.position.y;
                    isAvalaibleTarget = true;
                }
            }
            GetComponent().destination = targetPos;
        }
    }
}
    

将NavMeshController.cs挂载hero对象上,注意取消hero对象上之前的所有控制脚本。运行游戏,可以看到鼠标点击地面,坦克随即自动化寻路走到点击的位置,行走过程中自动避开障碍物(如果障碍物加了刚体,并且碰撞盒较大,在烘焙导航网格时障碍物区域太小,在使用导航寻路时,坦克经过障碍旁边仍然会擦边碰撞,这一点可以采取缩小坦克或者障碍物碰撞盒,或者干脆取消刚体组件,或者在烘焙导航网格时在Bake选项卡设置Agent Radius的值大一点等等措施解决)。
unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统_第5张图片

现在,我们知道了,简单脚本控制角色寻路是很直接地命令角色朝目的地走去,如果途中有阻挡,角色依然不改变方向地撞上去。而使用NavMesh导航系统则角色会先计算一条可行路线(即便没有可行路线,仍然会走到离目的地最近的地方),避开障碍物,走向目的地。如果你的场景设置成下面这样
unity3d NavMesh导航网格学习笔记之为什么要用导航网格系统_第6张图片
或者更复杂的迷宫,你就能体会到如果使用简单控制脚本时,玩家角色七磕八幢走向目的地的难受了。当然了,使用unityd自带的NavMesh导航系统必然会收到系统本身的一些限制,比如寻路过程中的转身动作的,动画播放等很难去控制。自己写的控制脚本自由度就比较高了,你想怎么控制就怎么控制,模拟导航寻路,使角色寻路过程中避开障碍物也是可以自己实现的,比如使用射线探测障碍物等手段。

你可能感兴趣的:(unity3d,导航系统,Nav,Mesh)