Unity导航寻路轨迹可视化实现

目录

基础实现方案

进阶优化方案

应用场景示例

注意事项

设置好LineRenderer线组件配置,用于绘制寻路轨迹

代码

使用说明

烘培导航网格

烘培寻路网格

运行效果

总结


基础实现方案

  1. 获取导航路径点

    • 使用NavMesh.CalculatePath()方法计算起点到终点的路径
    • 该方法返回一个NavMeshPath对象,包含路径点数组(corners)
    • 示例代码:
    NavMeshPath path = new NavMeshPath();
    bool pathFound = NavMesh.CalculatePath(startPosition, endPosition, NavMesh.AllAreas, path);
    if(pathFound && path.corners.Length > 1) {
        // 处理路径点
    }
    

  2. 可视化渲染方式

    • LineRenderer方案
      • 创建带有LineRenderer组件的游戏对象
      • 将路径点数组赋值给LineRenderer的positions属性
      • 可自定义线条颜色、宽度和材质
    • Gizmos绘制方案
      • 在OnDrawGizmos方法中使用Gizmos.DrawLine逐段绘制
      • 适合编辑器调试,但不适合运行时显示
  3. 动态更新处理

    • 在Update或协程中定期检测角色位置变化
    • 当角色移动超过阈值时重新计算路径
    • 平滑过渡处理避免路径突然跳变

进阶优化方案

  1. 路径美化处理

    • 使用贝塞尔曲线平滑路径拐角
    • 添加路径箭头指示方向
    • 实现渐变色效果表示路径热度
  2. 性能优化

    • 对象池管理LineRenderer实例
    • 降低路径更新频率(如每0.3秒更新一次)
    • 使用JobSystem进行路径计算
  3. 交互功能增强

    • 点击路径点查看详细信息
    • 路径拖拽编辑功能
    • 多段路径的合并与拆分

应用场景示例

  1. RPG游戏:显示任务目标路径指引
  2. 策略游戏:展示单位移动路线
  3. AR导航:在真实环境中显示虚拟路径
  4. 教育模拟:演示AI寻路算法过程

注意事项

  1. 导航网格需要预先烘焙好
  2. 复杂场景要考虑路径分段加载
  3. 移动平台注意性能开销
  4. 处理路径被动态障碍物阻挡的情况

完整实现通常需要结合项目具体需求进行调整,核心是把握好路径获取、渲染更新和性能平衡这三个关键环节。

最近刷到b站up主山长操作库的内容,感觉很有意思,于是就简单整理了一下。注意本文的实现思路完全是按这位up整理的,这里就先放记录在这里,后续如果实际项目有用的到再深入研究。

设置好LineRenderer线组件配置,用于绘制寻路轨迹

image

代码

新增代码控制寻路轨迹显示

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

public class NavPathLineRenderer : MonoBehaviour
{
    [Header("References")]
    [Tooltip("玩家的Transform组件")]
    [SerializeField] private Transform player;           // 玩家的Transform
    
    [Tooltip("目标点的Transform组件")]
    [SerializeField] private Transform target;           // 目标的Transform
    
    [Tooltip("用于可视化路径的LineRenderer组件")]
    [SerializeField] private LineRenderer line;          // 用于绘制路径的LineRenderer组件

    [Header("Path Settings")]
    [Tooltip("路径线相对于地面的垂直偏移量")]
    [SerializeField] private float pathHeightOffset = 0.3f;   // 绘制路径时的垂直偏移量(在地面上方)
    
    [Tooltip("每条路径段的分段数,数值越高路径越平滑")]
    [Range(1, 20)]
    [SerializeField] private int quality = 10;           // 每个路径段的分段数
    
    [Tooltip("射线检测的最大高度")]
    [SerializeField] private float maxHeight = 10;       // 射线最大高度
    
    [Tooltip("路径更新的时间间隔(秒)")]
    [SerializeField] private float drawUpdateSpeed = 0.2f;   // 路径绘制更新速度

    private Coroutine drawCoroutine;    // 用于管理路径绘制的协程引用

    private void Start()
    {
        // 确保LineRenderer组件不为空
        if (line == null)
        {
            line = GetComponent<LineRenderer>();
            if (line == null)
            {
                Debug.LogError("LineRenderer component is missing!");
                return;
            }
        }

        // 在开始之前停止任何现有的协程
        if (drawCoroutine != null)
        {
            StopCoroutine(drawCoroutine);
        }
        drawCoroutine = StartCoroutine(DrawNavMeshLine());
    }

