diff --git a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs index 1a259062..9c3e6b09 100644 --- a/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs +++ b/Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs @@ -620,20 +620,24 @@ namespace PathBerserker2d return PathTo(goal); } - // [项目新增] 目标点吸附:把任意世界点映射到最近的、agent 容身得下的可行走段上,再按 endMargin - // 从段两端内缩,得到"身体真正站得住"的世界点(避免落在角色宽度站不住的崖沿被移动层夹停)。 - // 与 SetRandomDestinationOnCurrentSegment 同源:endMargin 传 agent 半宽 + 落崖检测余量。 - // 段短于 2*endMargin → 退化到中点。searchRadius 内映射不到任何段(目标离导航面太远)时返回 false。 + // [项目新增] 目标点吸附:把任意世界点映射到最近的可行走段,再按 endMargin 从段两端内缩, + // 得到"身体真正站得住"的世界点(避免落在角色宽度站不住的崖沿被移动层夹停)。 + // 与 SetRandomDestinationOnCurrentSegment 同源:endMargin 传 agent 半宽 + 落崖检测余量。段短于 + // 2*endMargin → 退化到中点。映射方式与 PB2d 自身 UpdatePath 映射目标一致(见 UpdatePath): + // 搜索距离 = agent 到目标的距离(+余量)、用不带 agent 过滤的 TryMapPoint(就近段几何映射,可达性交给 + // allowCloseEnoughPath 的寻路阶段),故只要图上有段就一定能吸附——不会像固定小半径那样漏掉稍离地的点。 /// - /// Maps to the nearest walkable segment the agent fits on, + /// Maps to the NEAREST walkable segment (same robustness as + /// PB2d's own goal mapping in UpdatePath — search distance scales with agent→target distance), /// then insets by from BOTH segment ends so the returned point is /// one a bodied agent can actually stand on (not clamped at a ledge). A segment shorter than - /// 2*endMargin degenerates to its midpoint. Returns false (and echoes worldTarget) if nothing - /// maps within . + /// 2*endMargin degenerates to its midpoint. Returns false only if the graph has no segment at all. /// - public bool TryGetStandablePointNear(Vector2 worldTarget, float searchRadius, float endMargin, out Vector2 standable) + public bool TryGetStandablePointNear(Vector2 worldTarget, float endMargin, out Vector2 standable) { - if (!PBWorld.TryMapPoint(worldTarget, searchRadius, this, out var ptr)) + // 与 UpdatePath 映射目标同款:半径随距离放大,保证图上有段就映射得到最近点。 + float searchDist = Vector2.Distance(Position, worldTarget) + 0.1f; + if (!PBWorld.TryMapPoint(worldTarget, searchDist, out var ptr)) { standable = worldTarget; return false; diff --git a/Assets/_Game/Scripts/Enemies/Navigation/EnemyNavAgent.cs b/Assets/_Game/Scripts/Enemies/Navigation/EnemyNavAgent.cs index 6f9c947c..d8ea7eff 100644 --- a/Assets/_Game/Scripts/Enemies/Navigation/EnemyNavAgent.cs +++ b/Assets/_Game/Scripts/Enemies/Navigation/EnemyNavAgent.cs @@ -35,10 +35,6 @@ namespace BaseGames.Enemies.Navigation [Tooltip("两次重算最小间隔(s):留出跨帧路径计算完成的时间")] [SerializeField] private float _repathMinInterval = 0.25f; - [Header("目标点吸附")] - [Tooltip("把巡逻/移动目标映射到最近可行走段时允许的最大偏离(m);超出视为无效目标(路点摆得离导航面太远)")] - [SerializeField] private float _goalMapSearchRadius = 2f; - // 重寻路防抖状态 private Vector2 _lastPathGoal; private bool _hasPathGoal; @@ -182,12 +178,12 @@ namespace BaseGames.Enemies.Navigation // 目标点吸附:把任意世界目标映射到最近可行走段、并按身体宽度(EdgeSafeMargin)从段两端内缩, // 得到"身体真正站得住"的点。身体宽度是本执行层独占的知识——意图层(AI/Locomotion)只递原始目标。 - // 映射不到任何段(目标离导航面太远)时返回 false,standable 回落为原始 target。 + // 底层用与 PB2d 自身目标映射同款的距离自适应搜索,只要图上有段就一定吸附得到;返回 false 仅表示图为空。 public bool ResolveStandablePoint(Vector2 target, out Vector2 standable) { if (_navAgent == null) { standable = target; return false; } float margin = _enemyMovement != null ? _enemyMovement.EdgeSafeMargin : 0f; - return _navAgent.TryGetStandablePointNear(target, _goalMapSearchRadius, margin, out standable); + return _navAgent.TryGetStandablePointNear(target, margin, out standable); } public bool IsNearEdge()