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未完成的使命。

目录
相关文章
|
安全 Ubuntu KVM
变形金刚外传0x02:从V的主机准备到T的传输节点就绪
本篇我们继续来闲谈VMware出品的“变形金刚”。 最近在和关注公众号的朋友交流过程中,发现不少朋友都有一些疑惑: 想要学习NSX DC,有什么推荐的参考书么? 想要学习NSX-T,是否一定要有NSX-V的基础? 想要自己动手搞一搞NSX,服务器需要多少资源?
|
12月前
|
人工智能 Java 定位技术
3D寻路系统NavMesh-服务端篇
3D寻路系统NavMesh-服务端篇
137 0
|
机器学习/深度学习 传感器 算法
【具有路由 WSN 模拟器的随机方式移动】具有路由 WSN 模拟器的随机方式移动(Matlab代码实现)
【具有路由 WSN 模拟器的随机方式移动】具有路由 WSN 模拟器的随机方式移动(Matlab代码实现)
|
算法 5G
一种用于环境声源的被动到达角(AoA)提取算法(Matlab代码实现)
一种用于环境声源的被动到达角(AoA)提取算法(Matlab代码实现)
114 0
|
机器学习/深度学习 传感器 移动开发
【中继优化】基于高效局部地图搜索算法实现无人机通信中继位置优化附matlab代码和复现论文
【中继优化】基于高效局部地图搜索算法实现无人机通信中继位置优化附matlab代码和复现论文
|
IDE 开发工具 图形学
令人头秃的:你的主机中的软件中止了一个已建立的连接
令人头秃的:你的主机中的软件中止了一个已建立的连接
924 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 旁边。
4742 0