diff --git a/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab b/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab index 73d73506..8233fc18 100644 --- a/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab +++ b/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab @@ -259,7 +259,7 @@ BoxCollider2D: m_IsTrigger: 0 m_UsedByEffector: 0 m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} + m_Offset: {x: 0, y: 0.4} m_SpriteTilingProperty: border: {x: 0, y: 0, z: 0, w: 0} pivot: {x: 0, y: 0} @@ -647,7 +647,7 @@ CircleCollider2D: m_IsTrigger: 1 m_UsedByEffector: 0 m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} + m_Offset: {x: 0, y: 0.4} serializedVersion: 2 m_Radius: 0.4 --- !u!114 &8468978500168207169 @@ -751,7 +751,7 @@ CapsuleCollider2D: m_IsTrigger: 1 m_UsedByEffector: 0 m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} + m_Offset: {x: 0, y: 0.375} m_Size: {x: 0.55, y: 0.75} m_Direction: 0 --- !u!114 &7843048500329562790 diff --git a/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs b/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs index 66085867..378ab828 100644 --- a/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs +++ b/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs @@ -473,6 +473,7 @@ namespace BaseGames.Editor CapsuleCollider2D hurtCap = GetOrAddComponent(hurtBoxT.gameObject); hurtCap.isTrigger = true; hurtCap.size = new Vector2(0.55f, 0.75f); + AlignColliderBottomToPivot(hurtCap); // 底部对齐 y=0 HurtBox hurtBox = GetOrAddComponent(hurtBoxT.gameObject); Transform contactT = GetOrCreateChild(go.transform, "ContactDamageZone"); @@ -480,6 +481,7 @@ namespace BaseGames.Editor CircleCollider2D contactCol = GetOrAddComponent(contactT.gameObject); contactCol.isTrigger = true; contactCol.radius = 0.4f; + AlignColliderBottomToPivot(contactCol); // 底部对齐 y=0 HitBox contactHitBox = GetOrAddComponent(contactT.gameObject); BodyContactDamage bodyContact = GetOrAddComponent(contactT.gameObject); bodyContact.enabled = false; // 伪装/待机期不伤人;由 e001_chase 能力在追击期开启 @@ -2189,20 +2191,47 @@ namespace BaseGames.Editor private static Collider2D CreateBodyCollider(GameObject go, EnemyBodyColliderType type, Vector2 size) { + Collider2D col; switch (type) { case EnemyBodyColliderType.Capsule: var cap = GetOrAddComponent(go); cap.size = size; - return cap; + col = cap; + break; case EnemyBodyColliderType.Circle: var cir = GetOrAddComponent(go); cir.radius = Mathf.Min(size.x, size.y) * 0.5f; - return cir; + col = cir; + break; default: // Box var box = GetOrAddComponent(go); box.size = size; - return box; + col = box; + break; + } + AlignColliderBottomToPivot(col); // 底部对齐 y=0:原点=脚底,供 NavAgent 检测原点落在导航线上 + return col; + } + + /// + /// 把碰撞体底部对齐到 transform 原点(y=0)——原点即脚底。 + /// PathBerserker2d NavAgent 用 transform 原点(0,0)判定是否在导航段上,故所有创建物的碰撞体底部须在 y=0, + /// 否则站到地面时原点悬在导航线上方,导致 HasValidPosition=False、寻路失效。 + /// + private static void AlignColliderBottomToPivot(Collider2D col) + { + switch (col) + { + case CapsuleCollider2D cap: + cap.offset = new Vector2(cap.offset.x, cap.size.y * 0.5f); + break; + case BoxCollider2D box: + box.offset = new Vector2(box.offset.x, box.size.y * 0.5f); + break; + case CircleCollider2D cir: + cir.offset = new Vector2(cir.offset.x, cir.radius); + break; } } diff --git a/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs b/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs index 2cce83d7..bae8001b 100644 --- a/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs +++ b/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs @@ -30,12 +30,10 @@ namespace BaseGames.Enemies.Abilities _contactDamage.enabled = true; // 追击直到玩家消失或被 AI 中断(退出追击的决策归 AI,见 EnemyBrainContext.InterruptAbilities)。 - // 地面爬行怪用直接水平爬行追击(朝玩家方向),不依赖 A* 寻路。 - float runSpeed = _enemy.Stats != null ? _enemy.Stats.RunSpeed : 0f; + // 小怪走 nav 寻路(EnemyBase.MoveTo → 导航),寻路正确性依赖脚手架把碰撞体底部对齐 y=0。 while (_enemy.PlayerTransform != null) { - float dir = _enemy.PlayerTransform.position.x >= _enemy.transform.position.x ? 1f : -1f; - _enemy.MoveInDirectionWithSpeed(dir, runSpeed); + _enemy.MoveTo(_enemy.PlayerTransform.position); yield return null; }