    // 协程:持续绘制NavMesh路径
    private IEnumerator DrawNavMeshLine()
    {
        WaitForSeconds wait = new WaitForSeconds(drawUpdateSpeed);   // 等待时间间隔
        NavMeshPath path = new NavMeshPath();   // 存储计算路径的NavMeshPath对象

        // 只要目标不为空,就持续绘制路径
        while (target != null)
        {
            // 从玩家位置到目标位置计算路径
            if (NavMesh.CalculatePath(player.position, target.position, NavMesh.AllAreas, path))
            {
                // 平滑并绘制路径线条
                List<Vector3> newPath = new List<Vector3>();   // 存储平滑后的路径点

                // 遍历路径中的每个拐点
                for (int i = 0; i < path.corners.Length - 1; i++)
                {
                    // 计算当前路径段的起点和终点(加上高度偏移)
                    Vector3 currentPoint = path.corners[i] + Vector3.up * maxHeight;
                    Vector3 nextPoint = path.corners[i + 1] + Vector3.up * maxHeight;

                    // 细分路径段
                    for (int j = 0; j < quality; j++)
                    {
                        // 计算当前分段点
                        float t = (1f / quality) * j;
                        Vector3 calPoint = Vector3.Lerp(currentPoint, nextPoint, t);
                        
                        RaycastHit hit;
                        // 向下发射射线检测地面
                        if (Physics.Raycast(
                            calPoint, 
                            Vector3.down, 
                            out hit, 
                            Mathf.Infinity, 
                            1 << LayerMask.NameToLayer("Ground")))
                        {
                            newPath.Add(hit.point);   // 添加有效的地面点到路径
                        }
                    }
                }
                
                // 添加最终目标位置
                newPath.Add(target.position);

                // 设置LineRenderer
                line.positionCount = newPath.Count;
                // 反转路径顺序(从玩家到目标)
                for (int i = 0; i < newPath.Count; i++)
                {
                    line.SetPosition(i, newPath[newPath.Count - 1 - i] + Vector3.up * pathHeightOffset);
                }

                // 更新玩家的NavMeshAgent路径
                var agent = player.GetComponent<NavMeshAgent>();
                if (agent != null)
                {
                    agent.SetPath(path);
                }
            }

            yield return wait;   // 等待下一次更新
        }
    }
}

使用说明

  1. 组件配置

    • 将脚本附加到含有LineRenderer组件的游戏对象上
    • 在Inspector面板中设置:
      • Player:玩家角色(需要NavMeshAgent组件)
      • Target:目标点
      • Line:用于绘制的LineRenderer组件
  2. 参数说明

    • 路径高度偏移:控制路径线在地面上方的高度
    • 分段质量:数值越高路径越平滑,但性能消耗越大
    • 更新速度:控制路径更新的频率
  3. 注意事项

    • 确保场景中有"Ground"层,用于射线检测
    • 玩家对象需要NavMeshAgent组件
    • 目标对象需要位于NavMesh可行走区域内
  4. 应用场景

    • RPG游戏中的任务指引
    • 策略游戏的单位移动路径显示
    • 导航系统的路径预览功能

挂载代码,配置参数

image

烘培导航网格

设置地面图层

image

设置不同地面的优先级,区分不同表面

image

image

image

image

烘培寻路网格

image

运行效果

image

总结

本文提出了一种基于Unity NavMesh的寻路轨迹可视化解决方案。该方案通过LineRenderer组件绘制移动路径,并采用协程机制实现路径的定时更新。主要功能特性包括:路径平滑处理、高度偏移调整以及地面碰撞检测。核心实现技术涉及:

  1. 使用NavMesh.CalculatePath进行路径计算
  2. 采用分段插值算法实现路径平滑
  3. 通过射线检测确保路径与地面贴合

系统支持多项参数配置,可灵活调整路径高度、平滑度及更新频率。该方案适用于:

  • RPG游戏的任务指引系统
  • 策略游戏的单位移动路径展示

使用前提要求场景中已烘焙导航网格并正确设置地面层级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YF云飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值