Unity基础(21)-Navigation导航系统

导航系统

CharacterController -角色控制器

理解角色控制器:当角色跑到了90英里每小时,然后马上停下而且可以极快的转身。这是不真实,用刚体和物理效果来创建这种行为是不切实际的,感觉上也不对劲。解决办法就是专门的角色控制器。很简单,就是一个胶囊碰撞器附加了可以控制其移动的脚本 ,所以这就是角色控制器。

角色控制器的特点:
角色控制器允许在受制于碰撞的情况下进行运动,而不用处理刚体带来的问题。
控制器不会对加在它自身上的力做出反应,也不会自动推开其他刚体。
如果想让角色控制器推开其他刚体或者对象,你可以在对象附加的脚本中添加OnControllerColliderHit()函数,这样对它们施加力就能够产生碰撞。
如果游戏角色想被物理效果影响,那就使用刚体来进行。

  • 代码使用
using UnityEngine;
using System.Collections;
 
public class Move : MonoBehaviour {
    public float speed = 6.0F;
    private Vector3 moveDirection = Vector3.zero;
    public CharacterController controller;
    void Start() {
       controller = GetComponent();
    }
    void Update() {
      
        if (controller.isGrounded) {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            controller.Move(moveDirection * Time.deltaTime);
    }
}
  • 相机跟随
public class CameraFollow : MonoBehaviour {

    public Vector3 cameraV;
    public Vector3 ObjV;
    void Start () {
        
    }
    
    void Update () {
        cameraV = Camera.main.transform.position;
        ObjV = transform.position;
        cameraV = new Vector3(ObjV.x, ObjV.y + 6, ObjV.z - 8);
        Camera.main.transform.position = cameraV;
    }
}

注意:
Move与SimpleMove的不同
Move() 是进行绝对值的移动,不使用重力。直接体现在移动中越过障碍物,会保持与障碍物一样的高度继续移动
SimpleMove() 速度以米/秒为单位,重力被自动应用,专用于在地面行走的角色

去群空间找动画资源,代码直接Copy

角色身上脚本一览
  • 角色鼠标控制
public class AnimaPlay : MonoBehaviour {
    public Vector3 mousePos; // 鼠标位置
    public Animation ani;  // 动画组建
    public CharacterController cha;  // 角色控制器
    public float speed = 5f;  // 移动速度
    public bool state = false; // 状态
    void Start () {
        ani = GetComponent();
        cha = GetComponent();
    }

    void Update()
    {     
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                if (hit.collider.tag == "Plane")
                {
                    mousePos = hit.point;
                    state = true;
                }
            }
        }
        //判断角色是否到达目的地
        float distance = Vector3.Distance(mousePos, transform.position);
        if (distance > 1f && state == true)
        {
            Vector3 setp = Vector3.ClampMagnitude(mousePos - transform.position, speed);
            transform.LookAt(new Vertor3(mousePos.x,transform.y,mousePos .z));
            ani.Play("Run");
            cha.SimpleMove(setp);       
        }
        else
        {
            ani.Play("Idle");
            state = false;
        }
    }

    // 当角色控制器碰撞的物体,打印其名字
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        if (hit.collider.name == "Cube")
        {
            // 创建特效
        }
    }
}
  • NavMashAgent : 寻路、寻址
Base offset :碰撞模型和实体模型之间的垂直偏移量
Speed: 物体的行进最大速度
Angular Speed 行进过程中转向时的角速度。
Acceleration 加速度
Stopping distance:离目标距离还有多远时停止。
Auto Braking : 自动制动
Radius :物体的半径
Height :物体的高度
Quality : 代理躲避的水平,一般我们选默认的High Quality就行了
Priority :躲避优先级

Auto Traverse OffMesh Link :是否采用默认方式度过链接路径。
自动移动并关闭OffMeshLinks,
Auto Repath 自动重新寻路
Area mask : 区域模板

方法

1.SetDestination( Vector3 v )�设置目的地,与nma.destination = v一样的,你想怎么用都行,只是这个函数在设置目的地成功后返回***e,
  否则返回false,就只比调用属性多了一个返回值
