From 6f519ec9a9d0ceef3a6f13c36069bff6c6aa0a13 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Tue, 21 Jul 2026 16:18:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor(enemy):=20=E8=BA=AB=E4=BD=93=E6=8E=A5?= =?UTF-8?q?=E8=A7=A6=E4=BC=A4=E5=AE=B3=E6=94=B9=E4=B8=BA=E5=B8=B8=E9=A9=BB?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E5=B9=B6=E4=B8=8E=E8=83=BD=E5=8A=9B=E8=A7=A3?= =?UTF-8?q?=E8=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 所有敌人默认常驻身体接触伤害:存活即开、死亡时经 PerformDeath 统一关碰撞体停止。 - ContactChaseAbility/AnimatedCeilingDropAbility 移除对 BodyContactDamage 的开关引用 - BodyContactDamage 语义改为常驻(更新注释) - 脚手架 SetupHurtAndContactBoxes 去掉 contactEnabled 参数恒为 true,并把 ContactDamageZone 的 HitBox._targetLayers 限定为 PlayerHurtBox(避免常驻后敌人互相误伤) - 7 个敌人预制体:E001 启用 BodyContactDamage;E002/E004/E005/ChaoFeng 补齐 ContactDamageZone(镜像 HurtBox 身体碰撞体);全部 _targetLayers 收敛为 PlayerHurtBox - 更新 Docs/Guides/02 敌人搭建指南 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Enemies/ChaoFeng/ENM_ChaoFeng.prefab | 106 ++++++++++++ .../Prefabs/Enemies/E001/ENM_CaoZhi.prefab | 36 +--- .../Prefabs/Enemies/E002/ENM_HuangZhi.prefab | 137 +++++++++++---- .../Prefabs/Enemies/E003/ENM_YouZhi.prefab | 21 +-- .../Prefabs/Enemies/E004/ENM_ZhiMu.prefab | 163 ++++++++++++------ .../Prefabs/Enemies/E005/ENM_FeiZhi.prefab | 106 ++++++++++++ .../Prefabs/Enemies/E006/ENM_Huan.prefab | 34 +--- .../Editor/Scene/SceneObjectPlacerTool.cs | 34 ++-- .../Abilities/AnimatedCeilingDropAbility.cs | 15 +- .../Enemies/Abilities/ContactChaseAbility.cs | 21 +-- .../Scripts/Enemies/BodyContactDamage.cs | 7 +- Docs/Guides/02_Enemy_Boss_Setup_Guide.md | 6 +- 12 files changed, 461 insertions(+), 225 deletions(-) diff --git a/Assets/_Game/Prefabs/Enemies/ChaoFeng/ENM_ChaoFeng.prefab b/Assets/_Game/Prefabs/Enemies/ChaoFeng/ENM_ChaoFeng.prefab index 68f813f4..18f41029 100644 --- a/Assets/_Game/Prefabs/Enemies/ChaoFeng/ENM_ChaoFeng.prefab +++ b/Assets/_Game/Prefabs/Enemies/ChaoFeng/ENM_ChaoFeng.prefab @@ -670,6 +670,7 @@ Transform: - {fileID: 7580995191264333933} - {fileID: 2397879757105861778} - {fileID: 4107279870065028942} + - {fileID: 80973138644072513} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!50 &6158877404411547497 @@ -1276,3 +1277,108 @@ MonoBehaviour: m_EditorClassIdentifier: _onDamageDealt: {fileID: 0} _onHitConfirmed: {fileID: 11400000, guid: a67d56f5124e0db4f98f326c74be8091, type: 2} +--- !u!1 &8920059952006723162 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 80973138644072513} + - component: {fileID: 6125666153035542197} + - component: {fileID: 4960688227238377219} + - component: {fileID: 3072716489886911545} + m_Layer: 25 + m_Name: ContactDamageZone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &80973138644072513 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8920059952006723162} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2025611111464161772} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!70 &6125666153035542197 +CapsuleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8920059952006723162} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 1 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_Size: {x: 1.1, y: 1.9} + m_Direction: 0 +--- !u!114 &4960688227238377219 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8920059952006723162} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a655e2461396a8348a32a13144438e8e, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultSource: {fileID: 11400000, guid: caae9c7600281fe4e8d8637fa3fd2ca1, type: 2} + _hitCooldown: 0.1 + _hitMode: 0 + _hitInterval: 0.5 + _targetLayers: + serializedVersion: 2 + m_Bits: 32768 + _id: + _rivalHitBoxMask: + serializedVersion: 2 + m_Bits: 0 +--- !u!114 &3072716489886911545 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8920059952006723162} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6def12af0589a9545b80eb5accf61bb6, type: 3} + m_Name: + m_EditorClassIdentifier: + _repeatInterval: 0.5 diff --git a/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab b/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab index c1d2f18c..f3a46177 100644 --- a/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab +++ b/Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab @@ -575,38 +575,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: 0adeaa8a8508fbd40986dbb71cc85acd, type: 2} - _startClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 7400000, guid: 14b258b423ec2914bb5385226d1007b6, type: 2} - _NormalizedStartTime: NaN - _loopClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 7400000, guid: fcb8ddbfc79cc7246871a5f218b91da2, type: 2} - _NormalizedStartTime: NaN - _endClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 7400000, guid: 9f0fea347ba7eb347b0f71b423832808, type: 2} - _NormalizedStartTime: NaN - _contactDamage: {fileID: 9135205194319985817} - _dashSpeed: 9 - references: - version: 2 - RefIds: [] --- !u!1 &6788684755218838016 GameObject: m_ObjectHideFlags: 0 @@ -659,7 +627,7 @@ MonoBehaviour: _hitInterval: 0.5 _targetLayers: serializedVersion: 2 - m_Bits: 4294967295 + m_Bits: 32768 _id: _rivalHitBoxMask: serializedVersion: 2 @@ -671,7 +639,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6788684755218838016} - m_Enabled: 0 + m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 6def12af0589a9545b80eb5accf61bb6, type: 3} m_Name: diff --git a/Assets/_Game/Prefabs/Enemies/E002/ENM_HuangZhi.prefab b/Assets/_Game/Prefabs/Enemies/E002/ENM_HuangZhi.prefab index d630204a..379f760e 100644 --- a/Assets/_Game/Prefabs/Enemies/E002/ENM_HuangZhi.prefab +++ b/Assets/_Game/Prefabs/Enemies/E002/ENM_HuangZhi.prefab @@ -127,39 +127,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: 9094c0fd7780aca488db9408bec2323e, type: 2} - _strikeClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _loopClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _endClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN _attackHitBox: {fileID: 8864880579192852541} _hurtBox: {fileID: 1292370771080036383} - _hangDuration: 2 - references: - version: 2 - RefIds: [] --- !u!1 &2626404704847607916 GameObject: m_ObjectHideFlags: 0 @@ -457,6 +426,7 @@ Transform: - {fileID: 1952564073119898262} - {fileID: 8018188397413282834} - {fileID: 3853069460277176744} + - {fileID: 6613600939982668674} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!50 &6026231699680543836 @@ -734,3 +704,108 @@ MonoBehaviour: obstructLayer: serializedVersion: 2 m_Bits: 0 +--- !u!1 &7251201857052927930 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6613600939982668674} + - component: {fileID: 6239826598189337445} + - component: {fileID: 4545887833972453333} + - component: {fileID: 5239723699622728097} + m_Layer: 25 + m_Name: ContactDamageZone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6613600939982668674 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7251201857052927930} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 9176789658569836661} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!70 &6239826598189337445 +CapsuleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7251201857052927930} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 1 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_Size: {x: 0.45, y: 0.65} + m_Direction: 0 +--- !u!114 &4545887833972453333 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7251201857052927930} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a655e2461396a8348a32a13144438e8e, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultSource: {fileID: 11400000, guid: caae9c7600281fe4e8d8637fa3fd2ca1, type: 2} + _hitCooldown: 0.1 + _hitMode: 0 + _hitInterval: 0.5 + _targetLayers: + serializedVersion: 2 + m_Bits: 32768 + _id: + _rivalHitBoxMask: + serializedVersion: 2 + m_Bits: 0 +--- !u!114 &5239723699622728097 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7251201857052927930} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6def12af0589a9545b80eb5accf61bb6, type: 3} + m_Name: + m_EditorClassIdentifier: + _repeatInterval: 0.5 diff --git a/Assets/_Game/Prefabs/Enemies/E003/ENM_YouZhi.prefab b/Assets/_Game/Prefabs/Enemies/E003/ENM_YouZhi.prefab index a1af6e57..2522026c 100644 --- a/Assets/_Game/Prefabs/Enemies/E003/ENM_YouZhi.prefab +++ b/Assets/_Game/Prefabs/Enemies/E003/ENM_YouZhi.prefab @@ -277,25 +277,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: 85b5fb5f084da5b4891b55ccdf59fe5a, type: 2} - _fallLoopClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _fallGravityScale: 3.5 - _maxFallTime: 3 - _groundMask: - serializedVersion: 2 - m_Bits: 0 - _recoveryTime: 0.1 - _contactDamage: {fileID: 9017371590541886208} - references: - version: 2 - RefIds: [] --- !u!1 &6230483477122915711 GameObject: m_ObjectHideFlags: 0 @@ -383,7 +364,7 @@ MonoBehaviour: _hitInterval: 0.5 _targetLayers: serializedVersion: 2 - m_Bits: 4294967295 + m_Bits: 32768 _id: _rivalHitBoxMask: serializedVersion: 2 diff --git a/Assets/_Game/Prefabs/Enemies/E004/ENM_ZhiMu.prefab b/Assets/_Game/Prefabs/Enemies/E004/ENM_ZhiMu.prefab index 79af9975..f85255ba 100644 --- a/Assets/_Game/Prefabs/Enemies/E004/ENM_ZhiMu.prefab +++ b/Assets/_Game/Prefabs/Enemies/E004/ENM_ZhiMu.prefab @@ -167,40 +167,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: e31246206a0c7a34fb4350050cf0901f, type: 2} - _startClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _loopClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _endClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN _hitBox: {fileID: 1268810239883892084} - _hitActiveTime: 0.15 - _slamCount: 2 - _staggerDuration: 1.2 - references: - version: 2 - RefIds: [] --- !u!1 &1545843639864236458 GameObject: m_ObjectHideFlags: 0 @@ -246,18 +213,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: c43ff9a2528259b48aa83f9f950bb089, type: 2} - _faceClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - references: - version: 2 - RefIds: [] --- !u!1 &2254842475826608971 GameObject: m_ObjectHideFlags: 0 @@ -508,18 +463,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: b99aa7c679fcecd49871bfec9439b96a, type: 2} - _appearClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - references: - version: 2 - RefIds: [] --- !u!1 &4500835447412736162 GameObject: m_ObjectHideFlags: 0 @@ -798,6 +741,7 @@ Transform: - {fileID: 6852989283427571305} - {fileID: 7264053847966736484} - {fileID: 6925272127731859689} + - {fileID: 3259422555744994387} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!50 &3355772017171009690 @@ -1201,3 +1145,108 @@ MonoBehaviour: references: version: 2 RefIds: [] +--- !u!1 &8229771281009945795 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3259422555744994387} + - component: {fileID: 6506733018775259530} + - component: {fileID: 3130958997684117183} + - component: {fileID: 1282770859840413990} + m_Layer: 25 + m_Name: ContactDamageZone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3259422555744994387 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8229771281009945795} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2103993666191014279} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!70 &6506733018775259530 +CapsuleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8229771281009945795} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 1 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_Size: {x: 0.75, y: 1.1} + m_Direction: 0 +--- !u!114 &3130958997684117183 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8229771281009945795} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a655e2461396a8348a32a13144438e8e, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultSource: {fileID: 11400000, guid: caae9c7600281fe4e8d8637fa3fd2ca1, type: 2} + _hitCooldown: 0.1 + _hitMode: 0 + _hitInterval: 0.5 + _targetLayers: + serializedVersion: 2 + m_Bits: 32768 + _id: + _rivalHitBoxMask: + serializedVersion: 2 + m_Bits: 0 +--- !u!114 &1282770859840413990 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8229771281009945795} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6def12af0589a9545b80eb5accf61bb6, type: 3} + m_Name: + m_EditorClassIdentifier: + _repeatInterval: 0.5 diff --git a/Assets/_Game/Prefabs/Enemies/E005/ENM_FeiZhi.prefab b/Assets/_Game/Prefabs/Enemies/E005/ENM_FeiZhi.prefab index e5b417ed..2b6050fa 100644 --- a/Assets/_Game/Prefabs/Enemies/E005/ENM_FeiZhi.prefab +++ b/Assets/_Game/Prefabs/Enemies/E005/ENM_FeiZhi.prefab @@ -294,6 +294,7 @@ Transform: - {fileID: 6220213161530368437} - {fileID: 6247874888270033228} - {fileID: 1870740793056724981} + - {fileID: 5186351856257929582} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!50 &3127108423255305804 @@ -694,6 +695,111 @@ MonoBehaviour: _poolKey: ENM_YouZhi _count: 3 _radius: 1.5 +--- !u!1 &5847303612961356907 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5186351856257929582} + - component: {fileID: 1690687367876000149} + - component: {fileID: 2266402760472230316} + - component: {fileID: 6666768094922880470} + m_Layer: 25 + m_Name: ContactDamageZone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5186351856257929582 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5847303612961356907} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 3740776134859424860} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!70 &1690687367876000149 +CapsuleCollider2D: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5847303612961356907} + m_Enabled: 1 + m_Density: 1 + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_ForceSendLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ForceReceiveLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_ContactCaptureLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_CallbackLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_IsTrigger: 1 + m_UsedByEffector: 0 + m_UsedByComposite: 0 + m_Offset: {x: 0, y: 0} + m_Size: {x: 0.85, y: 0.95} + m_Direction: 0 +--- !u!114 &2266402760472230316 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5847303612961356907} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a655e2461396a8348a32a13144438e8e, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultSource: {fileID: 11400000, guid: caae9c7600281fe4e8d8637fa3fd2ca1, type: 2} + _hitCooldown: 0.1 + _hitMode: 0 + _hitInterval: 0.5 + _targetLayers: + serializedVersion: 2 + m_Bits: 32768 + _id: + _rivalHitBoxMask: + serializedVersion: 2 + m_Bits: 0 +--- !u!114 &6666768094922880470 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5847303612961356907} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6def12af0589a9545b80eb5accf61bb6, type: 3} + m_Name: + m_EditorClassIdentifier: + _repeatInterval: 0.5 --- !u!1 &5960285064422745315 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Game/Prefabs/Enemies/E006/ENM_Huan.prefab b/Assets/_Game/Prefabs/Enemies/E006/ENM_Huan.prefab index 8ad94914..5da3d139 100644 --- a/Assets/_Game/Prefabs/Enemies/E006/ENM_Huan.prefab +++ b/Assets/_Game/Prefabs/Enemies/E006/ENM_Huan.prefab @@ -719,38 +719,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _config: {fileID: 11400000, guid: f5f7cb08e1c1c83448830da185a7b796, type: 2} - _startClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _loopClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _endClip: - _FadeDuration: 0.25 - _Speed: 1 - _Events: - _NormalizedTimes: [] - _Callbacks: [] - _Names: [] - _Clip: {fileID: 0} - _NormalizedStartTime: NaN - _contactDamage: {fileID: 6544477441689240465} - _dashSpeed: 0 - references: - version: 2 - RefIds: [] --- !u!1 &5947943584201101387 GameObject: m_ObjectHideFlags: 0 @@ -838,7 +806,7 @@ MonoBehaviour: _hitInterval: 0.5 _targetLayers: serializedVersion: 2 - m_Bits: 4294967295 + m_Bits: 32768 _id: _rivalHitBoxMask: serializedVersion: 2 diff --git a/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs b/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs index a53a60c6..b1ee920c 100644 --- a/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs +++ b/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs @@ -310,7 +310,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); // Wire EnemyBase AssignReference(enemyBase, "_stats", enemyStats, report); @@ -379,7 +379,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); // References AssignReference(bossBase, "_stats", bossStats, report); @@ -450,7 +450,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: false, report); // E001 伪装期不伤,追击能力开 + SetupHurtAndContactBoxes(go, size, report); // 身体接触伤害常驻开启(与追击能力解耦) // Model A:AI 只决策触发哪个能力(Idle/Patrol/Alert 已改为纯移动意图,由 EnemyLocomotion 执行,无需挂能力组件) Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities"); @@ -484,7 +484,6 @@ namespace BaseGames.Editor AssignLayerMask(movement, "_wallMask", new[] { "Platform", "Wall" }, report); // 撞墙判定层(策划可调) AssignAsset(chaseAbility, "_config", report, false, "ABL_E001_Chase"); - AssignReference(chaseAbility, "_contactDamage", bodyContact, report); // 追击动画:起手/循环/收招(设计文档 Skill_Start/Loop/End) AssignClipTransition(chaseAbility, "_startClip", "Skill_Start", "Enemies/E001", report); AssignClipTransition(chaseAbility, "_loopClip", "Skill_Loop", "Enemies/E001", report); @@ -545,9 +544,9 @@ namespace BaseGames.Editor GetOrAddComponent(go); // required by EnemyNavAgent [RequireComponent] PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); - // HurtBox + ContactDamageZone(component.enabled 初始为 false:仅悬挂脆弱窗口期间由能力开启) + // HurtBox + ContactDamageZone(身体接触伤害常驻开启;HurtBox 悬挂期外关闭见下) var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); hurtBox.enabled = false; // 悬挂阶段外不可被攻击;CeilingHangStrikeAbility 在 _loopClip 期间开启 // AttackHitBox(钻出啃咬瞬间判定,由 CeilingHangStrikeAbility 激活) @@ -647,7 +646,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities"); Transform fallT = GetOrCreateChild(abilitiesT, "AnimatedCeilingDropAbility"); @@ -678,7 +677,6 @@ namespace BaseGames.Editor AssignLayerMask(movement, "_wallMask", new[] { "Platform", "Wall" }, report); // 撞墙判定层(策划可调) AssignAsset(fallAbility, "_config", report, false, "ABL_E003_Fall"); - AssignReference(fallAbility, "_contactDamage", bodyContact, report); // 出生 / 外部触发执行下坠能力(零代码:替代过去的 E003_YouZhi 专属脚本) EnemyAbilityTrigger fallTrigger = GetOrAddComponent(go); @@ -737,7 +735,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); Transform biteT = GetOrCreateChild(go.transform, "BiteHitBox"); SetLayer(biteT.gameObject, "EnemyHitBox", report); @@ -866,7 +864,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); Transform biteT = GetOrCreateChild(go.transform, "BiteHitBox"); SetLayer(biteT.gameObject, "EnemyHitBox", report); @@ -977,7 +975,7 @@ namespace BaseGames.Editor PhysicsPerceptionSystem sensorHub = GetOrAddComponent(go); var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); Transform landT = GetOrCreateChild(go.transform, "LandingHitBox"); SetLayer(landT.gameObject, "EnemyHitBox", report); @@ -1021,7 +1019,6 @@ namespace BaseGames.Editor AssignAsset(chaseAbl, "_config", report, false, "ABL_E006_Chase"); AssignReference(leapAbl, "_landingHitBox", landHitBox, report); - AssignReference(chaseAbl, "_contactDamage", bodyContact, report); Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody"); if (dmgSrc != null) @@ -1083,7 +1080,7 @@ namespace BaseGames.Editor // HurtBox + ContactDamageZone(Boss 身体接触伤害区,默认启用;策划可在 Inspector 关闭该子节点) var (hurtBox, bodyContact, contactHitBox) = - SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + SetupHurtAndContactBoxes(go, size, report); // Phase1 攻击 HitBox(默认禁用;技能执行时由 BossSkillExecutor 开关)。 // 计划:挥扇三连 FanCombo ×3 + 龙卷接触 Tornado。 @@ -2253,11 +2250,12 @@ namespace BaseGames.Editor /// /// 建/更新 HurtBox 与 ContactDamageZone 两个子节点:均为 BoxCollider2D、同尺寸 size、 /// 底部对齐 y=0、isTrigger=true。ContactDamageZone 带 HitBox + BodyContactDamage。 - /// contactEnabled:BodyContactDamage 初始启用状态(不需要接触伤害的敌人可传 false 或后续置节点非激活)。 - /// 返回 (hurtBox, bodyContact, contactHitBox) 供上层按需接线(如伤害源/能力引用)。 + /// 身体接触伤害默认常驻开启:所有敌人存活期间身体接触即持续造成伤害,与能力解耦、不由能力开关, + /// 死亡时经 EnemyBase.PerformDeath 统一禁用碰撞体而停止。 + /// 返回 (hurtBox, bodyContact, contactHitBox) 供上层按需接线(如伤害源)。 /// private static (HurtBox hurt, BodyContactDamage contact, HitBox contactHitBox) - SetupHurtAndContactBoxes(GameObject root, Vector2 size, bool contactEnabled, List report) + SetupHurtAndContactBoxes(GameObject root, Vector2 size, List report) { // HurtBox 子节点 var hurtT = GetOrCreateChild(root.transform, "HurtBox"); @@ -2277,8 +2275,10 @@ namespace BaseGames.Editor contactCol.isTrigger = true; AlignColliderBottomToPivot(contactCol); var contactHitBox = GetOrAddComponent(contactT.gameObject); + // 身体接触伤害只命中玩家,避免常驻开启后敌人之间互相误伤(EnemyHitBox × EnemyHurtBox 矩阵默认不忽略) + AssignLayerMask(contactHitBox, "_targetLayers", new[] { "PlayerHurtBox" }, report); var bodyContact = GetOrAddComponent(contactT.gameObject); - bodyContact.enabled = contactEnabled; + bodyContact.enabled = true; // 常驻开启:所有敌人默认身体接触伤害,存活即开、死亡才关 EnsureCollidersAreTriggers(contactT.gameObject); return (hurtBox, bodyContact, contactHitBox); diff --git a/Assets/_Game/Scripts/Enemies/Abilities/AnimatedCeilingDropAbility.cs b/Assets/_Game/Scripts/Enemies/Abilities/AnimatedCeilingDropAbility.cs index cf1a2355..74ea09f1 100644 --- a/Assets/_Game/Scripts/Enemies/Abilities/AnimatedCeilingDropAbility.cs +++ b/Assets/_Game/Scripts/Enemies/Abilities/AnimatedCeilingDropAbility.cs @@ -6,16 +6,14 @@ using UnityEngine; namespace BaseGames.Enemies.Abilities { /// - /// 带动画的天花板跌落能力:播放 Fall 动画 + 切换物理体为 Dynamic 自由下落,落地后启用接触伤害并恢复巡逻。 + /// 带动画的天花板跌落能力:播放 Fall 动画 + 切换物理体为 Dynamic 自由下落,落地后恢复巡逻。 /// 取代 sealed 的 CeilingDropAbility,动画所有权完整封装在本能力中。 - /// 可复用于任何需要从天花板落下并造成接触伤害的敌人。 + /// 可复用于任何需要从天花板落下的敌人。 + /// 身体接触伤害与本能力解耦:由常驻的 全程负责,本能力不再开关它。 /// [RequireComponent(typeof(Rigidbody2D))] public class AnimatedCeilingDropAbility : EnemyAbilityBase { - [Header("落地后")] - [SerializeField] private BodyContactDamage _contactDamage; - private AnimatedCeilingDropAbilitySO _cfg; private Rigidbody2D _rb; @@ -53,10 +51,7 @@ namespace BaseGames.Enemies.Abilities } _rb.velocity = Vector2.zero; - // 落地后启用接触伤害 - if (_contactDamage != null) - _contactDamage.enabled = true; - + // 身体接触伤害由常驻 BodyContactDamage 全程负责,落地无需在此开启。 yield return EnemyAbilityWaits.Get(_cfg.recoveryTime); // PlayLocomotionClip(Patrol) 播放 AnimConfig.Walk(地面移动动画) @@ -73,8 +68,6 @@ namespace BaseGames.Enemies.Abilities { if (_rb != null) _rb.velocity = Vector2.zero; - if (_contactDamage != null) - _contactDamage.enabled = false; } } } diff --git a/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs b/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs index cf443e0d..b919bf69 100644 --- a/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs +++ b/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs @@ -5,17 +5,15 @@ using UnityEngine; namespace BaseGames.Enemies.Abilities { /// - /// 冲刺追击 + 体接触伤害能力:起手(Skill_Start 张口) → 朝玩家方向直冲(Skill_Loop 快速爬行 + - /// 接触伤害),**直到撞墙/到平台边缘或玩家消失即停** → 收招(Skill_End)。一次冲刺为一次能力执行, + /// 冲刺追击能力:起手(Skill_Start 张口) → 朝玩家方向直冲(Skill_Loop 快速爬行), + /// **直到撞墙/到平台边缘或玩家消失即停** → 收招(Skill_End)。一次冲刺为一次能力执行, /// 结束后进入冷却(EnemyAbilitySO.cooldown);AI 追击态在冷却结束时经 EnsureAbility 重触发下一次冲刺。 /// 冲刺方向在起手后按玩家所在侧一次性确定(committed 冲锋,会越过跳开的玩家,可被躲)。 /// 追击动画由本能力全权驱动(Approach 步态不抢动画)。 + /// 身体接触伤害与本能力解耦:由常驻的 全程负责,本能力不再开关它。 /// public class ContactChaseAbility : EnemyAbilityBase { - [Header("接触伤害")] - [SerializeField] private BodyContactDamage _contactDamage; - private ContactChaseAbilitySO _cfg; protected override void Awake() @@ -56,11 +54,10 @@ namespace BaseGames.Enemies.Abilities float speed = _cfg.dashSpeed > 0f ? _cfg.dashSpeed : (_enemy.Stats != null ? _enemy.Stats.RunSpeed : 0f); - // 冲刺:朝该方向直冲、接触伤害开、播 Skill_Loop,直到撞墙/到边缘或玩家消失即停。 + // 冲刺:朝该方向直冲、播 Skill_Loop,直到撞墙/到边缘或玩家消失即停。 + // (身体接触伤害由常驻 BodyContactDamage 全程负责,此处不再开关。) if (_cfg.loopClip.Clip != null) _animancer.Play(_cfg.loopClip); - if (_contactDamage != null) - _contactDamage.enabled = true; float winX = _enemy.transform.position.x; float winT = 0f; @@ -82,14 +79,12 @@ namespace BaseGames.Enemies.Abilities _enemy.StopMovement(); // 收招 Skill_End;随后基类按 EnemyAbilitySO.cooldown 施加冷却。 - DisableContact(); yield return PlaySkillEnd(); Cleanup(); } protected override void OnInterrupted(InterruptReason reason) { - DisableContact(); // 丢失目标 = AI 主动退出追击态(ExternalRequest) → 播收招 Skill_End; // 受击/死亡/硬直等硬打断不播收招。协程已停,fire-and-forget;动画锁保证 Skill_End // 在其时长内不被巡逻步态盖掉。 @@ -109,12 +104,6 @@ namespace BaseGames.Enemies.Abilities yield return EnemyAbilityWaits.Get(_cfg.endClip.Clip.length); } - private void DisableContact() - { - if (_contactDamage != null) - _contactDamage.enabled = false; - } - private void Cleanup() { _enemy.SetEngaged(false); diff --git a/Assets/_Game/Scripts/Enemies/BodyContactDamage.cs b/Assets/_Game/Scripts/Enemies/BodyContactDamage.cs index a3ee28b8..d52f2154 100644 --- a/Assets/_Game/Scripts/Enemies/BodyContactDamage.cs +++ b/Assets/_Game/Scripts/Enemies/BodyContactDamage.cs @@ -4,9 +4,12 @@ using UnityEngine; namespace BaseGames.Enemies { /// - /// 接触伤害:组件启用时把 HitBox 切到 Interval 模式并持续激活, + /// 身体接触伤害:组件启用时把 HitBox 切到 Interval 模式并持续激活, /// 令敌人对停留在判定盒内的目标按固定间隔重复造成伤害。 - /// 适用于无攻击动画的简单障碍物、环境危险或测试场景。 + /// + /// 敌人默认常驻开启:只要敌人存活,身体接触即持续造成伤害;与任何攻击/移动能力解耦, + /// 不由能力开关。死亡由 EnemyBase.PerformDeath 统一禁用全部碰撞体而自然停止, + /// 对象池复用时 OnSpawn 恢复碰撞体 + GO 重新激活触发本组件 OnEnable 重新接管。 /// /// 重复命中由 HitBox 的 Interval 节奏(Enter/Exit 跟踪占用 + Update 轮询)驱动, /// 不再依赖反复 Activate()——后者无法对已停留目标补发 OnTriggerEnter,会导致只命中一次。 diff --git a/Docs/Guides/02_Enemy_Boss_Setup_Guide.md b/Docs/Guides/02_Enemy_Boss_Setup_Guide.md index ad25f7b4..cdaca48a 100644 --- a/Docs/Guides/02_Enemy_Boss_Setup_Guide.md +++ b/Docs/Guides/02_Enemy_Boss_Setup_Guide.md @@ -204,7 +204,7 @@ ENM_CaoZhi (根节点) ├── HurtBox/ │ ├── 组件:HurtBox、Collider2D(Is Trigger=true, Layer=EnemyHurtBox) ├── ContactDamageZone/ -│ ├── 组件:BodyContactDamage、HitBox、Collider2D(Is Trigger=true, Layer=EnemyHitBox) +│ ├── 组件:BodyContactDamage(默认常驻 enabled=true)、HitBox、Collider2D(Is Trigger=true, Layer=EnemyHitBox) └── Abilities/ ├── 子节点 Activate_Ability → 组件:PlayClipAbility └── 子节点 Chase_Ability → 组件:ContactChaseAbility @@ -235,7 +235,6 @@ ENM_CaoZhi (根节点) - `_config`:拖入 `ABL_E001_Chase.asset` - `_loopClip`:`Skill_Loop.anim` - `_endClip`:`Skill_End.anim` -- `_contactDamage`:拖入 `ContactDamageZone/` 节点上的 `BodyContactDamage` 组件 - `_sensorHub`:拖入根节点上的 `EnemySensorHub` 组件 - `_aggroSlotName`:`"aggro"` @@ -409,7 +408,7 @@ ENM_YouZhi (根节点) ├── 组件:Rigidbody2D(初始 Body Type=Kinematic,下落能力会自动切换为 Dynamic) ├── HurtBox/ ├── ContactDamageZone/ -│ └── 组件:BodyContactDamage(初始 enabled=false,落地后由能力自动启用) +│ └── 组件:BodyContactDamage(默认常驻 enabled=true;存活即身体接触伤害,与能力解耦,死亡时经 PerformDeath 统一关碰撞体停止) └── Abilities/ └── 子节点 Fall_Ability → 组件:AnimatedCeilingDropAbility ``` @@ -424,7 +423,6 @@ ENM_YouZhi (根节点) | `_maxFallTime` | `3`(超时保护) | | `_groundMask` | 选择 `Ground` Layer | | `_recoveryTime` | `0.1`(落地后短暂停顿) | -| `_contactDamage` | 拖入 `ContactDamageZone/` 的 BodyContactDamage | **EnemyAbilityTrigger 组件配置**(零代码出生/触发执行能力,替代过去的 E003_YouZhi 专属脚本): - `_abilityId`:`e003_fall`(与 `ABL_E003_Fall.asset` 的 `abilityId` 一致)