From f6f7eaaef24d3b4a04e8239ba1e25be8dd6ac570 Mon Sep 17 00:00:00 2001 From: dal4segno Date: Fri, 10 Apr 2026 09:43:26 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=93=9C=EB=A1=9C=EA=B7=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=EB=B3=84=20=EC=95=84=EC=9D=B4=EB=93=A4=20?= =?UTF-8?q?=EB=AA=A8=EC=85=98=20=EC=A0=84=ED=99=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EnemyAnimationController가 보스 런타임 페이즈를 Animator Phase 파라미터로 동기화\n- AC_Boss_Drog에 1/2페이즈 공용 Idle과 3페이즈 전용 Idle 상태 및 전이 추가\n- 정지 중 페이즈 변경과 이동/피격 후 복귀가 현재 페이즈 Idle로 이어지도록 정리 --- .../Controllers/AC_Boss_Drog.controller | 367 ++++++++++++------ .../Scripts/Enemy/EnemyAnimationController.cs | 25 ++ 2 files changed, 279 insertions(+), 113 deletions(-) diff --git a/Assets/_Game/Animations/Controllers/AC_Boss_Drog.controller b/Assets/_Game/Animations/Controllers/AC_Boss_Drog.controller index 2f09cafc..2064083d 100644 --- a/Assets/_Game/Animations/Controllers/AC_Boss_Drog.controller +++ b/Assets/_Game/Animations/Controllers/AC_Boss_Drog.controller @@ -1,5 +1,30 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1101 &-8931477014669629951 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 3 + m_ConditionEvent: Speed + m_EventTreshold: 0.01 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -4652545120162758660} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.9 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 0 --- !u!1107 &-8724618498758723359 AnimatorStateMachine: serializedVersion: 6 @@ -22,33 +47,6 @@ AnimatorStateMachine: m_ExitPosition: {x: 800, y: 120, z: 0} m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} m_DefaultState: {fileID: -1761221109508103449} ---- !u!1102 &-7908033645098541312 -AnimatorState: - serializedVersion: 6 - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Idle - m_Speed: 1 - m_CycleOffset: 0 - m_Transitions: - - {fileID: 3552691702041008167} - m_StateMachineBehaviours: [] - m_Position: {x: 50, y: 50, z: 0} - m_IKOnFeet: 0 - m_WriteDefaultValues: 1 - m_Mirror: 0 - m_SpeedParameterActive: 0 - m_MirrorParameterActive: 0 - m_CycleOffsetParameterActive: 0 - m_TimeParameterActive: 0 - m_Motion: {fileID: 7400000, guid: ebc8e8e59d375104babccd596aa3bdc0, type: 2} - m_Tag: - m_SpeedParameter: - m_MirrorParameter: - m_CycleOffsetParameter: - m_TimeParameter: --- !u!1101 &-7355565198356877363 AnimatorStateTransition: m_ObjectHideFlags: 1 @@ -96,6 +94,34 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 +--- !u!1101 &-5661198802355905067 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 4 + m_ConditionEvent: Speed + m_EventTreshold: 0.03 + - m_ConditionMode: 4 + m_ConditionEvent: Phase + m_EventTreshold: 3 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1582555298472611487} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.1 + m_TransitionOffset: 0 + m_ExitTime: 0.9 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 0 --- !u!1102 &-5654511470593336247 AnimatorState: serializedVersion: 6 @@ -107,7 +133,8 @@ AnimatorState: m_Speed: 1 m_CycleOffset: 0 m_Transitions: - - {fileID: -4610620118332829913} + - {fileID: 7762382708247891322} + - {fileID: 5235194402694696982} m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -132,9 +159,6 @@ AnimatorStateMachine: m_PrefabAsset: {fileID: 0} m_Name: Base Layer m_ChildStates: - - serializedVersion: 1 - m_State: {fileID: -7908033645098541312} - m_Position: {x: 30, y: 180, z: 0} - serializedVersion: 1 m_State: {fileID: -4652545120162758660} m_Position: {x: 290, y: 180, z: 0} @@ -150,6 +174,12 @@ AnimatorStateMachine: - serializedVersion: 1 m_State: {fileID: -5654511470593336247} m_Position: {x: 30, y: 270, z: 0} + - serializedVersion: 1 + m_State: {fileID: 1582555298472611487} + m_Position: {x: 240, y: 120, z: 0} + - serializedVersion: 1 + m_State: {fileID: -498625244521711372} + m_Position: {x: 240, y: 320, z: 0} m_ChildStateMachines: [] m_AnyStateTransitions: - {fileID: -6146543620670552976} @@ -161,7 +191,7 @@ AnimatorStateMachine: m_EntryPosition: {x: 50, y: 120, z: 0} m_ExitPosition: {x: 800, y: 120, z: 0} m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} - m_DefaultState: {fileID: -7908033645098541312} + m_DefaultState: {fileID: 1582555298472611487} --- !u!1102 &-4652545120162758660 AnimatorState: serializedVersion: 6 @@ -173,7 +203,8 @@ AnimatorState: m_Speed: 1 m_CycleOffset: 0 m_Transitions: - - {fileID: 8997152603305261974} + - {fileID: -5661198802355905067} + - {fileID: -4269009376538978435} m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -183,34 +214,40 @@ AnimatorState: m_MirrorParameterActive: 0 m_CycleOffsetParameterActive: 0 m_TimeParameterActive: 0 - m_Motion: {fileID: -1886843759694807048} + m_Motion: {fileID: 7400000, guid: 51c52bb037757304ca6faaf68c181bcd, type: 2} m_Tag: m_SpeedParameter: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: ---- !u!1101 &-4610620118332829913 +--- !u!1101 &-4269009376538978435 AnimatorStateTransition: m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: - m_Conditions: [] + m_Conditions: + - m_ConditionMode: 4 + m_ConditionEvent: Speed + m_EventTreshold: 0.03 + - m_ConditionMode: 6 + m_ConditionEvent: Phase + m_EventTreshold: 3 m_DstStateMachine: {fileID: 0} - m_DstState: {fileID: -7908033645098541312} + m_DstState: {fileID: -498625244521711372} m_Solo: 0 m_Mute: 0 m_IsExit: 0 serializedVersion: 3 - m_TransitionDuration: 0.25 + m_TransitionDuration: 0.1 m_TransitionOffset: 0 - m_ExitTime: 0.75 - m_HasExitTime: 1 + m_ExitTime: 0.9 + m_HasExitTime: 0 m_HasFixedDuration: 1 m_InterruptionSource: 0 m_OrderedInterruption: 1 - m_CanTransitionToSelf: 1 + m_CanTransitionToSelf: 0 --- !u!1102 &-2487449162152911812 AnimatorState: serializedVersion: 6 @@ -237,45 +274,6 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: ---- !u!206 &-1886843759694807048 -BlendTree: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Blend Tree - m_Childs: - - serializedVersion: 2 - m_Motion: {fileID: 4441030841997727119, guid: 005ddab128d7eb141b25099c0eb1ed39, type: 3} - m_Threshold: 0 - m_Position: {x: 0, y: 0} - m_TimeScale: 1 - m_CycleOffset: 0 - m_DirectBlendParameter: Speed - m_Mirror: 0 - - serializedVersion: 2 - m_Motion: {fileID: 2571081563578608591, guid: e6a2aa1552aac6f46b40192ec605d57e, type: 3} - m_Threshold: 0.5 - m_Position: {x: 0, y: 0} - m_TimeScale: 1 - m_CycleOffset: 0 - m_DirectBlendParameter: Speed - m_Mirror: 0 - - serializedVersion: 2 - m_Motion: {fileID: 1827226128182048838, guid: 60fb511bc6259b745b432aea6a222303, type: 3} - m_Threshold: 1 - m_Position: {x: 0, y: 0} - m_TimeScale: 1 - m_CycleOffset: 0 - m_DirectBlendParameter: Speed - m_Mirror: 0 - m_BlendParameter: Speed - m_BlendParameterY: Speed - m_MinThreshold: 0 - m_MaxThreshold: 1 - m_UseAutomaticThresholds: 1 - m_NormalizedBlendValues: 0 - m_BlendType: 0 --- !u!1102 &-1761221109508103449 AnimatorState: serializedVersion: 6 @@ -302,6 +300,31 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: +--- !u!1101 &-1591912023002520841 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 3 + m_ConditionEvent: Speed + m_EventTreshold: 0.01 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -4652545120162758660} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.9 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 0 --- !u!1101 &-1314145896434046212 AnimatorStateTransition: m_ObjectHideFlags: 1 @@ -327,6 +350,34 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 +--- !u!1102 &-498625244521711372 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Idle_Phase3 + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: -1591912023002520841} + - {fileID: 5829157465128090080} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 1654c779ca38159dab86a08864968bcc, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: --- !u!91 &9100000 AnimatorController: m_ObjectHideFlags: 0 @@ -384,6 +435,12 @@ AnimatorController: m_DefaultInt: 0 m_DefaultBool: 0 m_Controller: {fileID: 9100000} + - m_Name: Phase + m_Type: 3 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 9100000} m_AnimatorLayers: - serializedVersion: 5 m_Name: Base Layer @@ -412,7 +469,7 @@ AnimatorController: m_State: {fileID: -2487449162152911812} m_Motion: {fileID: 8640942340808133859, guid: 235e9fb2014c3044ba826dd0e71987a4, type: 3} - serializedVersion: 2 - m_State: {fileID: -7908033645098541312} + m_State: {fileID: 0} m_Motion: {fileID: 9143937929783346939, guid: 92dc2765bff93f540a4433ac13713d72, type: 3} m_Behaviours: [] m_BlendingMode: 0 @@ -421,7 +478,35 @@ AnimatorController: m_IKPass: 0 m_SyncedLayerAffectsTiming: 0 m_Controller: {fileID: 9100000} ---- !u!1101 &3552691702041008167 +--- !u!1102 &1582555298472611487 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Idle_Phase1 + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: -8931477014669629951} + - {fileID: 2459631991574308566} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: ed7913df0854ae86a9374a34d7ebdc7d, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1101 &2459631991574308566 AnimatorStateTransition: m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} @@ -429,23 +514,26 @@ AnimatorStateTransition: m_PrefabAsset: {fileID: 0} m_Name: m_Conditions: - - m_ConditionMode: 3 + - m_ConditionMode: 4 m_ConditionEvent: Speed - m_EventTreshold: 0.01 + m_EventTreshold: 0.03 + - m_ConditionMode: 6 + m_ConditionEvent: Phase + m_EventTreshold: 3 m_DstStateMachine: {fileID: 0} - m_DstState: {fileID: -4652545120162758660} + m_DstState: {fileID: -498625244521711372} m_Solo: 0 m_Mute: 0 m_IsExit: 0 serializedVersion: 3 - m_TransitionDuration: 0.25 + m_TransitionDuration: 0.15 m_TransitionOffset: 0 - m_ExitTime: 0.75 + m_ExitTime: 0.9 m_HasExitTime: 0 m_HasFixedDuration: 1 m_InterruptionSource: 0 m_OrderedInterruption: 1 - m_CanTransitionToSelf: 1 + m_CanTransitionToSelf: 0 --- !u!1102 &4717780193306342999 AnimatorState: serializedVersion: 6 @@ -473,6 +561,59 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: +--- !u!1101 &5235194402694696982 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 6 + m_ConditionEvent: Phase + m_EventTreshold: 3 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -498625244521711372} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.75 + m_HasExitTime: 1 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 0 +--- !u!1101 &5829157465128090080 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 4 + m_ConditionEvent: Speed + m_EventTreshold: 0.03 + - m_ConditionMode: 4 + m_ConditionEvent: Phase + m_EventTreshold: 3 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1582555298472611487} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.15 + m_TransitionOffset: 0 + m_ExitTime: 0.9 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 0 --- !u!1101 &7571880184799686224 AnimatorStateTransition: m_ObjectHideFlags: 1 @@ -495,6 +636,31 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 +--- !u!1101 &7762382708247891322 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 4 + m_ConditionEvent: Phase + m_EventTreshold: 3 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1582555298472611487} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.75 + m_HasExitTime: 1 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 0 --- !u!1102 &8846385207969213533 AnimatorState: serializedVersion: 6 @@ -522,28 +688,3 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: ---- !u!1101 &8997152603305261974 -AnimatorStateTransition: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: - m_Conditions: - - m_ConditionMode: 4 - m_ConditionEvent: Speed - m_EventTreshold: 0.03 - m_DstStateMachine: {fileID: 0} - m_DstState: {fileID: -7908033645098541312} - m_Solo: 0 - m_Mute: 0 - m_IsExit: 0 - serializedVersion: 3 - m_TransitionDuration: 0.1 - m_TransitionOffset: 0 - m_ExitTime: 0.9977373 - m_HasExitTime: 0 - m_HasFixedDuration: 0 - m_InterruptionSource: 0 - m_OrderedInterruption: 1 - m_CanTransitionToSelf: 1 diff --git a/Assets/_Game/Scripts/Enemy/EnemyAnimationController.cs b/Assets/_Game/Scripts/Enemy/EnemyAnimationController.cs index faa6b803..7edea99f 100644 --- a/Assets/_Game/Scripts/Enemy/EnemyAnimationController.cs +++ b/Assets/_Game/Scripts/Enemy/EnemyAnimationController.cs @@ -11,6 +11,7 @@ namespace Colosseum.Enemy { [Header("Animation Parameters")] [SerializeField] private string speedParam = "Speed"; + [SerializeField] private string phaseParam = "Phase"; [SerializeField] private string attackTriggerParam = "Attack"; [SerializeField] private string skillTriggerParam = "Skill"; @@ -21,6 +22,7 @@ namespace Colosseum.Enemy private Animator animator; private UnityEngine.AI.NavMeshAgent navMeshAgent; private EnemyBase enemyBase; + private BossBehaviorRuntimeState runtimeState; private float currentSpeed; private float speedVelocity; @@ -29,6 +31,7 @@ namespace Colosseum.Enemy animator = GetComponent(); navMeshAgent = GetComponent(); enemyBase = GetComponent(); + runtimeState = GetComponent(); } public override void OnNetworkSpawn() @@ -70,6 +73,12 @@ namespace Colosseum.Enemy // 애니메이터 파라미터 설정 animator.SetFloat(speedParam, currentSpeed); + + if (HasAnimatorParameter(animator, phaseParam, AnimatorControllerParameterType.Int)) + { + int currentPhase = runtimeState != null ? runtimeState.CurrentPatternPhase : 1; + animator.SetInteger(phaseParam, Mathf.Max(1, currentPhase)); + } } /// @@ -122,5 +131,21 @@ namespace Colosseum.Enemy /// 현재 애니메이션 속도 /// public float CurrentSpeed => currentSpeed; + + private static bool HasAnimatorParameter(Animator targetAnimator, string parameterName, AnimatorControllerParameterType parameterType) + { + if (targetAnimator == null || string.IsNullOrEmpty(parameterName)) + return false; + + AnimatorControllerParameter[] parameters = targetAnimator.parameters; + for (int i = 0; i < parameters.Length; i++) + { + AnimatorControllerParameter parameter = parameters[i]; + if (parameter.type == parameterType && parameter.name == parameterName) + return true; + } + + return false; + } } }