diff --git a/Assets/Editor/EnemyControllerEditor.cs b/Assets/Editor/EnemyControllerEditor.cs index 82dc98de..a6cb20f2 100644 --- a/Assets/Editor/EnemyControllerEditor.cs +++ b/Assets/Editor/EnemyControllerEditor.cs @@ -27,9 +27,6 @@ public class EnemyControllerEditor : Editor case EnemyState.Trace: GUI.backgroundColor = new Color(1, 0, 1, 1f); break; - case EnemyState.Attack: - GUI.backgroundColor = new Color(1, 1, 0, 1f); - break; case EnemyState.Dead: GUI.backgroundColor = new Color(1, 0, 0, 1f); break; @@ -49,10 +46,6 @@ public class EnemyControllerEditor : Editor EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Idle")) enemyController.SetState(EnemyState.Idle); if (GUILayout.Button("Trace")) enemyController.SetState(EnemyState.Trace); - EditorGUILayout.EndHorizontal(); - - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Attack")) enemyController.SetState(EnemyState.Attack); if (GUILayout.Button("Dead")) enemyController.SetState(EnemyState.Dead); EditorGUILayout.EndHorizontal(); } diff --git a/Assets/JYY/Animator/Dummy Monster.controller b/Assets/JYY/Animator/Dummy Monster.controller new file mode 100644 index 00000000..de7d8664 --- /dev/null +++ b/Assets/JYY/Animator/Dummy Monster.controller @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ca1c24b27ef486457ebafc23ce2f6ed321451f9aa9d234bb264466b3f12f15b +size 1347 diff --git a/Assets/JYY/Animator/Dummy Monster.controller.meta b/Assets/JYY/Animator/Dummy Monster.controller.meta new file mode 100644 index 00000000..7e707a03 --- /dev/null +++ b/Assets/JYY/Animator/Dummy Monster.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cb4d2ce283530414f92984caccad61a0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JYY/Animator/PldDogControl.controller b/Assets/JYY/Animator/PldDogControl.controller index 7b80e503..9a22018c 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:9473c357cb74d4228523205a76d0a1a1cc71d82baf736270906c82a171efe7e6 -size 16154 +oid sha256:7c8e0126546f60a0df64adf8fb366d479da5eb832ec0453ea51dfc7c731e2084 +size 17507 diff --git a/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab.meta b/Assets/JYY/Materials/Dummy.meta similarity index 57% rename from Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab.meta rename to Assets/JYY/Materials/Dummy.meta index 5ba3ecc5..90a6eb10 100644 --- a/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab.meta +++ b/Assets/JYY/Materials/Dummy.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 -guid: 3f431e991bd65014c833e89305ddd5e3 -PrefabImporter: +guid: 81ad24bdbd6cad44990b4f077f0687e7 +folderAsset: yes +DefaultImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/JYY/Materials/Dummy/Dummy Monster.mat b/Assets/JYY/Materials/Dummy/Dummy Monster.mat new file mode 100644 index 00000000..bcf5ec30 --- /dev/null +++ b/Assets/JYY/Materials/Dummy/Dummy Monster.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84566d1cced96b3b39f9d3f479b93cba504318e15dccc44e97a8e742ed9aadac +size 3661 diff --git a/Assets/JYY/Materials/Dummy/Dummy Monster.mat.meta b/Assets/JYY/Materials/Dummy/Dummy Monster.mat.meta new file mode 100644 index 00000000..c8b7fb71 --- /dev/null +++ b/Assets/JYY/Materials/Dummy/Dummy Monster.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9a8690b5dbb7c5643896a7d881a8fd6f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JYY/Materials/Dummy/Dummy Player.mat b/Assets/JYY/Materials/Dummy/Dummy Player.mat new file mode 100644 index 00000000..e2b75a45 --- /dev/null +++ b/Assets/JYY/Materials/Dummy/Dummy Player.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18bf8ebd5397569f2261bb288c087b0c9dd7e0c9c4edcd4ef7e97a38ed2a002d +size 6700 diff --git a/Assets/JYY/Materials/Dummy/Dummy Player.mat.meta b/Assets/JYY/Materials/Dummy/Dummy Player.mat.meta new file mode 100644 index 00000000..8db50417 --- /dev/null +++ b/Assets/JYY/Materials/Dummy/Dummy Player.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc5cecc864a5b0c49b266cec5aaec666 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JYY/Prefabs/AoE Indicator.meta b/Assets/JYY/Prefabs/AoE Indicator.meta new file mode 100644 index 00000000..6f952565 --- /dev/null +++ b/Assets/JYY/Prefabs/AoE Indicator.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2dbfaa22c1aa28242a4e80ed518bfae2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab b/Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorDynamo.prefab similarity index 100% rename from Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab rename to Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorDynamo.prefab diff --git a/Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorDynamo.prefab.meta similarity index 100% rename from Assets/JYY/Prefabs/AOEIndicatorDynamo.prefab.meta rename to Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorDynamo.prefab.meta diff --git a/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab b/Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorHorizontal.prefab similarity index 100% rename from Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab rename to Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorHorizontal.prefab diff --git a/Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorHorizontal.prefab.meta similarity index 100% rename from Assets/JYY/Prefabs/AOEIndicatorHorizontal.prefab.meta rename to Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorHorizontal.prefab.meta diff --git a/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab b/Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorVertical.prefab similarity index 100% rename from Assets/JYY/Prefabs/AOEIndicatorVertical.prefab rename to Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorVertical.prefab diff --git a/Assets/JYY/Prefabs/AOEIndicatorVertical.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorVertical.prefab.meta similarity index 100% rename from Assets/JYY/Prefabs/AOEIndicatorVertical.prefab.meta rename to Assets/JYY/Prefabs/AoE Indicator/AOEIndicatorVertical.prefab.meta diff --git a/Assets/JYY/Prefabs/AoE Indicator Chariot.prefab b/Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Chariot.prefab similarity index 100% rename from Assets/JYY/Prefabs/AoE Indicator Chariot.prefab rename to Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Chariot.prefab diff --git a/Assets/JYY/Prefabs/AoE Indicator Chariot.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Chariot.prefab.meta similarity index 100% rename from Assets/JYY/Prefabs/AoE Indicator Chariot.prefab.meta rename to Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Chariot.prefab.meta diff --git a/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab b/Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Horizontal.prefab similarity index 100% rename from Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab rename to Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Horizontal.prefab diff --git a/Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Horizontal.prefab.meta similarity index 100% rename from Assets/JYY/Prefabs/AoE Indicator Horizontal.prefab.meta rename to Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Horizontal.prefab.meta diff --git a/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab b/Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Vertical.prefab similarity index 100% rename from Assets/JYY/Prefabs/AoE Indicator Vertical.prefab rename to Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Vertical.prefab diff --git a/Assets/JYY/Prefabs/AoE Indicator Vertical.prefab.meta b/Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Vertical.prefab.meta similarity index 100% rename from Assets/JYY/Prefabs/AoE Indicator Vertical.prefab.meta rename to Assets/JYY/Prefabs/AoE Indicator/AoE Indicator Vertical.prefab.meta diff --git a/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab b/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab deleted file mode 100644 index 995bcd81..00000000 --- a/Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0d42386e12ec2eec2385f13fdcd2558718c9150245a834d5a667060f750b1ced -size 3100 diff --git a/Assets/JYY/Prefabs/[Enemy] PldDog.prefab b/Assets/JYY/Prefabs/[Enemy] PldDog.prefab index 8b998d43..9eb356ef 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:a4cedd199100ba2d66a0dfe22b6ab902677fcc6485b02d0553115d0e012b3c97 -size 79510 +oid sha256:fa57e55a6b7dc452a770a0a0ddb528ffa765818ec608bcb60f14e4e984a18e59 +size 79971 diff --git a/Assets/JYY/Scenes/MonsterTest.unity b/Assets/JYY/Scenes/MonsterTest.unity index f315080d..d772a68e 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:70e2e15667c9821fdb140d6ca8987d4caf3436e36abc139ba9da1192a5428331 -size 21018 +oid sha256:efc792ecb073a66263abf936bd751584b41224bde07c7f02418d10223d0c07f4 +size 22331 diff --git a/Assets/Scripts/Character/Enemy/CasterDemonController.cs b/Assets/Scripts/Character/Enemy/CasterDemonController.cs new file mode 100644 index 00000000..ad492597 --- /dev/null +++ b/Assets/Scripts/Character/Enemy/CasterDemonController.cs @@ -0,0 +1,19 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class CasterDemonController : EnemyController +{ + + public override void BattleSequence() + { + // TODO : 배틀 중일 때 루프 + Debug.Log("## 몬스터의 교전 행동 루프"); + } + + + public override void OnCannotFleeBehaviour() + { + Debug.Log("## 몬스터가 막다른 길에 몰려 뭔가 함"); + } +} diff --git a/Assets/Scripts/Character/Enemy/CasterDemonController.cs.meta b/Assets/Scripts/Character/Enemy/CasterDemonController.cs.meta new file mode 100644 index 00000000..88b08083 --- /dev/null +++ b/Assets/Scripts/Character/Enemy/CasterDemonController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79bc1ad21773bcf4e982d5fc7a93887b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Character/Enemy/EnemyController.cs b/Assets/Scripts/Character/Enemy/EnemyController.cs index 07f72e13..9883b5db 100644 --- a/Assets/Scripts/Character/Enemy/EnemyController.cs +++ b/Assets/Scripts/Character/Enemy/EnemyController.cs @@ -1,8 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; -public enum EnemyState { None, Idle, Trace, Attack, Dead } +public enum EnemyState { None, Idle, Trace, Dead, Flee} +public enum MonsterType { Melee, Caster, Ranged } [RequireComponent(typeof(NavMeshAgent))] [RequireComponent(typeof(Animator))] @@ -11,10 +13,12 @@ public abstract class EnemyController : CharacterBase [Header("AI")] [SerializeField] private float detectCircleRadius = 10f; // 플레이어 탐지 범위 [SerializeField] private LayerMask targetLayerMask; // 플레이어 레이어 마스크 + [SerializeField] private MonsterType monsterType; + public MonsterType MonsterType => monsterType; public Transform TraceTargetTransform { get; private set; } public NavMeshAgent Agent { get; private set; } - public Animator EnemyAnimator { get; private set; } + private Animator EnemyAnimator { get; set; } public EnemyState CurrentState {get; private set;} public LayerMask TargetLayerMask => targetLayerMask; public float MoveSpeed => moveSpeed; @@ -31,10 +35,14 @@ public abstract class EnemyController : CharacterBase // ----- // 상태 변수 + // Commons private EnemyStateIdle _enemyStateIdle; - private EnemyStateTrace _enemyStateTrace; - private EnemyStateAttack _enemyStateAttack; private EnemyStateDead _enemyStateDead; + // Melee + private EnemyStateTrace _enemyStateTrace; + // Caster + private EnemyStateFlee _enemyStateFlee; + private Dictionary _enemyStates; @@ -49,18 +57,34 @@ public abstract class EnemyController : CharacterBase base.Start(); // 상태 객체 생성 + // Commons _enemyStateIdle = new EnemyStateIdle(); - _enemyStateTrace = new EnemyStateTrace(); - _enemyStateAttack = new EnemyStateAttack(); _enemyStateDead = new EnemyStateDead(); - _enemyStates = new Dictionary + switch (MonsterType) { - { EnemyState.Idle, _enemyStateIdle }, - { EnemyState.Trace, _enemyStateTrace }, - { EnemyState.Attack, _enemyStateAttack }, - { EnemyState.Dead, _enemyStateDead }, - }; + case MonsterType.Melee: + _enemyStateTrace = new EnemyStateTrace(); + _enemyStates = new Dictionary + { + { EnemyState.Idle, _enemyStateIdle }, + { EnemyState.Trace, _enemyStateTrace }, + { EnemyState.Dead, _enemyStateDead }, + }; + break; + case MonsterType.Caster: + _enemyStateFlee = new EnemyStateFlee(); + _enemyStates = new Dictionary + { + { EnemyState.Idle, _enemyStateIdle }, + { EnemyState.Flee, _enemyStateFlee }, + { EnemyState.Dead, _enemyStateDead }, + }; + break; + case MonsterType.Ranged: + break; + } + SetState(EnemyState.Idle); } @@ -84,6 +108,24 @@ public abstract class EnemyController : CharacterBase } + #region 몬스터의 행동 패턴 위임 + + // 전략 패턴과 템플릿 메서드 패턴을 활용 + public virtual void BattleSequence() + { + // 이 메서드는 자식 요소에서 오버라이드하여 구현합니다. + Debug.LogWarning("BattleSequence가 구현되지 않음 : BattleSequence()를 오버라이드하여 구현하십시오."); + } + + // 도망치며 싸우는 몬스터가 도망칠 곳이 없을때 취할 행동 + public virtual void OnCannotFleeBehaviour() + { + Debug.LogWarning("OnCannotFleeBehaviour가 구현되지 않음 : OnCannotFleeBehaviour() 오버라이드하여 구현하십시오."); + } + + #endregion + + public override void Die() { base.Die(); @@ -106,6 +148,12 @@ public abstract class EnemyController : CharacterBase return null; } + private void OnDrawGizmos() + { + Gizmos.color = Color.red; + Gizmos.DrawWireSphere(transform.position, detectCircleRadius); + } + #endregion #region 애니메이션 제어 diff --git a/Assets/Scripts/Character/Enemy/EnemyState/Caster.meta b/Assets/Scripts/Character/Enemy/EnemyState/Caster.meta new file mode 100644 index 00000000..9a5dd5bc --- /dev/null +++ b/Assets/Scripts/Character/Enemy/EnemyState/Caster.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 06fb9eac62a34336b6023cc088be367d +timeCreated: 1745554862 \ No newline at end of file diff --git a/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs b/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs new file mode 100644 index 00000000..9445ab69 --- /dev/null +++ b/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs @@ -0,0 +1,109 @@ +using UnityEngine; +using UnityEngine.AI; + +public class EnemyStateFlee :IEnemyState +{ + private EnemyController _enemyController; + private Transform _playerTransform; + private float _fleeDistance = 5f; // 도망치는 거리 + private float _attackRange = 7f; // 공격 범위 + + // 막다른길 검사용 + private Vector3 _lastPosition; + private float _stuckTimer = 0f; + private const float StuckThresholdTime = 1f; // 1초 동안 거의 못 움직이면 막힌 걸로 간주 + private const float StuckMoveThreshold = 0.1f; // 이내 이동은 “제자리”로 본다 + + public void Enter(EnemyController enemyController) + { + _enemyController = enemyController; + Debug.Log("## Flee 상태 진입"); + + _playerTransform = _enemyController.TraceTargetTransform; + _lastPosition = _enemyController.transform.position; + _stuckTimer = 0f; + + + } + + public void Update() + { + if (!_playerTransform) + { + _enemyController.SetState(EnemyState.Idle); + return; + } + + FindPositionFlee(); + + // 막힘 감지 (실제 이동 체크) + CheckPath(); + + _lastPosition = _enemyController.transform.position; + } + + private void CheckPath() + { + float distance = Vector3.Distance(_enemyController.transform.position, _playerTransform.position); + if (distance < StuckMoveThreshold) + { + _stuckTimer += Time.deltaTime; + if (_stuckTimer >= StuckThresholdTime) + { + // 막다른 길임 : 대체 행동 실행 + HandleDeadEnd(); + _stuckTimer = 0f; + } + } + else + { + // 정상적인 길: 배틀 루프 실행 + _enemyController.BattleSequence(); + _stuckTimer = 0f; + } + } + + private void FindPositionFlee() + { + // 1) 목표 도망 위치 계산 + Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized; + Vector3 fleeTarget = _enemyController.transform.position + fleeDirection * _fleeDistance; + + // 2) 경로 계산해 보기 + NavMeshPath path = new NavMeshPath(); + _enemyController.Agent.CalculatePath(fleeTarget, path); + + if (path.status == NavMeshPathStatus.PathComplete) + { + // 제대로 도망갈 수 있으면 목적지 설정 + _enemyController.Agent.SetDestination(fleeTarget); + } + else + { + // 막다른 길임 : 대체 행동 실행 + HandleDeadEnd(); + } + } + + private void HandleDeadEnd() + { + // 무작위 도망 지점 샘플링 시도 + Vector3 randomDirection = Random.insideUnitSphere * (_fleeDistance * 2); + randomDirection += _playerTransform.position; + + if (NavMesh.SamplePosition(randomDirection, out var hit, (_fleeDistance * 2), NavMesh.AllAreas)) + { + _enemyController.Agent.SetDestination(hit.position); + return; + } + + // 대체 경로도 찾을 수 없는 경우 + _enemyController.OnCannotFleeBehaviour(); + } + + public void Exit() + { + _playerTransform = null; + _enemyController = null; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs.meta new file mode 100644 index 00000000..9f798685 --- /dev/null +++ b/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52fff5e2310f42608e3e3c5b45dcae38 +timeCreated: 1745554266 \ No newline at end of file diff --git a/Assets/Scripts/Character/Enemy/EnemyState/Commons.meta b/Assets/Scripts/Character/Enemy/EnemyState/Commons.meta new file mode 100644 index 00000000..d4b32419 --- /dev/null +++ b/Assets/Scripts/Character/Enemy/EnemyState/Commons.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 452917766030468e87209330ca1b410e +timeCreated: 1745554696 \ No newline at end of file diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs b/Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateDead.cs similarity index 100% rename from Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs rename to Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateDead.cs diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateDead.cs.meta similarity index 100% rename from Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs.meta rename to Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateDead.cs.meta diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs b/Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateIdle.cs similarity index 58% rename from Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs rename to Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateIdle.cs index a0fbbc52..d23de9c8 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateIdle.cs @@ -1,8 +1,8 @@ -using UnityEngine; +using System; +using UnityEngine; public class EnemyStateIdle: IEnemyState { - private EnemyController _enemyController; public void Enter(EnemyController enemyController) @@ -17,7 +17,17 @@ public class EnemyStateIdle: IEnemyState var detectPlayerTransform = _enemyController.DetectPlayerInCircle(); if (detectPlayerTransform) { - _enemyController.SetState(EnemyState.Trace); + switch (_enemyController.MonsterType) + { + case MonsterType.Melee: + _enemyController.SetState(EnemyState.Trace); + break; + case MonsterType.Caster: + _enemyController.SetState(EnemyState.Flee); + break; + case MonsterType.Ranged: + break; + } } } diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateIdle.cs.meta similarity index 100% rename from Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs.meta rename to Assets/Scripts/Character/Enemy/EnemyState/Commons/EnemyStateIdle.cs.meta diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs deleted file mode 100644 index 194ce30c..00000000 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -public class EnemyStateAttack : 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/EnemyStateAttack.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs.meta deleted file mode 100644 index 6116ce6e..00000000 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 29b87c92807e4f6b94c8a08ccc510321 -timeCreated: 1744799701 \ No newline at end of file diff --git a/Assets/Scripts/Character/Enemy/EnemyState/Melee.meta b/Assets/Scripts/Character/Enemy/EnemyState/Melee.meta new file mode 100644 index 00000000..0df3aa26 --- /dev/null +++ b/Assets/Scripts/Character/Enemy/EnemyState/Melee.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 64b8e3ece30b427eb71a9b6e33292292 +timeCreated: 1745554748 \ No newline at end of file diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs b/Assets/Scripts/Character/Enemy/EnemyState/Melee/EnemyStateTrace.cs similarity index 90% rename from Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs rename to Assets/Scripts/Character/Enemy/EnemyState/Melee/EnemyStateTrace.cs index b301d19a..ba2c7f76 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/Melee/EnemyStateTrace.cs @@ -30,16 +30,13 @@ public class EnemyStateTrace : IEnemyState public void Update() { - if(_enemyController.IsMeleeCombat) return; - if (_enemyController.Agent.enabled != true) return; + if (_enemyController.Agent.enabled != true || + _enemyController.IsMeleeCombat) return; PlayerTracking(); - if (_enemyController.Agent.remainingDistance <= _enemyController.Agent.stoppingDistance) - { - // TODO: 타겟에 도착함 -> 공격 준비 - // _enemyController.SetState(EnemyState.Attack); - } + // 전투 패턴은 몬스터 객체에게 위임 + _enemyController.BattleSequence(); } public void Exit() diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs.meta b/Assets/Scripts/Character/Enemy/EnemyState/Melee/EnemyStateTrace.cs.meta similarity index 100% rename from Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs.meta rename to Assets/Scripts/Character/Enemy/EnemyState/Melee/EnemyStateTrace.cs.meta diff --git a/Assets/Scripts/Character/Enemy/PldDogController.cs b/Assets/Scripts/Character/Enemy/PldDogController.cs index 2655b9e8..c6cb613b 100644 --- a/Assets/Scripts/Character/Enemy/PldDogController.cs +++ b/Assets/Scripts/Character/Enemy/PldDogController.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Serialization; @@ -8,6 +9,8 @@ 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"); @@ -35,7 +38,7 @@ public class PldDogController : EnemyController [SerializeField] private GameObject horizontalSlash; private float _patternTimer = 0f; - private int _currentPatternIndex = 0; + private int _lastPatternIndex = -1; private bool _isPatternRunning = false; private bool _isFirstAttack = true; @@ -53,23 +56,20 @@ public class PldDogController : EnemyController }; } - protected override void Update() + public override void BattleSequence() { - base.Update(); - - if (CurrentState != EnemyState.Trace || _isPatternRunning) - return; + _patternTimer += Time.deltaTime; + if (_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); + ExecutePattern(); _isFirstAttack = false; } @@ -78,24 +78,31 @@ public class PldDogController : EnemyController { if (Agent.isStopped) Agent.isStopped = false; Agent.SetDestination(TraceTargetTransform.position); - _patternTimer += Time.deltaTime; if (!_isPatternRunning && _patternTimer >= patternInterval) { + Debug.Log("## 폭탄 던질 조건 만족"); BombThrowPattern(); } } } - private void ExecutePattern(int patternIndex) + private void ExecutePattern() { _isPatternRunning = true; Agent.isStopped = true; IsMeleeCombat = true; - _patternActions[_currentPatternIndex]?.Invoke(); + var available = Enumerable + .Range(0, _patternActions.Count) + .Where(i => i != _lastPatternIndex) + .ToList(); - _currentPatternIndex = (_currentPatternIndex + 1) % _patternActions.Count; // 패턴 순환 + int nextIndex = available[Random.Range(0, available.Count)]; + + _patternActions[nextIndex]?.Invoke(); + + _lastPatternIndex = nextIndex; } // 순환 패턴과 별개로 동작하는 특수 패턴