From b6e0458350aa6ea3be379a6dea06db3a85feaf31 Mon Sep 17 00:00:00 2001 From: fiore Date: Tue, 22 Apr 2025 18:02:56 +0900 Subject: [PATCH] =?UTF-8?q?DEG-41=20=EA=B7=BC=EC=A0=91=20=EB=B2=94?= =?UTF-8?q?=EC=9C=84=ED=8C=A8=ED=84=B4,=20=EA=B1=B0=EB=A6=AC=EA=B0=80=20?= =?UTF-8?q?=EB=A9=80=EB=A9=B4=20=EC=9B=90=EA=B1=B0=EB=A6=AC=20=EA=B3=B5?= =?UTF-8?q?=EA=B2=A9=20=ED=8C=A8=ED=84=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/JYY/Animator/PldDogControl.controller | 4 +- Assets/JYY/Scenes/MonsterTest.unity | 4 +- .../Scripts/Character/Enemy/BossPattern.meta | 3 + .../{ => BossPattern}/ChariotAoeController.cs | 18 ++- .../ChariotAoeController.cs.meta | 0 .../Character/Enemy/EnemyController.cs | 29 +--- .../Enemy/EnemyState/EnemyStateAttack.cs | 30 ---- .../Enemy/EnemyState/EnemyStateDead.cs | 1 - .../Enemy/EnemyState/EnemyStateIdle.cs | 6 +- .../Enemy/EnemyState/EnemyStateTrace.cs | 25 +--- .../Character/Enemy/PldDogController.cs | 130 ++++++++++++++++-- 11 files changed, 142 insertions(+), 108 deletions(-) create mode 100644 Assets/Scripts/Character/Enemy/BossPattern.meta rename Assets/Scripts/Character/Enemy/{ => BossPattern}/ChariotAoeController.cs (84%) rename Assets/Scripts/Character/Enemy/{ => BossPattern}/ChariotAoeController.cs.meta (100%) diff --git a/Assets/JYY/Animator/PldDogControl.controller b/Assets/JYY/Animator/PldDogControl.controller index a67e40bf..9d61f13d 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:481922b21d2de476145ad4fefaccad66d344052ffc0a2808e577b717e59be4e9 +size 18696 diff --git a/Assets/JYY/Scenes/MonsterTest.unity b/Assets/JYY/Scenes/MonsterTest.unity index 471eda89..9e0ad0dc 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:ccea4dffb67fe759672ab88a8aae903251498785bbe1d83673c2e0a7a89ace8f -size 19724 +oid sha256:6a0de3e23ef1211a5b26d9fb80ba8911d8000a07e40a8b67cf4b33cb106539e6 +size 19722 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/ChariotAoeController.cs b/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs similarity index 84% rename from Assets/Scripts/Character/Enemy/ChariotAoeController.cs rename to Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs index f38a905f..c433f081 100644 --- a/Assets/Scripts/Character/Enemy/ChariotAoeController.cs +++ b/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs @@ -17,15 +17,17 @@ public struct DamageEffectData public class ChariotAoeController : MonoBehaviour { - private DamageEffectData _data; [SerializeField] private GameObject warningEffectInstance; - private EnemyController _enemyController; + private DamageEffectData _data; + private Action _destroyAction; + private Action _slashAction; - public void SetEffect(DamageEffectData data, EnemyController enemyController) + public void SetEffect(DamageEffectData data, Action slashAction, Action destroyAction) { _data = data; - _enemyController = enemyController; + _slashAction = slashAction; + _destroyAction = destroyAction; ShowWarningEffect(); Invoke(nameof(Explode), _data.delay); @@ -45,8 +47,11 @@ public class ChariotAoeController : MonoBehaviour // 공격 전조 제거 warningEffectInstance.SetActive(false); + // 공격 애니메이션 실행 + _slashAction.Invoke(); + effect.transform.localScale = new Vector3(_data.radius, _data.radius, _data.radius); - _enemyController.SetAttackTrigger(true); + // 폭발 반경 내의 모든 콜라이더 가져오기 Collider[] hitColliders = Physics.OverlapSphere(transform.position, _data.radius, _data.targetLayer); foreach (Collider hit in hitColliders) @@ -69,8 +74,7 @@ public class ChariotAoeController : MonoBehaviour private void OnDestroy() { - _enemyController.SetAttackTrigger(false); - _enemyController = null; + _destroyAction.Invoke(); } private void OnDrawGizmosSelected() diff --git a/Assets/Scripts/Character/Enemy/ChariotAoeController.cs.meta b/Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs.meta similarity index 100% rename from Assets/Scripts/Character/Enemy/ChariotAoeController.cs.meta rename to Assets/Scripts/Character/Enemy/BossPattern/ChariotAoeController.cs.meta diff --git a/Assets/Scripts/Character/Enemy/EnemyController.cs b/Assets/Scripts/Character/Enemy/EnemyController.cs index d93966fa..0cdca95a 100644 --- a/Assets/Scripts/Character/Enemy/EnemyController.cs +++ b/Assets/Scripts/Character/Enemy/EnemyController.cs @@ -12,26 +12,12 @@ public abstract class EnemyController : CharacterBase [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 bool AttackTrigger { get; protected set; } - - public bool IsInBattle { get => _isInBattle; protected set=> _isInBattle = value; } - private bool _isInBattle = false; - - - public bool IsBoss { get => _isBoss; protected set => _isBoss = value; } - private bool _isBoss = false; - public float WalkSpeed => walkSpeed; - public float RunSpeed => runSpeed; - - public Transform TraceTargetTransform { get; private set; } - - [Header("이동 능력")] - [SerializeField] private float walkSpeed = 5; - [SerializeField] private float runSpeed = 8; + public float MoveSpeed => moveSpeed; // ----- // 상태 변수 @@ -40,7 +26,6 @@ public abstract class EnemyController : CharacterBase private EnemyStateAttack _enemyStateAttack; private EnemyStateDead _enemyStateDead; - private Dictionary _enemyStates; protected virtual void Awake() @@ -88,11 +73,6 @@ public abstract class EnemyController : CharacterBase _enemyStates[CurrentState].Enter(this); } - public void SetInBattle(bool battle) - { - _isInBattle = battle; - } - public override void Die() { @@ -101,11 +81,6 @@ public abstract class EnemyController : CharacterBase } - public void SetAttackTrigger(bool value) - { - AttackTrigger = value; - } - #region 적 탐지 // 일정 반경에 플레이어가 진입하면 플레이어 소리를 감지했다고 판단 diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs index 1442509b..b102ce4e 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateAttack.cs @@ -4,52 +4,22 @@ 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 const float AttackInterval = 2f; - private float _attackTimer = 0f; public void Enter(EnemyController enemyController) { _enemyController = enemyController; _animator = _enemyController.EnemyAnimator; - } public void Update() { - if (!_enemyController.IsBoss) - NonBossSequence(); - if (_enemyController.AttackTrigger) - { - _animator.SetTrigger(VertiSlash); - _enemyController.SetState(EnemyState.Trace); - } - } - - private void NonBossSequence() - { - _animator.SetBool(VertiAttack, true); - _attackTimer += Time.deltaTime; - - if (_attackTimer >= AttackInterval) - { - _animator.SetTrigger(VertiSlash); - _attackTimer = 0f; - _enemyController.SetState(EnemyState.Trace); - } } public void Exit() { - _enemyController.SetAttackTrigger(false); - _animator.SetBool(VertiAttack, false); _animator = null; _enemyController = null; } diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs index 7ded15d5..158b9eab 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateDead.cs @@ -6,7 +6,6 @@ { _enemyController = enemyController; _enemyController.EnemyAnimator.SetTrigger("Dead"); - _enemyController.SetInBattle(false); } public void Update() diff --git a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs index 587c91a5..b8714ef6 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateIdle.cs @@ -2,13 +2,13 @@ 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); - _enemyController.SetInBattle(false); + _enemyController.EnemyAnimator.SetBool(Idle, true); } public void Update() @@ -22,7 +22,7 @@ public class EnemyStateIdle: IEnemyState public void Exit() { - _enemyController.EnemyAnimator.SetBool("Idle", false); + _enemyController.EnemyAnimator.SetBool(Idle, false); _enemyController = null; } } \ 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 e69433c5..4d9dce94 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/EnemyStateTrace.cs @@ -29,11 +29,12 @@ public class EnemyStateTrace : IEnemyState } _enemyController.EnemyAnimator.SetBool(Trace, true); - _enemyController.SetInBattle(true); } public void Update() { + if (_enemyController.Agent.enabled != true) return; + // 일정 주기로 찾은 플레이어의 위치를 갱신해서 갱신된 위치로 이동 FindTargetPosition(); @@ -44,7 +45,6 @@ public class EnemyStateTrace : IEnemyState // TODO: 타겟에 도착함 -> 공격 준비 _enemyController.SetState(EnemyState.Attack); } - } private void FindTargetPosition() @@ -70,24 +70,12 @@ public class EnemyStateTrace : IEnemyState { 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; } @@ -108,11 +96,6 @@ public class EnemyStateTrace : IEnemyState Time.deltaTime * 10f // 회전 속도 ); } - - // _enemyController.Agent.angularSpeed = 1080f; - // _enemyController.Agent.acceleration = 999f; - - // _enemyController.EnemyAnimator.SetFloat("MoveSpeed", 0f); } // 실제 속도 기반으로 애니메이션 제어 diff --git a/Assets/Scripts/Character/Enemy/PldDogController.cs b/Assets/Scripts/Character/Enemy/PldDogController.cs index 41b26f51..6ce9513b 100644 --- a/Assets/Scripts/Character/Enemy/PldDogController.cs +++ b/Assets/Scripts/Character/Enemy/PldDogController.cs @@ -2,9 +2,13 @@ using System; using System.Collections; using Unity.VisualScripting; using UnityEngine; +using Random = UnityEngine.Random; public class PldDogController : EnemyController { + private static readonly int WindUp = Animator.StringToHash("WindUp"); + private static readonly int VertiSlash = Animator.StringToHash("VertiSlash"); + [Header("공격 패턴 관련")] [SerializeField] private float patternInterval = 3f; @@ -12,7 +16,6 @@ public class PldDogController : EnemyController private int _currentPatternIndex = 0; private bool _isPatternRunning = false; - [Header("각종 데미지 이펙트 세트")] [SerializeField] private GameObject chariotSlashWarning; [SerializeField] private GameObject chariotSlash; @@ -25,27 +28,64 @@ public class PldDogController : EnemyController [SerializeField] private GameObject horizontalWarning; [SerializeField] private GameObject horizontalSlash; - // 몬스터의 행동 스크립트 - // IsBoos = 보스몬스터 여부 - // IsInBattle = 전투중인지 여부 - protected override void Awake() - { - base.Awake(); - IsBoss = true; - } + private bool _isInTrace; + private bool _isInAttack; + private bool _isFirstAttack = true; private void Update() { base.Update(); - if (IsInBattle && !_isPatternRunning && CurrentState == EnemyState.Attack) + CheckIsInBattle(); + + if (_isInAttack) { _patternTimer += Time.deltaTime; - if (_patternTimer >= patternInterval) + + if (!_isPatternRunning && (_isFirstAttack || _patternTimer >= patternInterval)) { - ExecutePattern(0); + Agent.enabled = false; + + // TODO: 순서대로 패턴 실행 + ExecutePattern(_currentPatternIndex); + + // _currentPatternIndex = (_currentPatternIndex + 1) % 3; // 패턴 순환 + + _isFirstAttack = false; } } + + if (_isInTrace) + { + _patternTimer += Time.deltaTime; + + if (!_isPatternRunning && _patternTimer >= patternInterval) + { + _isPatternRunning = true; + + float distanceToPlayer = Vector3.Distance(transform.position, TraceTargetTransform.position); + + if (distanceToPlayer > 3f) + { + BombThrowPattern(); + } + } + } + } + + private void CheckIsInBattle() + { + switch (CurrentState) + { + case EnemyState.Attack: + _isInAttack = true; + _isInTrace = false; + break; + case EnemyState.Trace: + _isInTrace = true; + _isInAttack = false; + break; + } } private void ExecutePattern(int patternIndex) @@ -70,11 +110,41 @@ public class PldDogController : EnemyController } } + private void BombThrowPattern() + { + Debug.Log("BombThrowPattern: 보스가 폭탄을 던집니다."); + + int bombCount = 1; // 한 번에 몇 개 던질지 + float radius = 2f; + + for (int i = 0; i < bombCount; i++) + { + Vector3 randomPos = TraceTargetTransform.position + (Random.insideUnitSphere * radius); + randomPos.y = 0.1f; // 지면에 맞추기 + + var boomObj = Instantiate(chariotSlashWarning, randomPos, Quaternion.identity); + boomObj.transform.localScale = new Vector3(5f, 5f, 5f); + var boom = boomObj.GetComponent(); + + DamageEffectData effectData = new DamageEffectData() + { + damage = (int)attackPower, + radius = 5f, + delay = 1.5f, + targetLayer = TargetLayerMask, + explosionEffectPrefab = chariotSlash + }; + + boom.SetEffect(effectData,()=>{ }, PatternClear); + } + } + private void ChariotSlashPattern() { Debug.Log("ChariotSlashPattern: 보스가 차지 슬래시를 사용합니다."); - EnemyAnimator.SetBool("VertiAttack", true); - var warning = Instantiate(chariotSlashWarning, transform.position, Quaternion.identity) + WindUpAnimationStart(); + + var slash = Instantiate(chariotSlashWarning, transform.position, Quaternion.identity) .GetComponent(); DamageEffectData effectData = new DamageEffectData() @@ -85,6 +155,36 @@ public class PldDogController : EnemyController targetLayer = TargetLayerMask, explosionEffectPrefab = chariotSlash }; - warning.SetEffect(effectData, this); + + slash.SetEffect(effectData, SlashAnimationPlay, + () => + { + PatternClear(); + WindUpAnimationEnd(); + SetState(EnemyState.Trace); + } + ); + } + + private void WindUpAnimationStart() + { + EnemyAnimator.SetBool(WindUp, true); + } + + private void WindUpAnimationEnd() + { + EnemyAnimator.SetBool(WindUp, false); + } + + private void SlashAnimationPlay() + { + EnemyAnimator.SetTrigger(VertiSlash); + } + + private void PatternClear() + { + _isPatternRunning = false; + _patternTimer = 0f; + Agent.enabled = true; } }