3D寻路系统NavMesh-客户端篇

简介: 3D寻路系统NavMesh-客户端篇

2D寻路我们一般以A*寻路为主,那么,3D游戏世界呢,NavMesh(导航网格) 是3D游戏世界中主动寻路的一种技术,如果你想让游戏人物能自动绕开障碍物到达目的地.那你就来学习下。

Navigation system由四部分组成:

导航网格(即 Navigation Mesh,缩写为 NavMesh)

是一种数据结构,用于描述游戏世界的可行走表面,并允许在游戏世界中寻找从一个可行走位置到另一个可行走位置的路径。该数据结构是从关卡几何体自动构建或烘焙的。

相关文档

导航网格代理 (NavMesh Agent)

组件可帮助您创建在朝目标移动时能够彼此避开的角色。代理使用导航网格来推断游戏世界,并知道如何避开彼此以及移动的障碍物。

相关文档

网格外链接 (Off-Mesh Link)

组件允许您合并无法使用可行走表面来表示的导航捷径。例如,跳过沟渠或围栏,或在通过门之前打开门,全都可以描述为网格外链接。

相关文档

导航网格障碍物 (NavMesh Obstacle)

组件可用于描述代理在世界中导航时应避开的移动障碍物。由物理系统控制的木桶或板条箱便是障碍物的典型例子。障碍物正在移动时,代理将尽力避开它,但是障碍物一旦变为静止状态,便会在导航网格中雕刻一个孔,从而使代理能够改变自己的路径来绕过它,或者如果静止的障碍物阻挡了路径,则代理可寻找其他不同的路线。

相关文档

接下去我们对一张现有的地图进行导航网格的制作:

构建导航网格:

原始图:

shaded:

wireframe:

选中目标地形,将Inspector面板中Static状态设置为Nav Static

2.打开Navigation窗口(Window->AI->Navigation),选择烘焙即可

以上有些参数需要了解:

参数
Agent Radius
定义代理中心与墙壁或窗台的接近程度。(间隔)
Agent Height
定义代理可以达到的空间有多低。(进坑)
Max Slope
定义代理走上坡道的陡峭程度。(爬坡)
Step Height
定义代理可以踏上的障碍物的高度。(楼梯)
Drop Height
可跳下的高度。
Jump Distance
可以跃过的距离。
Min Region Area
可剔除未连接的小型导航网格区域。表面积小于指定值的导航网格区域将被移除。

烘焙出来后,图就如下了,覆盖上了一层蓝绿色的膜:

创建导航主体:

角色,皮卡丘,:

添加组件:

创建静态障碍物:

现在给场景中添加一些静态的障碍物,看他能否绕开他们到达目的地。添加几个Cube,然后调节他们的大小,在把他们在Object栏中的Navigation Static勾选上,最后烘培一下,效果如下,凡是没有被蓝色覆盖到的都是障碍点。

加上导航轨迹

创建shader

//导航箭头
Shader "Custom/NavPathArrow"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _ScrollYSpeed("Y Scroll Speed", Range(-20, 20)) = 20
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" "RenderType"="Transparent" }
        LOD 100
        //双面渲染
        Cull Off
        //Alpha混合
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _ScrollYSpeed;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            fixed4 frag(v2f i) : SV_Target
            {
                fixed2 uv = i.uv;
                uv.y += _ScrollYSpeed * _Time;
                fixed4 col = tex2D(_MainTex, uv);
                return col;
            }
            ENDCG
        }
    }
}

创建材质:

创建material,Shader添加以上创建的shader,贴图添加合适的贴图即可。

创建个3D quad,然后把材质添加上去,制作成一个prefab,

