[fix] 도주 대체 경로 찾는 중 워프 발생하여 수정 시작

- 텔레포트 쿨타임 생성
- 텔레포트 로직 변경 (플레이어 뒤로 순간이동)
- 코루틴 관리를 위한 메서드 생성
This commit is contained in:
Fiore 2025-04-29 18:08:45 +09:00
parent 5dcde907a1
commit 71a904e57e
4 changed files with 100 additions and 40 deletions

BIN
Assets/JYY/Scenes/MonsterTest.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -1,16 +1,45 @@
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;
[SerializeField] private float teleportDistance = 4f; // 플레이어 뒤로 떨어질 거리
// 텔레포트 쿨타임
private float _teleportTimer = 0;
private const float TeleportThresholdTime = 3.5f;
private bool CanTeleport {
get
{
if (_teleportTimer >= TeleportThresholdTime )
{
_teleportTimer = 0;
return true;
}
return false;
}
}
private void LateUpdate()
{
_teleportTimer += Time.deltaTime;
}
public override void BattleSequence()
{
// 전투 행동이 이미 진행 중일 경우 실행 막기
@ -25,7 +54,6 @@ public class CasterDemonController : EnemyController
}
}
private void Thinking()
{
int selectedPattern = Random.Range(0, 10);
@ -51,34 +79,22 @@ public class CasterDemonController : EnemyController
case 8:
case 9:
StartCoroutine(ShotMagicMissile());
SetSequence(ShotMagicMissile());
break;
}
}
public override void OnCannotFleeBehaviour()
{
// 구석에 끼인 경우 탈출
Debug.Log("## 텔레포트 시전");
Teleport();
if(CanTeleport)
SetSequence(Teleport());
}
private IEnumerator ShotMagicMissile()
{
for (int i = 0; i < 3; i++)
{
// 1. 기본 위치
Vector3 basePos = TraceTargetTransform.position;
Vector3 aimPosition = basePos;
// 2. 플레이어 Rigidbody로 속도 얻기
if (TraceTargetTransform.TryGetComponent<Rigidbody>(out var rb))
{
// 아주 짧은 시간만 예측
float predictionTime = 0.3f;
aimPosition += rb.velocity * predictionTime;
}
var aimPosition = TargetPosOracle(out var basePos, out var rb);
// 높이는 변경할 필요 없음
float fixedY = bulletShotPosition.position.y;
@ -104,21 +120,59 @@ public class CasterDemonController : EnemyController
_doneBattleSequence = true;
}
private void Teleport()
private Vector3 TargetPosOracle(out Vector3 basePos, out Rigidbody rb)
{
if (teleportEffectPrefab != null)
Instantiate(teleportEffectPrefab, transform.position, Quaternion.identity);
// 1. 기본 위치
basePos = TraceTargetTransform.position;
Vector3 aimPosition = basePos;
if (Agent != null && teleportTransform != null)
Agent.Warp(teleportTransform.position);
else if (teleportTransform != null)
transform.position = teleportTransform.position;
// 2. 플레이어 Rigidbody로 속도 얻기
if (TraceTargetTransform.TryGetComponent<Rigidbody>(out rb))
{
// 아주 짧은 시간만 예측
float predictionTime = 0.3f;
aimPosition += rb.velocity * predictionTime;
}
if (teleportEffectPrefab != null && teleportTransform != null)
Instantiate(teleportEffectPrefab, teleportTransform.position, Quaternion.identity);
return aimPosition;
}
private IEnumerator Teleport()
{
Vector3 startPos = transform.position;
if (teleportEffectPrefab != null)
Instantiate(teleportEffectPrefab, startPos, Quaternion.identity);
// 플레이어 뒤쪽 위치 계산
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;
}
yield return new WaitForSeconds(0.3f);
// 텔레포트 실행
Agent.Warp(finalPos);
if (teleportEffectPrefab != null)
Instantiate(teleportEffectPrefab, finalPos, Quaternion.identity);
yield return null;
}
private void SetSequence(IEnumerator newSequence)
{
if (_currentSequence != null)
{
StopCoroutine(_currentSequence);
}
_currentSequence = StartCoroutine(newSequence);
}
}

View File

@ -10,13 +10,14 @@ public class EnemyStateFlee :IEnemyState
// 경로 탐색 주기 조절용
private float _fleeSearchTimer = 0;
private float _fleeThresholdTime = 0.2f;
private const float FleeThresholdTime = 0.2f;
// 막다른길 검사용
private Vector3 _lastPosition;
private float _stuckTimer = 0f;
private const float StuckThresholdTime = 1f; // 1초 동안 거의 못 움직이면 막힌 걸로 간주
private const float StuckMoveThreshold = 0.1f; // 이내 이동은 “제자리”로 본다
private int _stuckCount = 0;
public void Enter(EnemyController enemyController)
{
@ -25,7 +26,6 @@ public class EnemyStateFlee :IEnemyState
_playerTransform = _enemyController.TraceTargetTransform;
_lastPosition = _enemyController.transform.position;
_enemyController.Agent.ResetPath();
_enemyController.Agent.isStopped = false;
_stuckTimer = 0f;
@ -76,8 +76,6 @@ public class EnemyStateFlee :IEnemyState
_stuckTimer += Time.deltaTime;
if (_stuckTimer >= StuckThresholdTime)
{
Debug.Log("## 끼임");
HandleDeadEnd();
_stuckTimer = 0f;
}
@ -91,7 +89,7 @@ public class EnemyStateFlee :IEnemyState
private void FindPositionFlee()
{
_fleeSearchTimer += Time.deltaTime;
if (_fleeSearchTimer <= _fleeThresholdTime) return;
if (_fleeSearchTimer <= FleeThresholdTime) return;
// 1) 목표 도망 위치 계산
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
@ -107,6 +105,13 @@ public class EnemyStateFlee :IEnemyState
private void HandleDeadEnd()
{
if (_stuckCount >= 4)
{
_enemyController.OnCannotFleeBehaviour();
_stuckCount = 0;
return;
}
_stuckCount++;
// 무작위 도망 지점 샘플링 시도
Vector3 randomDirection = Random.insideUnitSphere * (_fleeDistance * 2);
randomDirection += _playerTransform.position;
@ -116,14 +121,15 @@ public class EnemyStateFlee :IEnemyState
// 샘플링에 성공했으면 일단 그 위치로 가 보도록 세팅
Debug.Log("## 일단 가봄");
_enemyController.Agent.SetDestination(hit.position);
_enemyController.OnCannotFleeBehaviour();
}
else
{
// 대체 경로도 찾을 수 없는 경우
Debug.Log("## 대체 경로도 못찾음");
_enemyController.OnCannotFleeBehaviour();
// _enemyController.OnCannotFleeBehaviour();
}
// else
// {
// // 대체 경로도 찾을 수 없는 경우
// Debug.Log("## 대체 경로도 못찾음");
// _enemyController.OnCannotFleeBehaviour();
// }
}