Unity中如何获取游戏对象与障碍物间NavMesh可达最近点Pn?
需求回顾
已知:
- Pi:自身GameObject的
transform.position - Po:障碍物的
transform.position - Po周围存在半径为
PoPn的NavMesh不可达区域,需要找到Pi与Po之间、靠近障碍物的NavMesh可达点Pn作为目标点
实现思路
通过定位不可达区域边界+NavMesh采样的组合方式实现:
- 计算Pi到Po的连线,找到该连线上距离Po恰好为不可达半径的点(不可达区域的边界点)
- 在该边界点附近的NavMesh上采样最近的可达点,即为Pn
代码实现
using UnityEngine; using UnityEngine.AI; public class NavMeshTargetHelper : MonoBehaviour { [Header("障碍物设置")] public Transform obstacle; public float obstacleUnreachableRadius = 1.2f; // 障碍物周围不可达区域的半径 /// <summary> /// 获取Pi与Po之间靠近障碍物的NavMesh可达点Pn /// </summary> /// <returns>Pn坐标</returns> public Vector3 GetPnPoint() { Vector3 piPos = transform.position; Vector3 poPos = obstacle.position; float distanceBetweenPiPo = Vector3.Distance(piPos, poPos); // 如果自身已经在不可达区域内,直接返回自身位置的NavMesh最近点 if (distanceBetweenPiPo <= obstacleUnreachableRadius) { NavMeshHit hit; NavMesh.SamplePosition(piPos, out hit, obstacleUnreachableRadius * 2, NavMesh.AllAreas); return hit.position; } // 计算Pi-Po连线上,不可达区域的边界点 Vector3 directionToPo = (poPos - piPos).normalized; Vector3 boundaryPoint = poPos - directionToPo * obstacleUnreachableRadius; // 在边界点附近采样NavMesh可达点 NavMeshHit navHit; if (NavMesh.SamplePosition(boundaryPoint, out navHit, obstacleUnreachableRadius * 0.5f, NavMesh.AllAreas)) { return navHit.position; } // 采样失败时,沿Pi方向逐步后退搜索最近可达点 float searchStep = 0.1f; Vector3 searchPos = boundaryPoint; while (Vector3.Distance(searchPos, piPos) < distanceBetweenPiPo) { searchPos -= directionToPo * searchStep; if (NavMesh.SamplePosition(searchPos, out navHit, searchStep * 2, NavMesh.AllAreas)) { return navHit.position; } } // 极端情况:返回Pi位置的NavMesh最近点 NavMesh.SamplePosition(piPos, out navHit, obstacleUnreachableRadius, NavMesh.AllAreas); return navHit.position; } }
关键细节说明
NavMesh.SamplePosition:Unity NavMesh核心采样函数,用于在指定范围内找到最近的NavMesh可达点,参数依次为采样原点、命中结果、采样半径、允许的NavMesh区域- 边界点计算:确保Pn尽可能靠近Pi-Po连线,符合“两点之间靠近障碍物”的需求
- 容错处理:覆盖了自身在不可达区域内、边界点无NavMesh等极端情况,保证代码鲁棒性
内容的提问来源于stack exchange,提问作者Adam_WY_Jeong
相关产品推荐
相关产品推荐