创建脚本,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Player: MonoBehaviour
{
    private NavMeshAgent agent;
    public MeshRenderer meshRenderer;//箭头3D对象Quad
    private List<Transform> points = new List<Transform>();//路径点
    private List<MeshRenderer> lines = new List<MeshRenderer>();//显示的路径
    private Vector3[] path;
    public float xscale = 1f;//缩放比例
    public float yscale = 1f;
    private void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        //箭头宽度缩放值
        xscale = meshRenderer.transform.localScale.x;
        //箭头长度缩放值
        yscale = meshRenderer.transform.localScale.y;
        meshRenderer.gameObject.SetActive(false);
    }
    [System.Obsolete]
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit,100))
            {
                HidePath();
                Vector3 point = hit.point;
                agent.destination = hit.point;
                path = agent.path.corners;
                //线段整体y轴加高,使轨迹悬浮
                for (int i = 0; i < path.Length; i++)
                {
                    path[i] = path[i] + new Vector3(0, 0.01f, 0);//这里的y要根据地形调整,原则是不要埋到地下去为准
                }
                //绘制路径
                DrawPath();
            }
        }
    }
    //画路径
    public void DrawPath()
    {
        if (path == null || path.Length <= 1)
            return;
        for (int i = 0; i < path.Length - 1; i++)
        {
            DrawLine(path[i], path[i + 1], i);
        }
    }
    //隐藏路径
    public void HidePath()
    {
        for (int i = 0; i < lines.Count; i++)
            lines[i].gameObject.SetActive(false);
    }
    //画路径
    private void DrawLine(Vector3 start, Vector3 end, int index)
    {
        MeshRenderer mr;
        if (index >= lines.Count)
        {
            mr = Instantiate(meshRenderer);
            lines.Add(mr);
        }
        else
        {
            mr = lines[index];
        }
        var tran = mr.transform;
        var length = Vector3.Distance(start, end);
        tran.localScale = new Vector3(xscale, length, 1);
        tran.position = (start + end) / 2;
        //指向
        tran.LookAt(start);
        //旋转偏移
        tran.Rotate(90, 0, 0);
        mr.material.mainTextureScale = new Vector2(1, length * yscale);
        mr.gameObject.SetActive(true);
    }
}

然后把脚本挂载到游戏主体皮卡丘上:

最终效果如下:

总结:

虽然这个AI系统省去了我们的很多麻烦,但还是有些不方便的地方,如不能渲染出竖直方向的NavMesh,不能做到动态的Bake,不能去实现一些有趣的玩法和随机地图的生成功能,不过高级NavMesh将会完成Unity自带NavMesh未完成的使命。

目录
相关文章
|
8月前
|
前端开发
如何利用dnslog探测目标主机杀软
如何利用dnslog探测目标主机杀软
112 0
|
8月前
|
网络安全 KVM 网络虚拟化
变形金刚外传0x03:进一步讨论NSX-T的传输节点就绪
话接上篇,对于NSX-T来说,由于传输节点配置文件将传输区域与主机交换机进行了严格意义上的绑定,因此不会出现在NSX-V场景中传输区域与分布式交换机覆盖不一致的情况。
|
6天前
|
负载均衡 网络虚拟化
【专栏】生成树协议(STP),用于消除网络环路并确保单向通信路径,提高可靠性和避免循环是至关重要的
【4月更文挑战第28天】本文详细介绍了生成树协议(STP),用于消除网络环路并确保单向通信路径。STP基于IEEE 802.1D,涉及根桥选举、端口角色分配及构建无环路径。高级特性包括快速STP(RSTP)的快速收敛、多实例STP(MSTP)的负载均衡和容错,以及各种保护机制。文章还讨论了实际案例和故障排除,为网络工程师提供STP的全面理解与应用指南。
|
8月前
|
安全 Ubuntu KVM
变形金刚外传0x02:从V的主机准备到T的传输节点就绪
本篇我们继续来闲谈VMware出品的“变形金刚”。 最近在和关注公众号的朋友交流过程中,发现不少朋友都有一些疑惑: 想要学习NSX DC,有什么推荐的参考书么? 想要学习NSX-T,是否一定要有NSX-V的基础? 想要自己动手搞一搞NSX,服务器需要多少资源?
|
6月前
|
人工智能 Java 定位技术
3D寻路系统NavMesh-服务端篇
3D寻路系统NavMesh-服务端篇
80 0
|
7月前
|
网络协议 网络虚拟化
【每日一记】OSPF邻居无法建立的排错思路
【每日一记】OSPF邻居无法建立的排错思路
60 1
|
10月前
|
算法 5G
一种用于环境声源的被动到达角(AoA)提取算法(Matlab代码实现)
一种用于环境声源的被动到达角(AoA)提取算法(Matlab代码实现)
|
IDE 开发工具 图形学
令人头秃的:你的主机中的软件中止了一个已建立的连接
令人头秃的:你的主机中的软件中止了一个已建立的连接
793 1
|
XML 前端开发 Java
从零开始实现放置游戏(十)——实现战斗挂机(1)hessian服务端搭建
 前面实现RMS系统时,我们让其直接访问底层数据库。后面我们在idlewow-game模块实现游戏逻辑时,将不再直接访问底层数据,而是通过hessian服务暴露接口给表现层。   本章,我们先把hessian服务搭好,并做一个简单的测试,这里以用户注册接口为例。   先简单介绍下,实现hessian接口,只需要在facade模块暴露接口,然后在core模块实现接口,最后在hessain模块配置好接口路由,将其启动即可。
从零开始实现放置游戏(十)——实现战斗挂机(1)hessian服务端搭建
|
iOS开发
AirPods的自动连接配对原理
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/voidreturn/article/details/81672275 首次连接 打开装有 AirPods 的充电盒,并将它放在 iPhone 旁边。
4656 0