U3D学习记录——3D RPG-03 Navigation地图烘焙与导航

1 Navigation地图烘焙

Navigation是unity自带的智能导航插件,通过Window——>AI——Navigation就可以打开管理界面。

其主要使用思路是,通过设置场景对象的Navigation属性,将场景对象设置为可通过和不可通过,然后给人物对象设置Navigation agent,其会自动根据场景对象的Navigation属性自动生成导航路线。

1.1 场景对象设置Navigation属性

1)将对象设置为Navigation static,保证可以设置Navigation属性

2)选择对象切换至Navigation面板,切换到第四个Object选项

Navigation Area选择此物体是否可以通过,通过这种方法,可以将场景对象中的,地形terrain设置为Walkable,然后将树木、大石头等阻挡物设置为Not Walkable。

切换到Bake选项,点击Bake烘焙后,这时再选中Navigation面板的状态下,Scene视图里会显示出可通过(浅蓝色)和不可通过的区域:

右下角可以选择是否显示区域提示。 

1.2 设置Navigation Mesh Agent

1)选中我们要导航的人物,add component添加Nav Mesh Agent组件

Agent Type: 表示导航Agent的类型,默认为Humanoid(类人的),也可以手动添加(设置Agent的高度、半径、能上的坡度,能跨的高度等属性)。
Base Offset: 设置导航Agent与人物高度的偏移。

Speed: 自动导航时Agent的最大移动速度。
Angular Speed: 自动导航时Agent的最大角(旋转)速度。
Acceleration: 自动导航刚开始时Agent需到达的其(Speed)速度时,此期间的最大加速度。acceleration值越大,越快达到上面选项设置的速度(Speed)。
Stopping Distance: 设置在自动导航时距离目标点(destination)多少距离时停下。
Auto Braking: 勾选后表示到达目标点或离目标点的距离满足Stopping Distance时自动停止。

Radius: 导航Agent的半径。
Height: 导航Agent的高度。

Quality: 表示躲避障碍物的行为质量,质量越高躲避行为越好,越智能。
Priority: 优先级,范围为0-99,(0优先级最高,99优先级最低)表示高优先级的Agent不会与低优先级的Agent进行碰撞。

Auto Traverse Off Mesh Link: 勾选后表示Agent可以自动的通过,场景中两个分开的物体间所创建的Off Mesh Link。
Auto Repath: 勾选后表示当Agent的当前路径无效时,可以自动计算寻找新的路径前进。
Area Mask: 可以指定Agent可通过哪些层,划分其可通过的区域。

这里的属性也与上文中场景对象的Navigation相对应

它会根据你设置的agent的大小等属性来智能判断场景对象是否能通过,例如虽然整个地形我们设置的是Walkable,但对于超过30°的斜坡会自动判定为不可通过。

 

 在将agent设置为与人物相匹配的大小和属性后,将场景对象的agent属性也配置好,再次烘焙,地图就会根据agent生成合适的Navigation 地图了。

1.3 Nav Mesh Obstacle

Navigation相关组件除了agent还有一个Obstacle,前面设置的场景对象Navigation属性的方式,只能针对场景中不会移动的static对象,而如果是像小石子等可以移动的阻挡物,则可以通过对其添加Nav Mesh Obstacle组件来完成设置。

2 鼠标控制导航移动

上文中完成了地图Navigation导航功能的烘焙,现在我们就可以使用Navigation系统,很轻易的让人物在地图上进行移动。为了让人物移动看起自然,我们可以顺便完成鼠标图标的根据选择物的动态变化,人物动画的基本设置。

2.1 鼠标图标的动态变化

其主要使用方法为Camera.main.ScreenPointToRay(Vector3 pos)和Physics.Raycast最后一个重载

官方文档:

https://docs.unity3d.com/cn/2020.2/ScriptReference/Camera.ScreenPointToRay.html