2.Move( Vector3 v )�让导航网格代理朝向量v的世界坐标系方向平移v的长度
3.Stop()�让导航网格代理停止寻路,但此寻路状态可以靠下面一个函数恢复到寻路状态,并且目的地也与上次一样
4.Resume()�恢复寻路状态,此时角色会在上一次执行了Stop函数停下来后恢复当时的状态,目的地为上一次的目的地
5.ActivateCurrentOffMeshLink( bool activated )�返回值为空�与OffMeshLink有关
6.CompleteOffMeshLink ()�让导航网格代理完成在OffMeshLink上的周游,后面会讲的

导航网格烘焙须知
使用此控件要注意静态物体设置为NavagationStatic



同时设置为不阻碍行走-Walkable ,即可以在障碍物上行走。



但关于障碍物即需要设置为NavagationStatic,同时设置为NotWalkable,即不可以在障碍物上行走

设置完毕后,进行烘焙即可
使用Bake进行导航网格烘焙
public class NavAgentMove : MonoBehaviour
{

    public UnityEngine.AI.NavMeshAgent agent;
    void Start()
    {
        agent = GetComponent();
    }


    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                if (!(hit.collider.name == "Plane"))
                {
                    return;
                }
                Vector3 pos = hit.point;
                transform.LookAt(new Vector3(hit.point.x, transform.position.y, hit.point.z));
                //agent.Move(pos);
                agent.SetDestination(pos);
            }
        }
        if (Input.GetMouseButtonDown(1))
        {
            Debug.Log("1");
            agent.Stop();
        }
        if (Input.GetMouseButtonDown(2))
        {
            Debug.Log("2");
            agent.Resume();
        }
   }
}
  • OffMashLink
    OffMeshLink这个组件主要是用来构造寻路角色的寻路路径的某个部分,比如我们有时需要怪物在寻路过程中从一个固定的地方移动到另一个固定的地方,设置其中的start,end即可,若不设置,则会如下图2:


开始 (Start)  分离网格链接的开始对象。
结束 (End)    分离网格链接的结束对象。
成本覆盖 (Cost Override)    如果值为正,则在路径请求处理中计算路径成本时使用该属性。否则,我们使用默认成本(此游戏对象所属的层的成本)。
如果“成本覆盖”(Cost Override) 设置为值 3.0,则在分离网格链接上移动的成本比在默认导航网格区域中移动相同距离的成本高三倍。 
此属性可在运行时编辑,无需重新烘焙''
双向 (Bi Directional) 如果此属性为“开”(on),则可以双向穿越链接,如果它为“关”(off),则只能按从“开始”(Start) 到“结束”(End) 的方向穿越链接。
已激活 (Activated) 指定寻路器是否实际使用此链接。此属性可在运行时编辑,无需重新烘焙。
图2

使用此控件要注意静态物体设置为NavagationStatic,offMashLinks,同时设置为Walkable,即可以在障碍物上行走,如果不可以在障碍物上行走,那么就没有导航了。一定要注意!!!


  • Navmesh Obstacle(了解)
    在导航网格上的固定障碍物,可以作为烘焙过程中的一部分设置。
    但是,也可能在场景具有动态阻挡物,这将通过Agent移动来避开。
    这种动态障碍物,可以指定Navmesh Obstacle组
    可以被添加任何游戏物体上并随该对象移动。


Radius 半径 : 障碍物圆柱的半径
Height 高度 : 障碍物圆柱的高度
Carve:是否打开在导航网格 的模式
Move Threshold:当模式为Carve时,此物体的移动距离超过这个阀值后,更新当前的导航网格(重新挖洞)

Carve模式的一些总结:
1.在Bake场景的时候,Navigation窗口的Bake页面有一个高度值,场景中的导航网格通常作为一个平面,当NavMeshObstacle 距离小于这个高度时,
才会在导航网格上挖洞,否则NavMeshObstacle 还是以普通模式存在的。
2.NavMeshObstacle 在刚创建的时候最好先关闭NavMeshObstacle 这个组件,但需要是再打开,在跟NavMeshAgent混用时,不能共用(同时激活状态),只能选其一,不然有bug。
3.碰撞还是使用trigger
4.最好不要同时使用RigidBody,有bug,新版本可能改好了.
5.在挖洞时,设备掉帧比较明显。善用Move Threshold。

你可能感兴趣的:(Unity基础(21)-Navigation导航系统)