From 6026911532ced8803982c054a0d35976e7a3b55b Mon Sep 17 00:00:00 2001 From: Joywayer Date: Mon, 27 Jul 2026 11:51:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(enemy):=20EnemyBase=20=E6=8C=81=E6=9C=89?= =?UTF-8?q?=E8=BA=AB=E4=BD=93=E5=87=A0=E4=BD=95=E6=9D=83=E5=A8=81(=5FbodyC?= =?UTF-8?q?ollider=20+=20Body),Awake/OnValidate=20=E5=8F=8C=E9=87=8D?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/_Game/Scripts/Enemies/EnemyBase.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Assets/_Game/Scripts/Enemies/EnemyBase.cs b/Assets/_Game/Scripts/Enemies/EnemyBase.cs index 19c14e93..e0470ed8 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyBase.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyBase.cs @@ -43,6 +43,11 @@ namespace BaseGames.Enemies [SerializeField] protected EnemyFeedback _feedback; [SerializeField] protected HurtBox _hurtBox; + [Header("身体碰撞体(唯一权威源)")] + [Tooltip("用于身体几何(宽高/边缘/探测起点)的碰撞体。留空 = 使用本物体上的 Collider2D。" + + "移动探测、导航内缩、冲刺终点等全部以此为准,不要在各处自行取碰撞体。")] + [SerializeField] private Collider2D _bodyCollider; + [Header("区域(可选)")] [Tooltip("地图固定巡逻/追击区域;配置后 BD_ChasePlayer 以区域边界替代 MaxChaseDistance,BD_ReturnToHome 归位至区域中心。留空则沿用出生点 + MaxChaseDistance 旧逻辑。")] [SerializeField] private EnemyPatrolZone _patrolZone; @@ -69,6 +74,9 @@ namespace BaseGames.Enemies // 碰撞体缓存:Awake 时收集一次,避免 Die()/OnSpawn() 中频繁 GetComponentsInChildren 分配 private Collider2D[] _colliders; + // 身体几何权威(懒创建;OnValidate 改引用后置空重建) + private EnemyBody _body; + // ── 对象池支持 ───────────────────────────────────────────────────── /// /// 本 GameObject 上的 PooledObject 组件(可选)。 @@ -224,6 +232,8 @@ namespace BaseGames.Enemies /// 攻击选择器(从已注册能力里筛出 category==Attack 的候选,Awake 时构建)。 public Abilities.EnemyAttackSelector AttackSelector => _attackSelector; private Abilities.EnemyAttackSelector _attackSelector; + /// 身体碰撞体几何的唯一权威查询口。移动/导航/能力一律经此获取身体尺寸。 + public IEnemyBody Body => _body ??= new EnemyBody(gameObject, _bodyCollider); /// 由 _onPlayerSpawned 事件缓存的玩家 Transform,供 BD 任务读取。 public Transform PlayerTransform => _playerTransform; /// 感知 Hub;供 BD 任务及 QuotaManager 暂停/恢复感知使用。 @@ -543,6 +553,11 @@ namespace BaseGames.Enemies BuildAttackSelector(); _colliders = GetComponentsInChildren(true); + // 身体几何权威校验:解析不到碰撞体 → 显式报错(根因暴露,不静默兜底) + if (Body.Collider == null) + Debug.LogError($"[EnemyBase] {name} 找不到身体碰撞体:请在 Inspector 指定 _bodyCollider," + + "或确保本物体上挂有 Collider2D。移动探测/导航内缩将不可用。", this); + // 收集配置型行为模块(零代码扩展点) _deathSequence = GetComponentInChildren(true); GetComponentsInChildren(true, _spawnHandlers); @@ -757,6 +772,7 @@ namespace BaseGames.Enemies protected virtual void OnValidate() { + _body = null; // 身体碰撞体引用可能在 Inspector 被改,缓存无条件失效(与警告抑制无关) if (SuppressValidationWarnings) return; if (_statsSO == null) Debug.LogWarning($"[EnemyBase] {gameObject.name} 缺少 EnemyStatsSO 配置(运行时会 NullRef)。", this); @@ -764,6 +780,8 @@ namespace BaseGames.Enemies Debug.LogWarning($"[EnemyBase] {gameObject.name} 未绑定 EnemyStats 组件引用。", this); if (_animancer == null) Debug.LogWarning($"[EnemyBase] {gameObject.name} 未绑定 AnimancerComponent 引用。", this); + if (_bodyCollider == null && GetComponent() == null) + Debug.LogWarning($"[EnemyBase] {gameObject.name} 找不到身体碰撞体(未指定 _bodyCollider 且本物体无 Collider2D)。", this); } #endif