[fix] 도주 대체 경로 찾는 중 워프 발생하여 수정 시작
- 텔레포트 쿨타임 생성 - 텔레포트 로직 변경 (플레이어 뒤로 순간이동) - 코루틴 관리를 위한 메서드 생성
This commit is contained in:
parent
5dcde907a1
commit
71a904e57e
BIN
Assets/JYY/Scenes/MonsterTest.unity
(Stored with Git LFS)
BIN
Assets/JYY/Scenes/MonsterTest.unity
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user