From b9a014df88d7fcb75fba40919ac578c60d0ec4ad Mon Sep 17 00:00:00 2001 From: Fiore Date: Wed, 7 May 2025 14:27:29 +0900 Subject: [PATCH] =?UTF-8?q?[refact]=20=EB=8F=84=EB=A7=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0,=20=EC=BD=94=EB=A3=A8=ED=8B=B4?= =?UTF-8?q?=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 몬스터가 텔레포트로 도망칠 위치를 에디터에서 수정할 수 있도록 개선 - 플레이어와 거리 계산 최적화 - 코루틴에서 사용하는 WaitForSecond 객체 캐싱 유틸 추가 Work in JIRA ISSUE #DEG-100 --- .../Character/Enemy/CasterDemonController.cs | 46 +++++++++---------- .../Enemy/EnemyState/Caster/EnemyStateFlee.cs | 34 +++++++++----- Assets/Scripts/Utils.meta | 3 ++ Assets/Scripts/Utils/Wait.cs | 18 ++++++++ Assets/Scripts/Utils/Wait.cs.meta | 3 ++ 5 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 Assets/Scripts/Utils.meta create mode 100644 Assets/Scripts/Utils/Wait.cs create mode 100644 Assets/Scripts/Utils/Wait.cs.meta diff --git a/Assets/Scripts/Character/Enemy/CasterDemonController.cs b/Assets/Scripts/Character/Enemy/CasterDemonController.cs index 54d35c78..7544458b 100644 --- a/Assets/Scripts/Character/Enemy/CasterDemonController.cs +++ b/Assets/Scripts/Character/Enemy/CasterDemonController.cs @@ -16,7 +16,6 @@ public class CasterDemonController : EnemyController public static readonly int Spin = Animator.StringToHash("Spin"); private bool _doneBattleSequence = true; - private bool _isFirstNoPath = true; private Coroutine _currentSequence; @@ -24,7 +23,7 @@ public class CasterDemonController : EnemyController [SerializeField] private Transform bulletShotPosition; [SerializeField] private GameObject magicMissilePrefab; [SerializeField] private GameObject teleportEffectPrefab; - + [SerializeField] private Vector3 teleportTargetPosition = Vector3.zero; [Header("각종 데미지 이펙트 세트")] [SerializeField] private GameObject chariotWarning; [SerializeField] private GameObject chariotEffect; @@ -33,15 +32,13 @@ public class CasterDemonController : EnemyController [SerializeField] private GameObject slowFieldWarning; [SerializeField] private GameObject slowFieldEffect; - // private float _teleportDistance = 4f; // 플레이어 뒤로 떨어질 거리 - // 텔레포트 쿨타임 처음엔 빨리 사용 가능함 private float _teleportTimer = 10f; private const float TeleportThresholdTime = 20f; // 다음 행동 생각 처음엔 즉시 실행 private float _tinkingTimer = 3f; - private float _tinkingThresholedTime = 3f; + private float _thinkingThresholdTime = 3f; // 프로퍼티 private bool CanTeleport { @@ -59,7 +56,7 @@ public class CasterDemonController : EnemyController { get { - if (_tinkingTimer >= _tinkingThresholedTime) + if (_tinkingTimer >= _thinkingThresholdTime) { _tinkingTimer = 0; return true; @@ -68,6 +65,7 @@ public class CasterDemonController : EnemyController } } + private void LateUpdate() { _teleportTimer += Time.deltaTime; @@ -82,8 +80,7 @@ public class CasterDemonController : EnemyController // 전투 행동 시작 _doneBattleSequence = false; - // TODO : 배틀 중일 때 루프 - // Debug.Log("## 몬스터의 교전 행동 루프"); + // 사용할 공격 생각하기 Thinking(); } } @@ -99,14 +96,14 @@ public class CasterDemonController : EnemyController case 2: case 3: case 4: + SetSequence(RunPattern(ShotMagicMissile)); + break; case 5: case 6: case 7: - SetSequence(ShotMagicMissile()); - break; case 8: case 9: - SetSequence(SlowFieldSpell()); + SetSequence(RunPattern(SlowFieldSpell)); break; } @@ -116,11 +113,11 @@ public class CasterDemonController : EnemyController { if (CanTeleport) { - action(); + action.Invoke(); Teleport(); return; } - SetSequence(KnockbackSpell()); + SetSequence(RunPattern(KnockbackSpell)); } private IEnumerator ShotMagicMissile() @@ -142,12 +139,11 @@ public class CasterDemonController : EnemyController missile.GetComponent() .Initialize(new BulletData(aimPosition, 5f, 10f, 5f)); - yield return new WaitForSeconds(0.4f); + yield return Wait.For(0.4f); } // 짧은 텀 후 끝내기 - yield return new WaitForSeconds(1f); - _doneBattleSequence = true; + yield return Wait.For(1f); } private Vector3 TargetPosOracle(out Vector3 basePos, out Rigidbody rb) @@ -191,8 +187,8 @@ public class CasterDemonController : EnemyController aoe.SetEffect(effectData, null, null); - // 중앙으로 이동 - Agent.Warp(Vector3.zero); + // 텔레포트 타겟 위치로 이동 + Agent.Warp(teleportTargetPosition); SetAnimation(Telepo); if (teleportEffectPrefab != null) @@ -220,11 +216,9 @@ public class CasterDemonController : EnemyController var warning = Instantiate(chariotWarning, fixedPos, Quaternion.identity).GetComponent(); warning.SetEffect(effectData, null, null); - // TODO : 효과 적용 // 3. 짧은 텀 후 끝내기 - yield return new WaitForSeconds(1f); - _doneBattleSequence = true; + yield return Wait.For(1f); } private IEnumerator KnockbackSpell() @@ -245,8 +239,7 @@ public class CasterDemonController : EnemyController var knockback = Instantiate(chariotWarning, transform).GetComponent(); knockback.SetEffect(effectData, null, null, DebuffType.Knockback.ToString()); - yield return new WaitForSeconds(1f); - _doneBattleSequence = true; + yield return Wait.For(1f); } private void SetSequence(IEnumerator newSequence) @@ -258,4 +251,9 @@ public class CasterDemonController : EnemyController _currentSequence = StartCoroutine(newSequence); } -} + private IEnumerator RunPattern(Func pattern) + { + yield return StartCoroutine(pattern()); + _doneBattleSequence = true; + } +} \ 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 index 77467655..a8c88bd6 100644 --- a/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs +++ b/Assets/Scripts/Character/Enemy/EnemyState/Caster/EnemyStateFlee.cs @@ -7,8 +7,11 @@ public class EnemyStateFlee :IEnemyState { private EnemyController _enemyController; private Transform _playerTransform; - private float _fleeDistance = 10f; // 도망치는 거리 private float _attackRange = 7f; // 공격 범위 + private float _fleeDistance = 15f; // 도망치는 거리 + + private float _attackRangeSqr; + private float _fleeDistanceSqr; // 경로 탐색 주기 조절용 private float _fleeSearchTimer = 0; @@ -33,6 +36,9 @@ public class EnemyStateFlee :IEnemyState _stuckTimer = 0f; _fleeSearchTimer = 0; + _attackRangeSqr = _attackRange * _attackRange; + _fleeDistanceSqr = _fleeDistance * _fleeDistance; + _enemyController.SetAnimation(CasterDemonController.Flee, true); } @@ -44,11 +50,17 @@ public class EnemyStateFlee :IEnemyState return; } - float currentDist = Vector3.Distance( - _enemyController.transform.position, - _playerTransform.position - ); - if (currentDist >= _attackRange) + float currentDist = (_enemyController.transform.position - _playerTransform.position).sqrMagnitude; + + if (currentDist >= _fleeDistanceSqr) + { + _enemyController.Agent.isStopped = true; + _enemyController.Agent.ResetPath(); + _enemyController.SetState(EnemyState.Idle); + return; + } + + if (currentDist >= _attackRangeSqr) { // 목적지 리셋 후 전투 시작 _enemyController.Agent.isStopped = true; @@ -74,8 +86,8 @@ public class EnemyStateFlee :IEnemyState private void CheckPath() { - float moved = Vector3.Distance(_enemyController.transform.position, _lastPosition); - if (moved < StuckMoveThreshold) + float moved = (_enemyController.transform.position - _lastPosition).sqrMagnitude; + if (moved < StuckMoveThreshold * StuckMoveThreshold) { _stuckTimer += Time.deltaTime; if (_stuckTimer >= StuckThresholdTime) @@ -95,14 +107,12 @@ public class EnemyStateFlee :IEnemyState _fleeSearchTimer += Time.deltaTime; if (_fleeSearchTimer <= FleeThresholdTime) return; - // 1) 목표 도망 위치 계산 + // 플레이어 반대방향으로 도망 Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized; Vector3 fleeTarget = _enemyController.transform.position + fleeDirection * _fleeDistance; - // 2) 경로 계산해 보기 + // 경로 설정 _enemyController.Agent.SetDestination(fleeTarget); - - // 3) 이동 _enemyController.Agent.isStopped = false; _fleeSearchTimer = 0; } diff --git a/Assets/Scripts/Utils.meta b/Assets/Scripts/Utils.meta new file mode 100644 index 00000000..73a2a189 --- /dev/null +++ b/Assets/Scripts/Utils.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6757ce2a26e44e9c931666533e7e8036 +timeCreated: 1746594438 \ No newline at end of file diff --git a/Assets/Scripts/Utils/Wait.cs b/Assets/Scripts/Utils/Wait.cs new file mode 100644 index 00000000..b7da55e6 --- /dev/null +++ b/Assets/Scripts/Utils/Wait.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UnityEngine; + +// 코루틴의 WaitForSeconds를 캐싱하는 유틸 +public static class Wait +{ + private static readonly Dictionary _waits = new(); + + public static WaitForSeconds For(float seconds) + { + if (!_waits.TryGetValue(seconds, out var wait)) + { + wait = new WaitForSeconds(seconds); + _waits[seconds] = wait; + } + return wait; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Utils/Wait.cs.meta b/Assets/Scripts/Utils/Wait.cs.meta new file mode 100644 index 00000000..5b81f880 --- /dev/null +++ b/Assets/Scripts/Utils/Wait.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e6fe7172532f42069e3fc7088ebd0718 +timeCreated: 1746594464 \ No newline at end of file