using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; using Random = UnityEngine.Random; public class CasterDemonController : EnemyController { private bool _doneBattleSequence = true; private bool _isFirstNoPath = true; private Coroutine _currentSequence; [SerializeField] private Transform teleportTransform; [SerializeField] private Transform bulletShotPosition; [SerializeField] private GameObject magicMissilePrefab; [SerializeField] private GameObject teleportEffectPrefab; [Header("각종 데미지 이펙트 세트")] [SerializeField] private GameObject chariotWarning; [SerializeField] private GameObject chariotEffect; private float _teleportDistance = 4f; // 플레이어 뒤로 떨어질 거리 // 텔레포트 쿨타임 private float _teleportTimer = 0; private const float TeleportThresholdTime = 20f; private bool CanTeleport { get { if (_teleportTimer >= TeleportThresholdTime ) { _teleportTimer = 0; return true; } return false; } } private void LateUpdate() { _teleportTimer += Time.deltaTime; } public override void BattleSequence() { // 전투 행동이 이미 진행 중일 경우 실행 막기 if (_doneBattleSequence) { // 전투 행동 시작 _doneBattleSequence = false; // TODO : 배틀 중일 때 루프 // Debug.Log("## 몬스터의 교전 행동 루프"); Thinking(); } } private void Thinking() { int selectedPattern = Random.Range(0, 10); switch (selectedPattern) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: SetSequence(ShotMagicMissile()); break; } } public override void OnCannotFleeBehaviour(Action action) { if (CanTeleport) { action(); Teleport(); } } private IEnumerator ShotMagicMissile() { for (int i = 0; i < 3; i++) { var aimPosition = TargetPosOracle(out var basePos, out var rb); // 높이는 변경할 필요 없음 float fixedY = bulletShotPosition.position.y; aimPosition.y = fixedY; // 3. 그 위치를 바라보고 transform.LookAt(aimPosition); // 4. 미사일 생성 및 초기화 var missile = Instantiate( magicMissilePrefab, bulletShotPosition.position, transform.rotation ); missile.GetComponent() .Initialize(new BulletData(aimPosition, 5f, 10f, 5f)); yield return new WaitForSeconds(0.4f); } // 짧은 텀 후 끝내기 yield return new WaitForSeconds(1f); _doneBattleSequence = true; } private Vector3 TargetPosOracle(out Vector3 basePos, out Rigidbody rb) { // 1. 기본 위치 basePos = TraceTargetTransform.position; Vector3 aimPosition = basePos; // 2. 플레이어 Rigidbody로 속도 얻기 if (TraceTargetTransform.TryGetComponent(out rb)) { // 아주 짧은 시간만 예측 float predictionTime = 0.3f; aimPosition += rb.velocity * predictionTime; } return aimPosition; } private void Teleport() { Vector3 startPos = transform.position; if (teleportEffectPrefab != null) Instantiate(teleportEffectPrefab, startPos, Quaternion.identity); // 텔레포트와 함께 시전하는 범위 공격 var aoe = Instantiate(chariotWarning, startPos, Quaternion.identity).GetComponent(); var effectData = new DamageEffectData { damage = (int)attackPower, radius = 10, delay = 1.5f, targetLayer = TargetLayerMask, explosionEffectPrefab = chariotEffect }; aoe.SetEffect(effectData, null, null); // // 플레이어 뒤쪽 위치 계산 // Vector3 playerPos = TraceTargetTransform.position; // Vector3 behindDir = -TraceTargetTransform.forward; // Vector3 targetPos = playerPos + behindDir.normalized * _teleportDistance; // // // NavMesh 유효 위치 확인 // Vector3 finalPos = targetPos; // if (NavMesh.SamplePosition(targetPos, out NavMeshHit hit, 1f, NavMesh.AllAreas)) // { // finalPos = hit.position; // } // // // 텔레포트 실행 // Agent.Warp(finalPos); // // if (teleportEffectPrefab != null) // Instantiate(teleportEffectPrefab, finalPos, Quaternion.identity); // 중앙으로 이동 Agent.Warp(Vector3.zero); if (teleportEffectPrefab != null) Instantiate(teleportEffectPrefab, Vector3.zero, Quaternion.identity); } private void SetSequence(IEnumerator newSequence) { if (_currentSequence != null) { StopCoroutine(_currentSequence); } _currentSequence = StartCoroutine(newSequence); } }