diff --git a/Assets/Editor/EnemyControllerEditor.cs b/Assets/Editor/EnemyControllerEditor.cs
index 23ac07cc..82dc98de 100644
--- a/Assets/Editor/EnemyControllerEditor.cs
+++ b/Assets/Editor/EnemyControllerEditor.cs
@@ -30,12 +30,6 @@ public class EnemyControllerEditor : Editor
case EnemyState.Attack:
GUI.backgroundColor = new Color(1, 1, 0, 1f);
break;
- case EnemyState.Move:
- GUI.backgroundColor = new Color(0, 1, 1, 1f);
- break;
- case EnemyState.GetHit:
- GUI.backgroundColor = new Color(0.1f, 0.1f, 0.1f, 1f);
- break;
case EnemyState.Dead:
GUI.backgroundColor = new Color(1, 0, 0, 1f);
break;
@@ -55,12 +49,10 @@ public class EnemyControllerEditor : Editor
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Idle")) enemyController.SetState(EnemyState.Idle);
if (GUILayout.Button("Trace")) enemyController.SetState(EnemyState.Trace);
- if (GUILayout.Button("Attack")) enemyController.SetState(EnemyState.Attack);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
- if (GUILayout.Button("Move")) enemyController.SetState(EnemyState.Move);
- if (GUILayout.Button("GetHit")) enemyController.SetState(EnemyState.GetHit);
+ if (GUILayout.Button("Attack")) enemyController.SetState(EnemyState.Attack);
if (GUILayout.Button("Dead")) enemyController.SetState(EnemyState.Dead);
EditorGUILayout.EndHorizontal();
}
diff --git a/Assets/JYY/Animator/PldDogControl.controller b/Assets/JYY/Animator/PldDogControl.controller
index a67e40bf..7b80e503 100644
--- a/Assets/JYY/Animator/PldDogControl.controller
+++ b/Assets/JYY/Animator/PldDogControl.controller
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b9e37c8d0a91f3599d34a7715c632cbcf76fd3c0a96c5d5335ab9d6ff65d3b4c
-size 18916
+oid sha256:9473c357cb74d4228523205a76d0a1a1cc71d82baf736270906c82a171efe7e6
+size 16154
diff --git a/Assets/JYY/Models.meta b/Assets/JYY/Models.meta
new file mode 100644
index 00000000..7143abc3
--- /dev/null
+++ b/Assets/JYY/Models.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ac3af37988877784e91ab90c4ade37d9
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Models/Y Bot.fbx b/Assets/JYY/Models/Y Bot.fbx
new file mode 100644
index 00000000..a5c4d7be
--- /dev/null
+++ b/Assets/JYY/Models/Y Bot.fbx
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:470fcb658dd731d414d635615d6232be394e7ea23915fb92ad41a0fca4d592bc
+size 1982368
diff --git a/Assets/JYY/Models/Y Bot.fbx.meta b/Assets/JYY/Models/Y Bot.fbx.meta
new file mode 100644
index 00000000..2e914645
--- /dev/null
+++ b/Assets/JYY/Models/Y Bot.fbx.meta
@@ -0,0 +1,109 @@
+fileFormatVersion: 2
+guid: decb96f75d6a2344baa18f902f21a131
+ModelImporter:
+ serializedVersion: 22200
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 1
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ rigImportErrors:
+ rigImportWarnings:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 3
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 0
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 1
+ importBlendShapes: 1
+ importCameras: 1
+ importLights: 1
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 0
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 3
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 1
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 1
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 3
+ humanoidOversampling: 1
+ avatarSetup: 1
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/AOEIndicator.prefab b/Assets/JYY/Prefabs/AOEIndicator.prefab
deleted file mode 100644
index 6ac5eda7..00000000
--- a/Assets/JYY/Prefabs/AOEIndicator.prefab
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8b8cb01bd819acc4a85f049a7fa119e05a3587e1f3b9e88ce1f0f0729a09b326
-size 4274
diff --git a/Assets/JYY/Prefabs/AOEIndicatorChariot.prefab b/Assets/JYY/Prefabs/AOEIndicatorChariot.prefab
deleted file mode 100644
index 5b73b6cb..00000000
--- a/Assets/JYY/Prefabs/AOEIndicatorChariot.prefab
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:db1f3ad7db0d99b20fdfe95c0ba7248476edee0875596606eb05ac19c33e84f2
-size 4283
diff --git a/Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab b/Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab
index 72d92b28..10a01d7f 100644
--- a/Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab
+++ b/Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bf0fd0659c187d35c8492ff925145c94fc5cac08dead6b13188f3f4cbb2f3052
-size 3988
+oid sha256:5fd0a892305c7a4c4e18543cf88703c940210e639e0a0a94aba30f0fe7fb4a2d
+size 3986
diff --git a/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab b/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab
index d6ba9554..2617bea6 100644
--- a/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab
+++ b/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e5dfaa59aeffa4e948edd40e96f05e2c708e491bb80c2a3446d9d1335b05adf0
+oid sha256:a8dcf363afeb774bbc49dde7a349e233c2ff8531d33694113013455fc7a4c7ca
size 3995
diff --git a/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab.meta b/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab.meta
index 586188cb..49096c4a 100644
--- a/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab.meta
+++ b/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 44d67bf59c049fb46876a549120a16d7
+guid: 0e60f1766f73dbc439ff69a154cc9a99
PrefabImporter:
externalObjects: {}
userData:
diff --git a/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab b/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab
index 28217b13..7acabcd4 100644
--- a/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab
+++ b/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:02ada0ed142206f604609397dd5b6a2349df7db879e9ab1cb7bdfc1fca8e6f75
+oid sha256:e8da3f157ed92e5524a0fb90cbd4335a8b757a2ef2889f00ae2e66bd704017e6
size 3985
diff --git a/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab.meta b/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab.meta
index 2202360a..877a5f21 100644
--- a/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab.meta
+++ b/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 9adff7c5e2e43974fa9f2d241ef2e433
+guid: dc0537feab3e2944aa554e23fb3923a3
PrefabImporter:
externalObjects: {}
userData:
diff --git a/Assets/JYY/Prefabs/AoE Indicator Chariot.prefab b/Assets/JYY/Prefabs/AoE Indicator Chariot.prefab
new file mode 100644
index 00000000..20a9ce49
--- /dev/null
+++ b/Assets/JYY/Prefabs/AoE Indicator Chariot.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:da22007db35be49ea0f412048256923f214ff6be182768aba94ea8137146c067
+size 5237
diff --git a/Assets/JYY/Prefabs/AOEIndicator.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator Chariot.prefab.meta
similarity index 100%
rename from Assets/JYY/Prefabs/AOEIndicator.prefab.meta
rename to Assets/JYY/Prefabs/AoE Indicator Chariot.prefab.meta
diff --git a/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab b/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab
new file mode 100644
index 00000000..3b79cddf
--- /dev/null
+++ b/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:27404af56e20a87bf6555fc1bbad80f7756f8412d15bccca896ea8c98a221ff7
+size 4474
diff --git a/Assets/JYY/Prefabs/AOEIndicatorChariot.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab.meta
similarity index 74%
rename from Assets/JYY/Prefabs/AOEIndicatorChariot.prefab.meta
rename to Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab.meta
index 1d15c4e7..586188cb 100644
--- a/Assets/JYY/Prefabs/AOEIndicatorChariot.prefab.meta
+++ b/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: e9e020ef2784edf4ca2a83ae9e1edefd
+guid: 44d67bf59c049fb46876a549120a16d7
PrefabImporter:
externalObjects: {}
userData:
diff --git a/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab b/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab
new file mode 100644
index 00000000..438c2522
--- /dev/null
+++ b/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e6f2c2d8b80d4562e9a72bfc313a716717ae8bf33192053e85b12aeea9b9b9ff
+size 4459
diff --git a/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab.meta
new file mode 100644
index 00000000..2202360a
--- /dev/null
+++ b/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9adff7c5e2e43974fa9f2d241ef2e433
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab b/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab
new file mode 100644
index 00000000..995bcd81
--- /dev/null
+++ b/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0d42386e12ec2eec2385f13fdcd2558718c9150245a834d5a667060f750b1ced
+size 3100
diff --git a/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab.meta b/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab.meta
new file mode 100644
index 00000000..5ba3ecc5
--- /dev/null
+++ b/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 3f431e991bd65014c833e89305ddd5e3
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/Charge slash red.prefab b/Assets/JYY/Prefabs/Charge slash red.prefab
new file mode 100644
index 00000000..3f562bef
--- /dev/null
+++ b/Assets/JYY/Prefabs/Charge slash red.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:401068a261779945bc03fed98b231b07965d7520470f19f5b1ff2b6bf73b4f59
+size 710841
diff --git a/Assets/JYY/Prefabs/Charge slash red.prefab.meta b/Assets/JYY/Prefabs/Charge slash red.prefab.meta
new file mode 100644
index 00000000..bf5f20d3
--- /dev/null
+++ b/Assets/JYY/Prefabs/Charge slash red.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8a0ddc8dd6d760e4e93999c4d49dc16c
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/Explosion.prefab b/Assets/JYY/Prefabs/Explosion.prefab
new file mode 100644
index 00000000..780b51ec
--- /dev/null
+++ b/Assets/JYY/Prefabs/Explosion.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a95da2a8bdc43724d48bc36adc162d419090185d28b9df881af7de481a53c4f3
+size 473754
diff --git a/Assets/JYY/Prefabs/Explosion.prefab.meta b/Assets/JYY/Prefabs/Explosion.prefab.meta
new file mode 100644
index 00000000..5f3ac223
--- /dev/null
+++ b/Assets/JYY/Prefabs/Explosion.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2ccd5acc2f6d74d4bb687fd2ee94b9de
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/Red energy explosion 1.prefab b/Assets/JYY/Prefabs/Red energy explosion 1.prefab
new file mode 100644
index 00000000..39f7c17d
--- /dev/null
+++ b/Assets/JYY/Prefabs/Red energy explosion 1.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1364f3853992b0997dcd5fb86204334c243e4b464bf6d96da6374dcb2e98f8d9
+size 1305159
diff --git a/Assets/JYY/Prefabs/Red energy explosion 1.prefab.meta b/Assets/JYY/Prefabs/Red energy explosion 1.prefab.meta
new file mode 100644
index 00000000..a8bb01f0
--- /dev/null
+++ b/Assets/JYY/Prefabs/Red energy explosion 1.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 49ada3fea2be23f4a988d4bc21dcaa32
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/Snow slash 1.prefab b/Assets/JYY/Prefabs/Snow slash 1.prefab
new file mode 100644
index 00000000..4b1759bb
--- /dev/null
+++ b/Assets/JYY/Prefabs/Snow slash 1.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:72a13e9bb38f18954e603c863b4b610882f8b43d55ba27499daf3bcfe42830b8
+size 474114
diff --git a/Assets/JYY/Prefabs/Snow slash 1.prefab.meta b/Assets/JYY/Prefabs/Snow slash 1.prefab.meta
new file mode 100644
index 00000000..a886fdef
--- /dev/null
+++ b/Assets/JYY/Prefabs/Snow slash 1.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 03a874e2d684ee04a9729b8363fdbb9c
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/JYY/Prefabs/[Enemy] PldDog.prefab b/Assets/JYY/Prefabs/[Enemy] PldDog.prefab
index f383c5f8..8b998d43 100644
--- a/Assets/JYY/Prefabs/[Enemy] PldDog.prefab
+++ b/Assets/JYY/Prefabs/[Enemy] PldDog.prefab
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c7b23e4a2f6475f6cfe0641a03fd4415fe2b732fe649a14f93b72ea104f250f3
-size 80026
+oid sha256:a4cedd199100ba2d66a0dfe22b6ab902677fcc6485b02d0553115d0e012b3c97
+size 79510
diff --git a/Assets/JYY/Scenes/MonsterTest.unity b/Assets/JYY/Scenes/MonsterTest.unity
index a2f28549..f315080d 100644
--- a/Assets/JYY/Scenes/MonsterTest.unity
+++ b/Assets/JYY/Scenes/MonsterTest.unity
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ec97ec66df4283ed273c243f4aa1642c492661d1163184ce650d833e5a36bd87
-size 19269
+oid sha256:70e2e15667c9821fdb140d6ca8987d4caf3436e36abc139ba9da1192a5428331
+size 21018
diff --git a/Assets/Scripts/Character/Enemy/BossPattern.meta b/Assets/Scripts/Character/Enemy/BossPattern.meta
new file mode 100644
index 00000000..e375e2dd
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: d3b800a343fe42afa7494329ef235461
+timeCreated: 1745300808
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/AoeControllerBase.cs b/Assets/Scripts/Character/Enemy/BossPattern/AoeControllerBase.cs
new file mode 100644
index 00000000..bf689d3f
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/AoeControllerBase.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections;
+using UnityEngine;
+
+
+[Serializable]
+public struct DamageEffectData
+{
+ public int damage;
+ public float radius;
+ public float delay;
+ public LayerMask targetLayer;
+ public GameObject explosionEffectPrefab;
+}
+
+///
+/// AOE 범위 공격의 공통 로직을 처리하는 추상 베이스 클래스입니다.
+///
+public abstract class AoeControllerBase : MonoBehaviour
+{
+ [Header("경고 이펙트")]
+ [SerializeField] protected GameObject warningEffectInstance;
+
+ protected DamageEffectData _data;
+ private Action _slashAction;
+ private Action _destroyAction;
+
+ ///
+ /// 범위 공격 이펙트를 설정하고, 딜레이 후 폭발을 실행합니다.
+ ///
+ public void SetEffect(DamageEffectData data, Action slashAction, Action destroyAction)
+ {
+ _data = data;
+ _slashAction = slashAction;
+ _destroyAction = destroyAction;
+
+ ShowWarningEffect();
+ StartCoroutine(ExplodeAfterDelay());
+ }
+
+ protected virtual void ShowWarningEffect()
+ {
+ if (warningEffectInstance != null)
+ warningEffectInstance.SetActive(true);
+
+ float diameter = _data.radius * 2f;
+ transform.localScale = new Vector3(diameter, 1f, diameter);
+ }
+
+ private IEnumerator ExplodeAfterDelay()
+ {
+ yield return new WaitForSeconds(_data.delay);
+ Explode();
+ }
+
+ ///
+ /// 폭발 이펙트 생성, 데미지 처리, 콜백 호출 순서로 실행합니다.
+ ///
+ protected virtual void Explode()
+ {
+ // 경고 이펙트 숨기기
+ if (warningEffectInstance != null)
+ warningEffectInstance.SetActive(false);
+
+ ShowDamageEffect();
+
+ // 슬래시 액션(애니메이션 트리거) 호출
+ _slashAction?.Invoke();
+
+ // 범위 내 데미지 처리
+ HitCheck();
+
+ // 패턴 클리어 콜백
+ _destroyAction?.Invoke();
+
+ // 자기 자신 제거
+ Destroy(gameObject, 2f);
+ }
+
+ protected virtual void HitCheck()
+ {
+ var hits = Physics.OverlapSphere(transform.position, _data.radius, _data.targetLayer);
+ foreach (var hit in hits)
+ {
+ if (hit.CompareTag("Player"))
+ {
+ Debug.Log($"{hit.name}에게 {_data.damage} 데미지 적용");
+ // TODO: 실제 데미지 처리 로직 호출
+ }
+ }
+ }
+
+ protected virtual void ShowDamageEffect()
+ {
+ // 폭발 이펙트 생성
+ if (_data.explosionEffectPrefab != null)
+ {
+ var effect = Instantiate(_data.explosionEffectPrefab, transform.position, transform.rotation);
+ effect.transform.localScale = new Vector3(_data.radius, _data.radius, _data.radius);
+ Destroy(effect, 2f);
+ }
+ }
+
+ protected virtual void OnDrawGizmosSelected()
+ {
+ Gizmos.color = Color.red;
+ Gizmos.DrawWireSphere(transform.position, _data.radius);
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/AoeControllerBase.cs.meta b/Assets/Scripts/Character/Enemy/BossPattern/AoeControllerBase.cs.meta
new file mode 100644
index 00000000..532cedaa
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/AoeControllerBase.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1dd40dca214a4038be21f64ce645e5d9
+timeCreated: 1745393630
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/BoomAoeController.cs b/Assets/Scripts/Character/Enemy/BossPattern/BoomAoeController.cs
new file mode 100644
index 00000000..560b885d
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/BoomAoeController.cs
@@ -0,0 +1,4 @@
+public class BoomAoeController : AoeControllerBase
+{
+
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/BoomAoeController.cs.meta b/Assets/Scripts/Character/Enemy/BossPattern/BoomAoeController.cs.meta
new file mode 100644
index 00000000..8bf641f6
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/BoomAoeController.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e32c2002701d49df83faa36b3da55436
+timeCreated: 1745395178
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs b/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs
new file mode 100644
index 00000000..e658d92a
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections;
+using UnityEngine;
+
+
+
+public class ChariotAoeController : AoeControllerBase
+{
+ protected override void ShowDamageEffect()
+ {
+ // 폭발 이펙트 생성
+ if (_data.explosionEffectPrefab != null)
+ {
+ var effect = Instantiate(_data.explosionEffectPrefab, transform.position, transform.rotation);
+ effect.transform.localScale = new Vector3(2f, 2f, 2f);
+ Destroy(effect, 2f);
+ }
+ }
+}
diff --git a/Assets/Scripts/Character/Enemy/EnemyAttackController.cs.meta b/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs.meta
similarity index 100%
rename from Assets/Scripts/Character/Enemy/EnemyAttackController.cs.meta
rename to Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs.meta
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/HorizontalAoeController.cs b/Assets/Scripts/Character/Enemy/BossPattern/HorizontalAoeController.cs
new file mode 100644
index 00000000..6ef4c7c0
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/HorizontalAoeController.cs
@@ -0,0 +1,52 @@
+using UnityEngine;
+
+public class HorizontalAoeController : AoeControllerBase
+{
+ private float slashAngle = 270f;
+ private int gizmoSegments = 20;
+ protected override void HitCheck()
+ {
+ var hits = Physics.OverlapSphere(transform.position, _data.radius, _data.targetLayer);
+ foreach (var hit in hits)
+ {
+ if (!hit.CompareTag("Player")) continue;
+
+ Vector3 dir = hit.transform.position - transform.position;
+ dir.y = 0;
+ float angleToForward = Vector3.Angle(transform.forward, dir);
+
+ if (angleToForward <= slashAngle * 0.5f)
+ {
+ Debug.Log($"{hit.name}이(가) 횡적 슬래시 데미지 범위에 있습니다.");
+ Debug.Log($"{hit.name}에게 {_data.damage} 데미지 적용");
+ // TODO: 실제 데미지 처리 로직 호출
+ }
+ }
+ }
+
+ private void OnDrawGizmosSelected()
+ {
+ // 부채꼴 형태 기즈모 드로잉
+ Gizmos.color = Color.red;
+ Vector3 origin = transform.position;
+ float halfAngle = slashAngle * 0.5f;
+ float step = slashAngle / gizmoSegments;
+
+ // 시작 포인트
+ Vector3 prevDir = Quaternion.AngleAxis(-halfAngle, Vector3.up) * transform.forward;
+ Vector3 prevPoint = origin + prevDir.normalized * _data.radius;
+ Gizmos.DrawLine(origin, prevPoint);
+
+ for (int i = 1; i <= gizmoSegments; i++)
+ {
+ float currentAngle = -halfAngle + step * i;
+ Vector3 currDir = Quaternion.AngleAxis(currentAngle, Vector3.up) * transform.forward;
+ Vector3 currPoint = origin + currDir.normalized * _data.radius;
+ Gizmos.DrawLine(prevPoint, currPoint);
+ prevPoint = currPoint;
+ }
+
+ // 마지막 라인
+ Gizmos.DrawLine(origin, prevPoint);
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/HorizontalAoeController.cs.meta b/Assets/Scripts/Character/Enemy/BossPattern/HorizontalAoeController.cs.meta
new file mode 100644
index 00000000..0fc4ea79
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/HorizontalAoeController.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e77da766410d47f9a7effebd30fd33f6
+timeCreated: 1745394588
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/VerticalAoeController.cs b/Assets/Scripts/Character/Enemy/BossPattern/VerticalAoeController.cs
new file mode 100644
index 00000000..37b3fbb0
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/VerticalAoeController.cs
@@ -0,0 +1,51 @@
+using UnityEngine;
+
+public class VerticalAoeController : AoeControllerBase
+{
+
+ protected override void ShowWarningEffect()
+ {
+ if (warningEffectInstance != null)
+ warningEffectInstance.SetActive(true);
+
+ var centerCap = Vector3.forward * _data.radius;
+ float diameter = _data.radius * 2f;
+ transform.localScale = new Vector3(_data.radius, 1f, diameter);
+ transform.Translate(centerCap, Space.Self);
+ }
+
+ protected override void ShowDamageEffect()
+ {
+ // 폭발 이펙트 생성
+ if (_data.explosionEffectPrefab != null)
+ {
+ var effect = Instantiate(_data.explosionEffectPrefab, transform.position, transform.rotation);
+ effect.transform.localScale = new Vector3(_data.radius, _data.radius, _data.radius);
+ Destroy(effect, 2f);
+ }
+ }
+
+ protected override void HitCheck()
+ {
+ // 박스 판정 (사각형 직선)
+ Vector3 halfExtents = new Vector3(_data.radius, 1f, _data.radius * 2f);
+ Collider[] hits = Physics.OverlapBox(transform.position, halfExtents, transform.rotation, _data.targetLayer);
+
+ foreach (var hit in hits)
+ {
+ if (!hit.CompareTag("Player")) continue;
+ Debug.Log($"{hit.name} 사각형 범위에 있어 데미지 적용");
+ // TODO: 데미지 로직
+ }
+ }
+
+ private void OnDrawGizmosSelected()
+ {
+ Gizmos.color = Color.red;
+ Vector3 center = transform.position;
+ Vector3 size = new Vector3(_data.radius, 1f, _data.radius * 2f);
+ Gizmos.matrix = Matrix4x4.TRS(center, transform.rotation, Vector3.one);
+ Gizmos.DrawWireCube(Vector3.zero, size);
+ Gizmos.matrix = Matrix4x4.identity;
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/BossPattern/VerticalAoeController.cs.meta b/Assets/Scripts/Character/Enemy/BossPattern/VerticalAoeController.cs.meta
new file mode 100644
index 00000000..9fe09225
--- /dev/null
+++ b/Assets/Scripts/Character/Enemy/BossPattern/VerticalAoeController.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 8eb40ee5f0d943469026d2b6522dbe46
+timeCreated: 1745393484
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyAnimatorStateAttack.cs b/Assets/Scripts/Character/Enemy/EnemyAnimatorStateAttack.cs
deleted file mode 100644
index 91bdc4a1..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyAnimatorStateAttack.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using UnityEngine;
-
-public class EnemyAnimatorStateAttack : StateMachineBehaviour
-{
- // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
- // override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
- // {
- // animator.gameObject.GetComponent().SetState(EnemyState.Trace);
- // }
-
-
-}
diff --git a/Assets/Scripts/Character/Enemy/EnemyAnimatorStateAttack.cs.meta b/Assets/Scripts/Character/Enemy/EnemyAnimatorStateAttack.cs.meta
deleted file mode 100644
index 032dac99..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyAnimatorStateAttack.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: a5765847dbef51e4f9bccde712eeda30
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Scripts/Character/Enemy/EnemyAttackController.cs b/Assets/Scripts/Character/Enemy/EnemyAttackController.cs
deleted file mode 100644
index 543db2f9..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyAttackController.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System.Collections.Generic;
-using UnityEngine;
-
-public class EnemyAttackController : MonoBehaviour
-{
- [Header("각종 전조 오브젝트")]
- [SerializeField] private GameObject verticalWarningArea;
- [SerializeField] private GameObject horizontalWarningArea;
- [SerializeField] private GameObject chariotWarningArea;
- [SerializeField] private GameObject dynamoWarningArea;
-
- // 배열에 담아서 관리
- private List warningAreas;
- private GameObject _activeArea;
-
- private void Awake()
- {
- warningAreas = new List()
- {
- verticalWarningArea,
- horizontalWarningArea,
- chariotWarningArea,
- dynamoWarningArea
- };
- }
-
- // 랜덤 전조 호출
- public void TriggerRandomWarning(Vector3 spawnPosition, Quaternion spawnRotation)
- {
- // 0 ~ Count-1 사이 랜덤 인덱스
- int idx = Random.Range(0, warningAreas.Count);
- GameObject selected = warningAreas[idx];
-
- // 예시: Instantiate 방식으로 화면에 띄우기
- _activeArea = Instantiate(selected, spawnPosition, spawnRotation);
- }
-
- public void DestroyWarningArea()
- {
- Destroy(_activeArea);
- }
-}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyController.cs b/Assets/Scripts/Character/Enemy/EnemyController.cs
index 58534e20..56a57950 100644
--- a/Assets/Scripts/Character/Enemy/EnemyController.cs
+++ b/Assets/Scripts/Character/Enemy/EnemyController.cs
@@ -2,49 +2,46 @@
using UnityEngine;
using UnityEngine.AI;
-public enum EnemyState { None, Idle, Trace, Attack, GetHit, Move, Dead }
+public enum EnemyState { None, Idle, Trace, Attack, Dead }
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Animator))]
-[RequireComponent(typeof(EnemyAttackController))]
public abstract class EnemyController : CharacterBase
{
[Header("AI")]
[SerializeField] private float detectCircleRadius = 10f; // 플레이어 탐지 범위
[SerializeField] private LayerMask targetLayerMask; // 플레이어 레이어 마스크
+ public Transform TraceTargetTransform { get; private set; }
public NavMeshAgent Agent { get; private set; }
public Animator EnemyAnimator { get; private set; }
-
public EnemyState CurrentState {get; private set;}
+ public LayerMask TargetLayerMask => targetLayerMask;
+ public float MoveSpeed => moveSpeed;
+ public bool IsMeleeCombat { get; protected set; }
- public EnemyAttackController EnemyAttackController { get; private set; }
-
- public float WalkSpeed => walkSpeed;
- public float RunSpeed => runSpeed;
-
- public Transform TraceTargetTransform { get; private set; }
-
- [SerializeField] private float walkSpeed = 5;
- [SerializeField] private float runSpeed = 8;
+ // -----
+ // 애니메이션 관련
+ private int _currentAnimationTrigger = -1;
+ // 애니메이션 파라미터 해시값
+ public static readonly int Idle = Animator.StringToHash("Idle");
+ public static readonly int Dead = Animator.StringToHash("Dead");
+ public static readonly int Trace = Animator.StringToHash("Trace");
// -----
// 상태 변수
private EnemyStateIdle _enemyStateIdle;
private EnemyStateTrace _enemyStateTrace;
private EnemyStateAttack _enemyStateAttack;
- private EnemyStateGetHit _enemyStateGetHit;
private EnemyStateDead _enemyStateDead;
- private EnemyStateMove _enemyStateMove;
private Dictionary _enemyStates;
- private void Awake()
+ protected virtual void Awake()
{
EnemyAnimator = GetComponent();
Agent = GetComponent();
- EnemyAttackController = GetComponent();
}
protected override void Start()
@@ -55,24 +52,20 @@ public abstract class EnemyController : CharacterBase
_enemyStateIdle = new EnemyStateIdle();
_enemyStateTrace = new EnemyStateTrace();
_enemyStateAttack = new EnemyStateAttack();
- _enemyStateGetHit = new EnemyStateGetHit();
_enemyStateDead = new EnemyStateDead();
- _enemyStateMove = new EnemyStateMove();
_enemyStates = new Dictionary
{
{ EnemyState.Idle, _enemyStateIdle },
{ EnemyState.Trace, _enemyStateTrace },
{ EnemyState.Attack, _enemyStateAttack },
- { EnemyState.GetHit, _enemyStateGetHit },
{ EnemyState.Dead, _enemyStateDead },
- { EnemyState.Move, _enemyStateMove}
};
SetState(EnemyState.Idle);
}
- private void Update()
+ protected virtual void Update()
{
if (CurrentState != EnemyState.None)
{
@@ -90,6 +83,14 @@ public abstract class EnemyController : CharacterBase
_enemyStates[CurrentState].Enter(this);
}
+
+ public override void Die()
+ {
+ base.Die();
+ // TODO : 사망 후 동작
+
+ }
+
#region 적 탐지
// 일정 반경에 플레이어가 진입하면 플레이어 소리를 감지했다고 판단
@@ -107,5 +108,38 @@ public abstract class EnemyController : CharacterBase
#endregion
+ #region 애니메이션 제어
+
+ // Trigger
+ public void SetAnimation(int hashName)
+ {
+ if (_currentAnimationTrigger != -1)
+ {
+ EnemyAnimator.ResetTrigger(_currentAnimationTrigger);
+ }
+
+ EnemyAnimator.SetTrigger(hashName);
+ _currentAnimationTrigger = hashName;
+ }
+
+ // Bool
+ public void SetAnimation(int hashName, bool value)
+ {
+ EnemyAnimator.SetBool(hashName, value);
+ }
+
+ // Float
+ public void SetAnimation(int hashName, float value)
+ {
+ EnemyAnimator.SetFloat(hashName, value);
+ }
+
+ // Integer
+ public void SetAnimation(int hashName, int value)
+ {
+ EnemyAnimator.SetInteger(hashName, value);
+ }
+
+ #endregion
}
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs
index 6cc865a5..194ce30c 100644
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs
+++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs
@@ -4,65 +4,21 @@ using UnityEngine;
public class EnemyStateAttack : IEnemyState
{
- private static readonly int VertiSlash = Animator.StringToHash("VertiSlash");
- private static readonly int VertiAttack = Animator.StringToHash("VertiAttack");
-
private EnemyController _enemyController;
- private Animator _animator;
- private Coroutine _attackRoutine;
- private EnemyAttackController _enemyAttackController;
- private enum AttackType
- {
- VerticalAttack, // 위에서 아래로 베는 것
- HorizontalAttack, // 옆으로 베는 것
- ChariotAttack, // 원형
- DynamoAttack, // 도넛
- };
- private AttackType _currentAttackType;
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
- _animator = _enemyController.EnemyAnimator;
- _enemyAttackController = _enemyController.EnemyAttackController;
- _animator.SetBool(VertiAttack, true);
- _attackRoutine = _enemyController.StartCoroutine(VerticalAttackSequence());
}
public void Update()
{
- }
- private IEnumerator VerticalAttackSequence()
- {
- // 1. 전조 이펙트 생성
- _enemyAttackController.TriggerRandomWarning(_enemyController.transform.position, _enemyController.transform.rotation);
- // 2. 검을 들어올림
- yield return new WaitForSeconds(3f);
-
- // 3. 대기(전조와 검 들어올리는 애니메이션을 위함)
-
- // 4. 검 휘두르기
- _animator.SetTrigger(VertiSlash);
- _enemyAttackController.DestroyWarningArea();
- // TODO : 5. 공격 판정 발생
-
- yield return new WaitForSeconds(1f);
- // 6. 애니메이션 트리거 종료 -> 애니메이터 상태 머신으로 처리
- _enemyController.SetState(EnemyState.Trace);
}
public void Exit()
{
- if (_attackRoutine != null)
- {
- _enemyController.StopCoroutine(_attackRoutine);
- _attackRoutine = null;
- }
- _animator.SetBool(VertiAttack, false);
- _animator = null;
- _enemyAttackController = null;
_enemyController = null;
}
}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs
index 158b9eab..ba34bb17 100644
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs
+++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs
@@ -5,7 +5,7 @@
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
- _enemyController.EnemyAnimator.SetTrigger("Dead");
+ _enemyController.SetAnimation(EnemyController.Dead);
}
public void Update()
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateGetHit.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateGetHit.cs
deleted file mode 100644
index b4c44e8a..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateGetHit.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-public class EnemyStateGetHit: IEnemyState
-{
- private EnemyController _enemyController;
-
- public void Enter(EnemyController enemyController)
- {
- _enemyController = enemyController;
- }
-
- public void Update()
- {
-
- }
-
- public void Exit()
- {
- _enemyController = null;
- }
-}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateGetHit.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateGetHit.cs.meta
deleted file mode 100644
index e0212137..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateGetHit.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: 7067b1b0eacf490c863a4cb68c290d3a
-timeCreated: 1744799049
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs
index b8714ef6..a0fbbc52 100644
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs
+++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs
@@ -2,13 +2,14 @@
public class EnemyStateIdle: IEnemyState
{
- private static readonly int Idle = Animator.StringToHash("Idle");
+
private EnemyController _enemyController;
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
- _enemyController.EnemyAnimator.SetBool(Idle, true);
+ Debug.Log("## Idle 상태 진입");
+ _enemyController.SetAnimation(EnemyController.Idle, true);
}
public void Update()
@@ -22,7 +23,7 @@ public class EnemyStateIdle: IEnemyState
public void Exit()
{
- _enemyController.EnemyAnimator.SetBool(Idle, false);
+ _enemyController.SetAnimation(EnemyController.Idle, false);
_enemyController = null;
}
}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateMove.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateMove.cs
deleted file mode 100644
index e68bdcd3..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateMove.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-public class EnemyStateMove : IEnemyState
-{
- private EnemyController _enemyController;
-
- public void Enter(EnemyController enemyController)
- {
- _enemyController = enemyController;
- }
-
- public void Update()
- {
-
- }
-
- public void Exit()
- {
- _enemyController = null;
- }
-}
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateMove.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateMove.cs.meta
deleted file mode 100644
index 05ec512c..00000000
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateMove.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: 5abb29c9137942fe95bc66670d8ef521
-timeCreated: 1744799142
\ No newline at end of file
diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs
index ae814987..b301d19a 100644
--- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs
+++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs
@@ -2,9 +2,6 @@
public class EnemyStateTrace : IEnemyState
{
- private static readonly int MoveSpeed = Animator.StringToHash("MoveSpeed");
- private static readonly int Trace = Animator.StringToHash("Trace");
-
private EnemyController _enemyController;
private Transform _detectPlayerTransform;
@@ -14,7 +11,7 @@ public class EnemyStateTrace : IEnemyState
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
-
+ Debug.Log("## Trace 상태 진입");
_detectPlayerTransform = _enemyController.TraceTargetTransform;
if (!_detectPlayerTransform)
{
@@ -28,24 +25,31 @@ public class EnemyStateTrace : IEnemyState
_enemyController.Agent.SetDestination(_detectPlayerTransform.position);
}
- _enemyController.EnemyAnimator.SetBool(Trace, true);
+ _enemyController.SetAnimation(EnemyController.Trace, true);
}
public void Update()
{
- // 일정 주기로 찾은 플레이어의 위치를 갱신해서 갱신된 위치로 이동
- FindTargetPosition();
+ if(_enemyController.IsMeleeCombat) return;
+ if (_enemyController.Agent.enabled != true) return;
PlayerTracking();
if (_enemyController.Agent.remainingDistance <= _enemyController.Agent.stoppingDistance)
{
// TODO: 타겟에 도착함 -> 공격 준비
- _enemyController.SetState(EnemyState.Attack);
+ // _enemyController.SetState(EnemyState.Attack);
}
-
}
+ public void Exit()
+ {
+ _detectPlayerTransform = null;
+ _enemyController.SetAnimation(EnemyController.Trace, false);
+ _enemyController = null;
+ }
+
+ // 일정 주기로 찾은 플레이어의 위치를 갱신해서 갱신된 위치로 이동
private void FindTargetPosition()
{
if (_detectPlayerInCircleWaitTime > MaxDetectPlayerInCircleWaitTime)
@@ -67,26 +71,16 @@ public class EnemyStateTrace : IEnemyState
// 플레이어를 추적하는 속도를 제어하는 함수
private void PlayerTracking()
{
+ FindTargetPosition();
+
float distance = (_detectPlayerTransform.position - _enemyController.transform.position).magnitude;
- if (distance > 5f)
- {
- // 먼 거리: 뛰기
- _enemyController.Agent.speed = _enemyController.RunSpeed;
- _enemyController.Agent.acceleration = 20f;
- _enemyController.Agent.angularSpeed = 270f;
- // _enemyController.EnemyAnimator.SetFloat("MoveSpeed", 1f); // 애니메이션도 Run으로
-
- // NavMeshAgent 회전에 맡기기
- _enemyController.Agent.updateRotation = true;
- }
- else if (distance > 2f)
+ if (distance > 2f)
{
// 가까운 거리: 걷기
- _enemyController.Agent.speed = _enemyController.WalkSpeed;
+ _enemyController.Agent.speed = _enemyController.MoveSpeed;
_enemyController.Agent.acceleration = 8f;
_enemyController.Agent.angularSpeed = 720f;
- // _enemyController.EnemyAnimator.SetFloat("MoveSpeed", 0.4f); // Walk 애니메이션
_enemyController.Agent.updateRotation = true;
}
@@ -107,23 +101,7 @@ public class EnemyStateTrace : IEnemyState
Time.deltaTime * 10f // 회전 속도
);
}
-
- // _enemyController.Agent.angularSpeed = 1080f;
- // _enemyController.Agent.acceleration = 999f;
-
- // _enemyController.EnemyAnimator.SetFloat("MoveSpeed", 0f);
}
-
- // 실제 속도 기반으로 애니메이션 제어
- float currentSpeed = _enemyController.Agent.velocity.magnitude;
- _enemyController.EnemyAnimator.SetFloat(MoveSpeed, currentSpeed);
- }
-
- public void Exit()
- {
- _detectPlayerTransform = null;
- _enemyController.EnemyAnimator.SetBool(Trace, false);
- _enemyController = null;
}
}
diff --git a/Assets/Scripts/Character/Enemy/PldDogController.cs b/Assets/Scripts/Character/Enemy/PldDogController.cs
index 1a9eb28d..2655b9e8 100644
--- a/Assets/Scripts/Character/Enemy/PldDogController.cs
+++ b/Assets/Scripts/Character/Enemy/PldDogController.cs
@@ -1,7 +1,208 @@
using System;
+using System.Collections;
+using System.Collections.Generic;
+using Unity.VisualScripting;
using UnityEngine;
+using UnityEngine.Serialization;
+using Random = UnityEngine.Random;
public class PldDogController : EnemyController
{
+ private static readonly int WindUp = Animator.StringToHash("WindUp");
+ private static readonly int Slash = Animator.StringToHash("Slash");
+ private static readonly int BoomShot = Animator.StringToHash("BoomShot");
+ [Header("공격 패턴 관련")]
+ [SerializeField] private float patternInterval = 3f;
+ [SerializeField] private float meleeRange = 2f;
+ [SerializeField] private float bombTriggerDelay = 1.5f;
+
+ [Header("폭탄 패턴 설정")]
+ [SerializeField] private int bombCount = 1;
+ [SerializeField] private Vector3 bombScale = new Vector3(5f, 5f, 5f);
+
+ [Header("각종 데미지 이펙트 세트")]
+ [SerializeField] private GameObject chariotSlashWarning;
+ [SerializeField] private GameObject chariotSlash;
+ [SerializeField] private GameObject boomExplosion;
+
+ [Space(10)]
+ [SerializeField] private GameObject verticalWarning;
+ [SerializeField] private GameObject verticalSlash;
+
+ [Space(10)]
+ [SerializeField] private GameObject horizontalWarning;
+ [SerializeField] private GameObject horizontalSlash;
+
+ private float _patternTimer = 0f;
+ private int _currentPatternIndex = 0;
+ private bool _isPatternRunning = false;
+ private bool _isFirstAttack = true;
+
+ private List _patternActions;
+
+ protected override void Awake()
+ {
+ base.Awake();
+
+ _patternActions = new List
+ {
+ ChariotSlashPattern,
+ VerticalSlashPattern,
+ HorizontalSlashPattern
+ };
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (CurrentState != EnemyState.Trace || _isPatternRunning)
+ return;
+
+ float distanceToPlayer = Vector3.Distance(transform.position, TraceTargetTransform.position);
+
+ if (distanceToPlayer <= meleeRange) // 근접 범위
+ {
+ if (!Agent.isStopped) Agent.isStopped = true;
+ _patternTimer += Time.deltaTime;
+
+ if (!_isPatternRunning && (_isFirstAttack || _patternTimer >= patternInterval))
+ {
+ ExecutePattern(_currentPatternIndex);
+
+ _isFirstAttack = false;
+ }
+ }
+ else
+ {
+ if (Agent.isStopped) Agent.isStopped = false;
+ Agent.SetDestination(TraceTargetTransform.position);
+ _patternTimer += Time.deltaTime;
+
+ if (!_isPatternRunning && _patternTimer >= patternInterval)
+ {
+ BombThrowPattern();
+ }
+ }
+ }
+
+ private void ExecutePattern(int patternIndex)
+ {
+ _isPatternRunning = true;
+ Agent.isStopped = true;
+ IsMeleeCombat = true;
+
+ _patternActions[_currentPatternIndex]?.Invoke();
+
+ _currentPatternIndex = (_currentPatternIndex + 1) % _patternActions.Count; // 패턴 순환
+ }
+
+ // 순환 패턴과 별개로 동작하는 특수 패턴
+ private void BombThrowPattern()
+ {
+ Debug.Log("BombThrowPattern: 보스가 폭탄을 던집니다.");
+ SetAnimation(BoomShot);
+ _isPatternRunning = true;
+ Agent.isStopped = true;
+
+ for (int i = 0; i < bombCount; i++)
+ {
+ Vector3 targetPos = TraceTargetTransform.position;
+ targetPos.y = 0.1f; // 지면에 맞춤
+
+ var warning = Instantiate(chariotSlashWarning, targetPos, Quaternion.identity);
+ warning.transform.localScale = bombScale;
+ var aoe = warning.GetComponent();
+
+ var effectData = new DamageEffectData
+ {
+ damage = (int)attackPower,
+ radius = bombScale.x,
+ delay = bombTriggerDelay,
+ targetLayer = TargetLayerMask,
+ explosionEffectPrefab = boomExplosion
+ };
+
+ aoe.SetEffect(effectData, null, PatternClear);
+ }
+ }
+
+ private void ChariotSlashPattern()
+ {
+ Debug.Log("ChariotSlashPattern: 보스가 차지 슬래시를 사용합니다.");
+ WindUpAnimation();
+
+ var warning = Instantiate(chariotSlashWarning, transform.position, Quaternion.identity)
+ .GetComponent();
+
+ var effectData = new DamageEffectData
+ {
+ damage = (int)attackPower,
+ radius = 7.5f,
+ delay = 2.5f,
+ targetLayer = TargetLayerMask,
+ explosionEffectPrefab = chariotSlash
+ };
+
+ warning.SetEffect(effectData, SlashAnimationPlay, PatternClear);
+ }
+
+ private void VerticalSlashPattern()
+ {
+ Debug.Log("VerticalSlashPattern: 보스가 수직 슬래시를 사용합니다.");
+ WindUpAnimation();
+
+ var warning = Instantiate(verticalWarning, transform.position, transform.rotation)
+ .GetComponent();
+
+ var effectData = new DamageEffectData
+ {
+ damage = (int)attackPower,
+ radius = 5f,
+ delay = 2f,
+ targetLayer = TargetLayerMask,
+ explosionEffectPrefab = verticalSlash
+ };
+
+ warning.SetEffect(effectData, SlashAnimationPlay, PatternClear);
+ }
+
+ private void HorizontalSlashPattern()
+ {
+ Debug.Log("HorizontalSlashPattern: 보스가 횡적 슬래시를 사용합니다.");
+ WindUpAnimation();
+
+ var warning = Instantiate(horizontalWarning, transform.position, transform.rotation)
+ .GetComponent();
+
+ var effectData = new DamageEffectData
+ {
+ damage = (int)attackPower,
+ radius = 15f,
+ delay = 2f,
+ targetLayer = TargetLayerMask,
+ explosionEffectPrefab = horizontalSlash
+ };
+
+ warning.SetEffect(effectData, SlashAnimationPlay, PatternClear);
+ }
+
+ private void WindUpAnimation()
+ {
+ SetAnimation(WindUp);
+ }
+
+ private void SlashAnimationPlay()
+ {
+ SetAnimation(Slash);
+ }
+
+ private void PatternClear()
+ {
+ _isPatternRunning = false;
+ IsMeleeCombat = false;
+ _patternTimer = 0f;
+ Agent.isStopped = false;
+ }
}