@
feat(enemy): 追击(nav)也夹紧悬崖边缘——碰撞体前缘不越地形边缘 MoveWithSpeed(导航跟段驱动追击)原先无边缘夹紧,仅靠 nav 图,agent 按点定位 可让碰撞体前缘越出段/地形边缘约半个碰撞体宽。现加"悬崖"夹紧(WouldFallAhead, 按碰撞体前缘即时判定),贴地生效:追击时碰撞体边缘停在地形边缘、不越界,与 Pace 一致。只夹悬崖不夹墙(墙交寻路绕行,免误夹停);跨沟的 nav-link 跳/落不经 MoveWithSpeed(仅 IsMovingOnSegment 时写速度),故不影响跳跃/下落过沟。 WouldBlockAhead 拆为 WouldHitWallAhead / WouldFallAhead 复用;PlayMode 校验 拆分正确(前缘朝悬崖侧 WouldFall=True)、Pace 不回归。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
This commit is contained in:
@@ -226,33 +226,39 @@ namespace BaseGames.Enemies
|
|||||||
return new Vector2(x, b.min.y);
|
return new Vector2(x, b.min.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collider2D GroundColliderOrSelf()
|
||||||
|
=> _groundCheckCollider != null ? _groundCheckCollider : GetComponent<Collider2D>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 朝 <paramref name="dir"/> 前进是否会撞墙或让碰撞体前缘越过地形边缘。
|
/// 朝 <paramref name="dir"/> 前进是否会撞墙或让碰撞体前缘越过地形边缘(墙 或 悬崖)。
|
||||||
/// 用碰撞体前缘(bounds.max.x / min.x)判定,天然考虑碰撞体宽度——
|
/// 用碰撞体前缘(bounds.max.x / min.x)判定,天然考虑碰撞体宽度——
|
||||||
/// 保证"碰撞体边缘不越过地形边缘"。用当前请求方向即时射线,避免缓存朝向过期。
|
/// 保证"碰撞体边缘不越过地形边缘"。用当前请求方向即时射线,避免缓存朝向过期。
|
||||||
/// 供移动层夹紧与巡逻 Pace 翻向共用同一判定,避免"夹停了却不掉头"。
|
/// 供移动层夹紧与巡逻 Pace 翻向共用同一判定,避免"夹停了却不掉头"。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool WouldBlockAhead(float dir)
|
public bool WouldBlockAhead(float dir) => WouldHitWallAhead(dir) || WouldFallAhead(dir);
|
||||||
|
|
||||||
|
/// <summary>朝 <paramref name="dir"/> 前缘水平方向是否有墙。</summary>
|
||||||
|
public bool WouldHitWallAhead(float dir)
|
||||||
{
|
{
|
||||||
var col = _groundCheckCollider != null ? _groundCheckCollider : GetComponent<Collider2D>();
|
var col = GroundColliderOrSelf();
|
||||||
if (col == null) return false;
|
if (col == null || _wallCheckDist <= 0f) return false;
|
||||||
Bounds b = col.bounds;
|
Bounds b = col.bounds;
|
||||||
float sign = Mathf.Sign(dir);
|
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;
|
LayerMask wallLayer = (_wallMask.value != 0) ? _wallMask : _groundMask;
|
||||||
|
return Physics2D.Raycast(new Vector2(edgeX, b.center.y), new Vector2(sign, 0f), _wallCheckDist, wallLayer);
|
||||||
|
}
|
||||||
|
|
||||||
// 墙:从前缘水平探;命中则前方有墙
|
/// <summary>朝 <paramref name="dir"/> 前缘外是否为悬崖(脚边地面缺失,会让碰撞体越出地形边缘)。</summary>
|
||||||
if (_wallCheckDist > 0f &&
|
public bool WouldFallAhead(float dir)
|
||||||
Physics2D.Raycast(new Vector2(edgeX, b.center.y), new Vector2(sign, 0f), _wallCheckDist, wallLayer))
|
{
|
||||||
return true;
|
var col = GroundColliderOrSelf();
|
||||||
|
if (col == null || _ledgeCheckDownDist <= 0f) return false;
|
||||||
// 悬崖:从"前缘 + 前探偏移"处向下探地;无地面则前缘外是悬崖
|
Bounds b = col.bounds;
|
||||||
if (_ledgeCheckDownDist > 0f &&
|
float sign = Mathf.Sign(dir);
|
||||||
!Physics2D.Raycast(new Vector2(edgeX + sign * _ledgeCheckFwdOffset, b.min.y),
|
float edgeX = sign >= 0f ? b.max.x : b.min.x;
|
||||||
Vector2.down, _ledgeCheckDownDist, _groundMask))
|
return !Physics2D.Raycast(new Vector2(edgeX + sign * _ledgeCheckFwdOffset, b.min.y),
|
||||||
return true;
|
Vector2.down, _ledgeCheckDownDist, _groundMask);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WallAndLedgeCheck()
|
private void WallAndLedgeCheck()
|
||||||
@@ -416,7 +422,11 @@ namespace BaseGames.Enemies
|
|||||||
public void MoveWithSpeed(float dir, float speed)
|
public void MoveWithSpeed(float dir, float speed)
|
||||||
{
|
{
|
||||||
if (_isTurning) return;
|
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;
|
var vel = _rb.velocity;
|
||||||
vel.x = dir * speed;
|
vel.x = dir * speed;
|
||||||
_rb.velocity = vel;
|
_rb.velocity = vel;
|
||||||
|
|||||||
Reference in New Issue
Block a user