[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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.AI;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
public class CasterDemonController : EnemyController
|
public class CasterDemonController : EnemyController
|
||||||
{
|
{
|
||||||
private bool _doneBattleSequence = true;
|
private bool _doneBattleSequence = true;
|
||||||
private bool _isFirstNoPath = true;
|
private bool _isFirstNoPath = true;
|
||||||
|
|
||||||
|
private Coroutine _currentSequence;
|
||||||
|
|
||||||
[SerializeField] private Transform teleportTransform;
|
[SerializeField] private Transform teleportTransform;
|
||||||
[SerializeField] private Transform bulletShotPosition;
|
[SerializeField] private Transform bulletShotPosition;
|
||||||
[SerializeField] private GameObject magicMissilePrefab;
|
[SerializeField] private GameObject magicMissilePrefab;
|
||||||
[SerializeField] private GameObject teleportEffectPrefab;
|
[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()
|
public override void BattleSequence()
|
||||||
{
|
{
|
||||||
// 전투 행동이 이미 진행 중일 경우 실행 막기
|
// 전투 행동이 이미 진행 중일 경우 실행 막기
|
||||||
@ -25,7 +54,6 @@ public class CasterDemonController : EnemyController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Thinking()
|
private void Thinking()
|
||||||
{
|
{
|
||||||
int selectedPattern = Random.Range(0, 10);
|
int selectedPattern = Random.Range(0, 10);
|
||||||
@ -51,34 +79,22 @@ public class CasterDemonController : EnemyController
|
|||||||
case 8:
|
case 8:
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
StartCoroutine(ShotMagicMissile());
|
SetSequence(ShotMagicMissile());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCannotFleeBehaviour()
|
public override void OnCannotFleeBehaviour()
|
||||||
{
|
{
|
||||||
// 구석에 끼인 경우 탈출
|
if(CanTeleport)
|
||||||
|
SetSequence(Teleport());
|
||||||
Debug.Log("## 텔레포트 시전");
|
|
||||||
Teleport();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator ShotMagicMissile()
|
private IEnumerator ShotMagicMissile()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
// 1. 기본 위치
|
var aimPosition = TargetPosOracle(out var basePos, out var rb);
|
||||||
Vector3 basePos = TraceTargetTransform.position;
|
|
||||||
Vector3 aimPosition = basePos;
|
|
||||||
|
|
||||||
// 2. 플레이어 Rigidbody로 속도 얻기
|
|
||||||
if (TraceTargetTransform.TryGetComponent<Rigidbody>(out var rb))
|
|
||||||
{
|
|
||||||
// 아주 짧은 시간만 예측
|
|
||||||
float predictionTime = 0.3f;
|
|
||||||
aimPosition += rb.velocity * predictionTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 높이는 변경할 필요 없음
|
// 높이는 변경할 필요 없음
|
||||||
float fixedY = bulletShotPosition.position.y;
|
float fixedY = bulletShotPosition.position.y;
|
||||||
@ -104,21 +120,59 @@ public class CasterDemonController : EnemyController
|
|||||||
_doneBattleSequence = true;
|
_doneBattleSequence = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Teleport()
|
private Vector3 TargetPosOracle(out Vector3 basePos, out Rigidbody rb)
|
||||||
{
|
{
|
||||||
if (teleportEffectPrefab != null)
|
// 1. 기본 위치
|
||||||
Instantiate(teleportEffectPrefab, transform.position, Quaternion.identity);
|
basePos = TraceTargetTransform.position;
|
||||||
|
Vector3 aimPosition = basePos;
|
||||||
|
|
||||||
if (Agent != null && teleportTransform != null)
|
// 2. 플레이어 Rigidbody로 속도 얻기
|
||||||
Agent.Warp(teleportTransform.position);
|
if (TraceTargetTransform.TryGetComponent<Rigidbody>(out rb))
|
||||||
else if (teleportTransform != null)
|
{
|
||||||
transform.position = teleportTransform.position;
|
// 아주 짧은 시간만 예측
|
||||||
|
float predictionTime = 0.3f;
|
||||||
|
aimPosition += rb.velocity * predictionTime;
|
||||||
|
}
|
||||||
|
|
||||||
if (teleportEffectPrefab != null && teleportTransform != null)
|
return aimPosition;
|
||||||
Instantiate(teleportEffectPrefab, teleportTransform.position, Quaternion.identity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 _fleeSearchTimer = 0;
|
||||||
private float _fleeThresholdTime = 0.2f;
|
private const float FleeThresholdTime = 0.2f;
|
||||||
|
|
||||||
// 막다른길 검사용
|
// 막다른길 검사용
|
||||||
private Vector3 _lastPosition;
|
private Vector3 _lastPosition;
|
||||||
private float _stuckTimer = 0f;
|
private float _stuckTimer = 0f;
|
||||||
private const float StuckThresholdTime = 1f; // 1초 동안 거의 못 움직이면 막힌 걸로 간주
|
private const float StuckThresholdTime = 1f; // 1초 동안 거의 못 움직이면 막힌 걸로 간주
|
||||||
private const float StuckMoveThreshold = 0.1f; // 이내 이동은 “제자리”로 본다
|
private const float StuckMoveThreshold = 0.1f; // 이내 이동은 “제자리”로 본다
|
||||||
|
private int _stuckCount = 0;
|
||||||
|
|
||||||
public void Enter(EnemyController enemyController)
|
public void Enter(EnemyController enemyController)
|
||||||
{
|
{
|
||||||
@ -25,7 +26,6 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
|
|
||||||
_playerTransform = _enemyController.TraceTargetTransform;
|
_playerTransform = _enemyController.TraceTargetTransform;
|
||||||
_lastPosition = _enemyController.transform.position;
|
_lastPosition = _enemyController.transform.position;
|
||||||
|
|
||||||
_enemyController.Agent.ResetPath();
|
_enemyController.Agent.ResetPath();
|
||||||
_enemyController.Agent.isStopped = false;
|
_enemyController.Agent.isStopped = false;
|
||||||
_stuckTimer = 0f;
|
_stuckTimer = 0f;
|
||||||
@ -76,8 +76,6 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
_stuckTimer += Time.deltaTime;
|
_stuckTimer += Time.deltaTime;
|
||||||
if (_stuckTimer >= StuckThresholdTime)
|
if (_stuckTimer >= StuckThresholdTime)
|
||||||
{
|
{
|
||||||
|
|
||||||
Debug.Log("## 끼임");
|
|
||||||
HandleDeadEnd();
|
HandleDeadEnd();
|
||||||
_stuckTimer = 0f;
|
_stuckTimer = 0f;
|
||||||
}
|
}
|
||||||
@ -91,7 +89,7 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
private void FindPositionFlee()
|
private void FindPositionFlee()
|
||||||
{
|
{
|
||||||
_fleeSearchTimer += Time.deltaTime;
|
_fleeSearchTimer += Time.deltaTime;
|
||||||
if (_fleeSearchTimer <= _fleeThresholdTime) return;
|
if (_fleeSearchTimer <= FleeThresholdTime) return;
|
||||||
|
|
||||||
// 1) 목표 도망 위치 계산
|
// 1) 목표 도망 위치 계산
|
||||||
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
|
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
|
||||||
@ -107,6 +105,13 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
|
|
||||||
private void HandleDeadEnd()
|
private void HandleDeadEnd()
|
||||||
{
|
{
|
||||||
|
if (_stuckCount >= 4)
|
||||||
|
{
|
||||||
|
_enemyController.OnCannotFleeBehaviour();
|
||||||
|
_stuckCount = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_stuckCount++;
|
||||||
// 무작위 도망 지점 샘플링 시도
|
// 무작위 도망 지점 샘플링 시도
|
||||||
Vector3 randomDirection = Random.insideUnitSphere * (_fleeDistance * 2);
|
Vector3 randomDirection = Random.insideUnitSphere * (_fleeDistance * 2);
|
||||||
randomDirection += _playerTransform.position;
|
randomDirection += _playerTransform.position;
|
||||||
@ -116,14 +121,15 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
// 샘플링에 성공했으면 일단 그 위치로 가 보도록 세팅
|
// 샘플링에 성공했으면 일단 그 위치로 가 보도록 세팅
|
||||||
Debug.Log("## 일단 가봄");
|
Debug.Log("## 일단 가봄");
|
||||||
_enemyController.Agent.SetDestination(hit.position);
|
_enemyController.Agent.SetDestination(hit.position);
|
||||||
_enemyController.OnCannotFleeBehaviour();
|
// _enemyController.OnCannotFleeBehaviour();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 대체 경로도 찾을 수 없는 경우
|
|
||||||
Debug.Log("## 대체 경로도 못찾음");
|
|
||||||
_enemyController.OnCannotFleeBehaviour();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // 대체 경로도 찾을 수 없는 경우
|
||||||
|
// Debug.Log("## 대체 경로도 못찾음");
|
||||||
|
// _enemyController.OnCannotFleeBehaviour();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user