https://docs.unity3d.com/cn/2020.2/ScriptReference/Physics.Raycast.html

    void SetCursorTexture()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray,out hitInfo))
        {
            //根据鼠标所在位置,设置图标图案
            switch (hitInfo.collider.tag)
            {
                case "Ground":
                    Cursor.SetCursor(tagert,new Vector2(16,16),CursorMode.Auto);
                    break;


            }
        }
    }

主要逻辑为,从主摄像机向鼠标点击位置发射一条射线,得到这条射线的碰撞信息hitInfo,然后根据碰撞对象的标签类型设置不同的鼠标图标,例如碰撞物体为Ground,则显示tagert这个鼠标图标。

2.2 人物动画状态机Blend Tree简单设置

1)打开人物Animator Controller,此前我们下载的角色资源Controller里面有默认的展示动画,我们先全部删除。

2)创建一个Blend Tree,并给Tree创建三个结点,分别代表idle、walk、run三种状态。

3)新建一个Parameters,Speed参数用于控制行进状态

4)Blend Tree的Parameters改为新建的参数Speed,分别将人物的idle/walk/run三个动画按照顺序拖入不同状态结点中。更多Blend Tree使用参考:https://blog.csdn.net/yupu56/article/details/53585304

 

2.3 鼠标控制移动

在Navigation中,人物的移动通过设置Navigation.destination即可完成,我们新建一个Player Manager,将它写到里面专门用于控制Player的控制。

public void MoveToTaget(Vector3 targert)
    {
        agent.destination = targert;
    }

随后,绑定MouseManager中的OnMouseClicked事件,当点击对象是Ground地面(要将地形tag设置为Ground)时,触发

    void MouseController()
    {
        if(Input.GetMouseButtonDown(0) && hitInfo.collider!= null)
        {
            if(hitInfo.collider.CompareTag("Ground"))
            {
                OnMouseClicked?.Invoke(hitInfo.point);
            }
        }
    }

ex:为了防止点击在树木上无法移动,可以将树木等遮挡物图层设置为Ignore Raycast

最后测试,人物通过点击可以在地图的可通过区域,自行规划路径移动。

MouseManager完整代码:

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

public class MouseManager : MonoBehaviour
{
    public static MouseManager Instance;
    public event Action<Vector3> OnMouseClicked;
    public Texture2D point, doorway, attack, tagert, arrow;
    RaycastHit hitInfo;
    void Awake()
    {
        if (Instance != null)
            Destroy(gameObject);
        Instance = this;
    }
    void Update()
    {
        SetCursorTexture();
        MouseController();
    }
    void SetCursorTexture()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray,out hitInfo))
        {
            //根据鼠标所在位置,设置图标图案
            switch (hitInfo.collider.tag)
            {
                case "Ground":
                    Cursor.SetCursor(tagert,new Vector2(16,16),CursorMode.Auto);
                    break;


            }
        }
    }
    void MouseController()
    {
        if(Input.GetMouseButtonDown(0) && hitInfo.collider!= null)
        {
            if(hitInfo.collider.CompareTag("Ground"))
            {
                OnMouseClicked?.Invoke(hitInfo.point);
            }
        }
    }
    
}

PlayerManager完整代码:

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

public class PlayerManager : MonoBehaviour
{
    // Start is called before the first frame update
    private NavMeshAgent agent;
    private Animator animator;
    void Awake()
    {
        agent = this.GetComponent<NavMeshAgent>();
        animator = this.GetComponent<Animator>();


    }
    void Start()
    {
        MouseManager.Instance.OnMouseClicked += MoveToTaget;
    }

    // Update is called once per frame
    void Update()
    {
        SwitchAnimation();
    }
    public void MoveToTaget(Vector3 targert)
    {
        Debug.Log(targert);
        agent.destination = targert;
    }
    private void SwitchAnimation()
    {
        animator.SetFloat("Speed",agent.velocity.sqrMagnitude);
    }
}


参考资料:

https://learn.u3d.cn/tutorial/3drpg-core

https://docs.unity3d.com/cn/2020.2/ScriptReference/index.html

https://blog.csdn.net/weixin_45373419/article/details/99703281

https://blog.csdn.net/yupu56/article/details/53585304

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值