diff --git a/Assets/_Game/Scripts/Enemies/EnemyMovement.cs b/Assets/_Game/Scripts/Enemies/EnemyMovement.cs index 622a4f41..d6125847 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyMovement.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyMovement.cs @@ -226,33 +226,39 @@ namespace BaseGames.Enemies return new Vector2(x, b.min.y); } + private Collider2D GroundColliderOrSelf() + => _groundCheckCollider != null ? _groundCheckCollider : GetComponent(); + /// - /// 朝 前进是否会撞墙或让碰撞体前缘越过地形边缘。 + /// 朝 前进是否会撞墙或让碰撞体前缘越过地形边缘(墙 或 悬崖)。 /// 用碰撞体前缘(bounds.max.x / min.x)判定,天然考虑碰撞体宽度—— /// 保证"碰撞体边缘不越过地形边缘"。用当前请求方向即时射线,避免缓存朝向过期。 /// 供移动层夹紧与巡逻 Pace 翻向共用同一判定,避免"夹停了却不掉头"。 /// - public bool WouldBlockAhead(float dir) + public bool WouldBlockAhead(float dir) => WouldHitWallAhead(dir) || WouldFallAhead(dir); + + /// 前缘水平方向是否有墙。 + public bool WouldHitWallAhead(float dir) { - var col = _groundCheckCollider != null ? _groundCheckCollider : GetComponent(); - if (col == null) return false; + var col = GroundColliderOrSelf(); + if (col == null || _wallCheckDist <= 0f) return false; Bounds b = col.bounds; float sign = Mathf.Sign(dir); - float edgeX = sign >= 0f ? b.max.x : b.min.x; // 朝向侧碰撞体前缘 + float edgeX = sign >= 0f ? b.max.x : b.min.x; LayerMask wallLayer = (_wallMask.value != 0) ? _wallMask : _groundMask; + return Physics2D.Raycast(new Vector2(edgeX, b.center.y), new Vector2(sign, 0f), _wallCheckDist, wallLayer); + } - // 墙:从前缘水平探;命中则前方有墙 - if (_wallCheckDist > 0f && - Physics2D.Raycast(new Vector2(edgeX, b.center.y), new Vector2(sign, 0f), _wallCheckDist, wallLayer)) - return true; - - // 悬崖:从"前缘 + 前探偏移"处向下探地;无地面则前缘外是悬崖 - if (_ledgeCheckDownDist > 0f && - !Physics2D.Raycast(new Vector2(edgeX + sign * _ledgeCheckFwdOffset, b.min.y), - Vector2.down, _ledgeCheckDownDist, _groundMask)) - return true; - - return false; + /// 前缘外是否为悬崖(脚边地面缺失,会让碰撞体越出地形边缘)。 + public bool WouldFallAhead(float dir) + { + var col = GroundColliderOrSelf(); + if (col == null || _ledgeCheckDownDist <= 0f) return false; + Bounds b = col.bounds; + float sign = Mathf.Sign(dir); + float edgeX = sign >= 0f ? b.max.x : b.min.x; + return !Physics2D.Raycast(new Vector2(edgeX + sign * _ledgeCheckFwdOffset, b.min.y), + Vector2.down, _ledgeCheckDownDist, _groundMask); } private void WallAndLedgeCheck() @@ -416,7 +422,11 @@ namespace BaseGames.Enemies public void MoveWithSpeed(float dir, float speed) { if (_isTurning) return; - UpdateFacing(dir); + if (dir != 0f) UpdateFacing(dir); + // 地面怪追击/导航:前缘将越过地形边缘(悬崖)则不前进——碰撞体边缘停在地形边缘、不越界。 + // 只夹"悬崖"不夹"墙"(墙交给寻路绕行,免得贴墙路径被误夹停);跨沟的 nav-link 跳/落 + // 不经本方法(EnemyNavAgent 仅在 IsMovingOnSegment 时写 MoveSpeed),故不影响跳跃/下落过沟。 + if (dir != 0f && IsGrounded && WouldFallAhead(dir)) dir = 0f; var vel = _rb.velocity; vel.x = dir * speed; _rb.velocity = vel;