@
fix(enemy): 巡逻边缘不越界 + 卡死兜底 + Locomotion 惰性发现 - WouldBlockAhead(EnemyMovement):按请求方向从碰撞体前缘(bounds.max/min.x) 即时射线判墙/悬崖,天然考虑碰撞体宽度;MoveHorizontal 据此夹紧前进,保证 "碰撞体边缘停在地形边缘、不越界"。移动层夹紧与 Pace 翻向共用同一判定, 避免"夹停却不掉头"。nav 走 MoveWithSpeed 不受影响。 - Pace 加窗口净位移卡死兜底:撞上未挂检测层的墙/卡角(含贴墙微抖)也能翻向, 用净位移而非逐帧差以免微抖重置计数。 - EnemyBase.Locomotion 改惰性发现:关域重载下 Awake 设的实例字段可能残留 为 null,首次访问按需补发现,编辑器/构建都不为空(此前致入口态偶发 NRE)。 PlayMode(跨调用取样,避免 Thread.Sleep 冻结主线程)验证:Pace 来回踱步、 遇边缘/墙掉头、碰撞体不越界。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
This commit is contained in:
@@ -27,6 +27,8 @@ namespace BaseGames.Enemies
|
||||
private bool _gaitInit;
|
||||
private float _paceDir = 1f;
|
||||
private bool _paceBlockedPrev;
|
||||
private float _paceWindowStartX;
|
||||
private int _paceWindowFrames;
|
||||
private int _wpIndex = -1;
|
||||
private int _wpDir = 1;
|
||||
private bool _warnedNoWaypoints;
|
||||
@@ -114,11 +116,26 @@ namespace BaseGames.Enemies
|
||||
|
||||
case PatrolStrategy.Pace: // 撞墙/悬崖翻向的来回踱步(速度驱动,不依赖 nav)
|
||||
var mv = _enemy.Movement;
|
||||
bool blocked = mv != null && (mv.IsWallAhead || mv.IsLedgeAhead);
|
||||
// 边沿触发:仅在"障碍首次出现"时翻向一次。TickPatrol 跑在 Update(可变帧率),
|
||||
// 而 IsWallAhead/IsLedgeAhead 在 FixedUpdate 刷新——若用电平触发(每帧 blocked 就翻),
|
||||
// 检测刷新前的多个 Update 帧会把同一障碍连翻多次→边缘左右抖动。
|
||||
if (blocked && !_paceBlockedPrev) _paceDir = -_paceDir;
|
||||
// 用与移动层夹紧同一判定(WouldBlockAhead,即时按请求方向+碰撞体前缘),
|
||||
// 保证"夹停在地形边缘"与"掉头"一致,不会夹停却不翻向。
|
||||
bool blocked = mv != null && mv.WouldBlockAhead(_paceDir);
|
||||
// 兜底卡死检测(窗口净位移):命令前进但一段时间净位移过小(撞上未挂检测层的墙/
|
||||
// 卡角,含贴墙微抖)也视为受阻,使巡逻对场景配置鲁棒。用净位移而非逐帧差,
|
||||
// 避免"贴墙推进-被弹回"的微抖每帧重置计数。
|
||||
float px = _enemy.transform.position.x;
|
||||
if (++_paceWindowFrames >= 12)
|
||||
{
|
||||
if (Mathf.Abs(px - _paceWindowStartX) < 0.05f) blocked = true;
|
||||
_paceWindowStartX = px;
|
||||
_paceWindowFrames = 0;
|
||||
}
|
||||
// 边沿触发:仅"障碍首次出现"翻一次;翻后按新方向即时判定,天然消抖,
|
||||
// 且两侧都堵(窄台)时翻一次即停住、不来回抖。
|
||||
if (blocked && !_paceBlockedPrev)
|
||||
{
|
||||
_paceDir = -_paceDir;
|
||||
_paceWindowStartX = px; _paceWindowFrames = 0; // 翻向后重开窗口
|
||||
}
|
||||
_paceBlockedPrev = blocked;
|
||||
_enemy.MoveInDirection(_paceDir);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user