fix(BT12-Dev): EnemyDeath 근본 fix — Animator transition 5 + UnscaledTime + 진단 회수
근본 원인 (본 PM MCP 직접 진단):
- Enemy.controller 영역 Idle/Run/Hurt → Death/Hurt transition 부재 → death Trigger 호출 영역 transition X
- Animator updateMode = Normal·Time.timeScale = 0 (LevelUp 카드 선택) → Animator.Update 정지 → transition 영역 X
해결 (본 PM 자율 결정 + MCP 직접 적용):
- Enemy.controller transition 5 추가 (Idle→Death, Idle→Hurt, Run→Death, Run→Hurt, Hurt→Death)
→ manage_animation controller_add_transition 영역 직접 호출
- EnemyDeath.cs animator.updateMode = AnimatorUpdateMode.UnscaledTime 추가
→ Time.timeScale = 0 영역 영역 Animator 영역 정상 진행 → death animation 재생 + transition 발동
- 진단 Debug.Log 회수: Projectile (8 분기)·AttackHitbox (1줄)·EnemyDeath (1줄)
→ 사망 원인 확정 영역 회수 의무 정합
본 PM MCP 직접 진단 절차:
1. read_console — Console 직접 읽기 (Health@Enemy·Projectile 출력 검증)
2. controller_get_info — Enemy.controller parameters·states·transitions 직접 검증
3. execute_code — Player·Enemy 위치·Schedule<EnemyDeath> 직접 호출·Animator state 검증
4. manage_animation controller_add_transition — Animator transition 5 직접 추가
5. anim.SetTrigger("death") + anim.Update(0.5f) → Baddie-Death 진입 정합 검증
PD 결정 (2026-05-10): "MCP 활용해서 네가 직접 체크해" — 본 PM 자율 진단·fix·검증.
PD 자성 #13: PD에게 작업 떠넘기기 금지·MCP 능동 활용 의무.
This commit is contained in:
parent
d6764ceb6e
commit
f50196056b
|
|
@ -1,5 +1,80 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1101 &-4529516712060657819
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: hurt
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 1102385943819249538}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &-4341369660076969782
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: death
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 1102820478267390064}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &-3589952439751684934
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: death
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 1102820478267390064}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -81,7 +156,7 @@ BlendTree:
|
|||
m_BlendType: 0
|
||||
--- !u!1101 &110119416
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 3
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
|
|
@ -109,7 +184,7 @@ AnimatorStateTransition:
|
|||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &110135224
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 3
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
|
|
@ -137,7 +212,7 @@ AnimatorStateTransition:
|
|||
m_CanTransitionToSelf: 1
|
||||
--- !u!1107 &110773768
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 5
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
|
|
@ -170,7 +245,7 @@ AnimatorStateMachine:
|
|||
m_DefaultState: {fileID: 1102040898249463802}
|
||||
--- !u!1101 &1101000010127028388
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 3
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
|
|
@ -195,7 +270,7 @@ AnimatorStateTransition:
|
|||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &1101000013044116430
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 3
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
|
|
@ -342,7 +417,7 @@ AnimatorStateTransition:
|
|||
m_CanTransitionToSelf: 1
|
||||
--- !u!1102 &1102040898249463802
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
|
|
@ -352,6 +427,8 @@ AnimatorState:
|
|||
m_CycleOffset: 0
|
||||
m_Transitions:
|
||||
- {fileID: 1101392776920089998}
|
||||
- {fileID: -3589952439751684934}
|
||||
- {fileID: -4529516712060657819}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
|
|
@ -369,7 +446,7 @@ AnimatorState:
|
|||
m_TimeParameter:
|
||||
--- !u!1102 &1102385943819249538
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
|
|
@ -379,6 +456,7 @@ AnimatorState:
|
|||
m_CycleOffset: 0
|
||||
m_Transitions:
|
||||
- {fileID: 1101786070068309808}
|
||||
- {fileID: -4341369660076969782}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
|
|
@ -396,7 +474,7 @@ AnimatorState:
|
|||
m_TimeParameter:
|
||||
--- !u!1102 &1102469078766878910
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
|
|
@ -406,6 +484,8 @@ AnimatorState:
|
|||
m_CycleOffset: 0
|
||||
m_Transitions:
|
||||
- {fileID: 1101973801263089050}
|
||||
- {fileID: 3987740943136003294}
|
||||
- {fileID: 1971216200071372489}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
|
|
@ -423,7 +503,7 @@ AnimatorState:
|
|||
m_TimeParameter:
|
||||
--- !u!1102 &1102820478267390064
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
|
|
@ -447,3 +527,53 @@ AnimatorState:
|
|||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1101 &1971216200071372489
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: hurt
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 1102385943819249538}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &3987740943136003294
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: death
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 1102820478267390064}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@ namespace Platformer.Gameplay
|
|||
|
||||
public override void Execute()
|
||||
{
|
||||
// BT12-Dev 진단 (2026-05-10 PD A+B) — EnemyDeath.Execute 호출 검증.
|
||||
// 회수: PD 사망 원인 확정 후 본 PM revert commit.
|
||||
Debug.Log($"[EnemyDeath][Execute] enemy={(enemy != null ? enemy.name : "NULL")} collider={(enemy != null && enemy._collider != null ? enemy._collider.enabled.ToString() : "NULL")} t={Time.time:F2}");
|
||||
|
||||
if (enemy == null) return;
|
||||
|
||||
// 충돌·이동·patrol 영역 비활성
|
||||
|
|
@ -30,14 +26,25 @@ namespace Platformer.Gameplay
|
|||
if (body != null) body.simulated = false;
|
||||
|
||||
// death 애니메이션 트리거 (Enemy.controller 영역의 'death' parameter)
|
||||
// BT12-Dev 2026-05-10 — Enemy.controller 영역 Idle/Run/Hurt → Death transition 추가 후 정합 발동.
|
||||
// BT12-Dev 2026-05-10 근본 fix — Time.timeScale = 0 (카드 선택 모드) 영역 Animator Update Mode = Normal 정지 회피.
|
||||
// updateMode = UnscaledTime 영역 → timeScale 영향 X · death animation 정합 재생 + transition 정합 발동.
|
||||
var animator = enemy.GetComponent<Animator>();
|
||||
if (animator != null) animator.SetTrigger("death");
|
||||
if (animator != null)
|
||||
{
|
||||
animator.updateMode = AnimatorUpdateMode.UnscaledTime;
|
||||
animator.SetTrigger("death");
|
||||
}
|
||||
|
||||
// 사운드
|
||||
if (enemy._audio != null && enemy.ouch != null)
|
||||
enemy._audio.PlayOneShot(enemy.ouch);
|
||||
|
||||
// 1초 후 GameObject 영역 Destroy (사망 애니메이션 시간)
|
||||
// BT12-Dev 2026-05-10 근본 fix — Time.timeScale = 0 (카드 선택 모드) 영역 Object.Destroy(1f) 적용 X 영역 회피.
|
||||
// (1) MonoBehaviour Coroutine 영역 X — 본 Event는 일반 객체. 직접 Destroy 영역 즉시 호출.
|
||||
// (2) death 애니메이션 영역 GameObject 활성 영역 의무 — SetActive(false) 영역 X·Destroy 1.5f 영역 timeScale 영향 영역.
|
||||
// (3) 안전 영역 — destroyOnLoad 정합·timeScale=0 영역 영역 영역 — Destroy 영역 다음 frame 영역 적용 영역 (Time.timeScale=0 영역 영역 적용 X).
|
||||
// → 핵심: timeScale=1 시점 영역 LevelUpManager 카드 선택 종료 후 Time.timeScale=1 영역 → Destroy 영역 정합 적용.
|
||||
Object.Destroy(enemy.gameObject, 1f);
|
||||
|
||||
// BT12-MVP-A 영역 신규 (2026-05-08) — 적 처치 시 EXP 발급
|
||||
|
|
|
|||
|
|
@ -70,9 +70,6 @@ namespace Platformer.Mechanics
|
|||
if (!health.IsAlive)
|
||||
{
|
||||
var enemy = col.GetComponent<EnemyController>();
|
||||
// BT12-Dev 진단 (2026-05-10 PD A+B) — EnemyDeath schedule 호출 검증.
|
||||
// 회수: PD 사망 원인 확정 후 본 PM revert commit.
|
||||
Debug.Log($"[AttackHitbox][Schedule] col={col.name} enemy={(enemy != null ? enemy.name : "NULL")} hp={health.CurrentHP} t={Time.time:F2}");
|
||||
if (enemy != null)
|
||||
{
|
||||
Schedule<EnemyDeath>().enemy = enemy;
|
||||
|
|
|
|||
|
|
@ -43,54 +43,26 @@ namespace EerieVillage.Skills.Effectors
|
|||
|
||||
protected virtual void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
// BT12-Dev 진단 (2026-05-09 PD A안) — 적 피격 X 근본 진단.
|
||||
// 회수 의무: PD Console 결과 수령 + 근본 fix 적용 후 본 진단 Debug.Log 일괄 제거.
|
||||
Debug.Log($"[Projectile][Enter] other={other.name} layer={other.gameObject.layer} t={Time.time:F2}");
|
||||
|
||||
if (_hitTargets.Contains(other))
|
||||
{
|
||||
Debug.Log($"[Projectile][Return] _hitTargets duplicate other={other.name}");
|
||||
return;
|
||||
}
|
||||
if (_hitTargets.Contains(other)) return;
|
||||
|
||||
// PD 지시 2026-05-09 후속 방어 — 자기(Player) hit·자기 자신·hit 방어.
|
||||
if (other.GetComponent<PlayerController>() != null)
|
||||
{
|
||||
Debug.Log($"[Projectile][Return] PlayerController detected other={other.name}");
|
||||
return;
|
||||
}
|
||||
if (other.GetComponent<PlayerController>() != null) return;
|
||||
|
||||
// Enemy 레이어 한정.
|
||||
// Phase 2-D fallback (2026-05-09): TagManager에 "Enemy" 레이어 미등재 시 LayerMask.NameToLayer 반환값 = -1.
|
||||
// 레이어 매칭 실패 시 EnemyController 컴포넌트 존재 여부로 대체 판정.
|
||||
int enemyLayer = LayerMask.NameToLayer("Enemy");
|
||||
bool hasEnemyController = other.GetComponent<EnemyController>() != null;
|
||||
bool isEnemy = (enemyLayer != -1 && other.gameObject.layer == enemyLayer) || hasEnemyController;
|
||||
Debug.Log($"[Projectile][LayerCheck] enemyLayer={enemyLayer} otherLayer={other.gameObject.layer} hasEnemyController={hasEnemyController} isEnemy={isEnemy}");
|
||||
|
||||
if (!isEnemy)
|
||||
{
|
||||
Debug.Log($"[Projectile][Return] not Enemy other={other.name}");
|
||||
return;
|
||||
}
|
||||
bool isEnemy = (enemyLayer != -1 && other.gameObject.layer == enemyLayer)
|
||||
|| other.GetComponent<EnemyController>() != null;
|
||||
if (!isEnemy) return;
|
||||
|
||||
var health = other.GetComponent<Health>();
|
||||
if (health == null)
|
||||
{
|
||||
Debug.Log($"[Projectile][Return] Health component missing other={other.name}");
|
||||
return;
|
||||
}
|
||||
if (!health.IsAlive)
|
||||
{
|
||||
Debug.Log($"[Projectile][Return] Health not alive other={other.name} hp={health.CurrentHP}");
|
||||
return;
|
||||
}
|
||||
if (health == null || !health.IsAlive) return;
|
||||
|
||||
_hitTargets.Add(other);
|
||||
|
||||
// 유효 대미지 산출 (balance/01 v0.2 §3 공식 — ActiveSkillRuntime.CalculateEffectiveDamage())
|
||||
int damage = _runtime.CalculateEffectiveDamage();
|
||||
Debug.Log($"[Projectile][Hit] other={other.name} damage={damage}");
|
||||
|
||||
// 피해 적용
|
||||
health.Decrement(damage);
|
||||
|
|
|
|||
Loading…
Reference in New Issue