DEG-95 몬스터가 도망치는 상태 스크립트 구현
- 도망치는 애니메이션을 상태 스크립트에서 처리 - 전투 패턴은 몬스터 객체에게 위임
This commit is contained in:
parent
39379da300
commit
2bb71999b7
@ -4,5 +4,16 @@ using UnityEngine;
|
||||
|
||||
public class CasterDemonController : EnemyController
|
||||
{
|
||||
|
||||
|
||||
public override void BattleSequence()
|
||||
{
|
||||
// TODO : 배틀 중일 때 루프
|
||||
Debug.Log("## 몬스터의 교전 행동 루프");
|
||||
}
|
||||
|
||||
|
||||
public override void OnCannotFleeBehaviour()
|
||||
{
|
||||
Debug.Log("## 몬스터가 막다른 길에 몰려 뭔가 함");
|
||||
}
|
||||
}
|
||||
|
@ -110,13 +110,24 @@ public abstract class EnemyController : CharacterBase
|
||||
}
|
||||
|
||||
|
||||
#region 몬스터의 행동 패턴 위임
|
||||
|
||||
// 전략 패턴과 템플릿 메서드 패턴을 활용
|
||||
public virtual void BattleSequence()
|
||||
{
|
||||
// 이 메서드는 자식 요소에서 오버라이드하여 구현합니다.
|
||||
Debug.LogWarning("BattleSequence가 구현되지 않음 : " + "BattleSequence()를 오버라이드하여 구현하십시오.");
|
||||
Debug.LogWarning("BattleSequence가 구현되지 않음 : BattleSequence()를 오버라이드하여 구현하십시오.");
|
||||
}
|
||||
|
||||
// 도망치며 싸우는 몬스터가 도망칠 곳이 없을때 취할 행동
|
||||
public virtual void OnCannotFleeBehaviour()
|
||||
{
|
||||
Debug.LogWarning("OnCannotFleeBehaviour가 구현되지 않음 : OnCannotFleeBehaviour() 오버라이드하여 구현하십시오.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public override void Die()
|
||||
{
|
||||
base.Die();
|
||||
|
@ -1,45 +1,109 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
public class EnemyStateFlee :IEnemyState
|
||||
{
|
||||
private EnemyController _enemyController;
|
||||
private Transform _detectPlayerTransform;
|
||||
|
||||
private const float MaxDetectPlayerInCircleWaitTime = 0.2f;
|
||||
private float _detectPlayerInCircleWaitTime = 0f;
|
||||
|
||||
private Transform _playerTransform;
|
||||
private float _fleeDistance = 5f; // 도망치는 거리
|
||||
private float _attackRange = 7f; // 공격 범위
|
||||
|
||||
// 막다른길 검사용
|
||||
private Vector3 _lastPosition;
|
||||
private float _stuckTimer = 0f;
|
||||
private const float StuckThresholdTime = 1f; // 1초 동안 거의 못 움직이면 막힌 걸로 간주
|
||||
private const float StuckMoveThreshold = 0.1f; // 이내 이동은 “제자리”로 본다
|
||||
|
||||
public void Enter(EnemyController enemyController)
|
||||
{
|
||||
_enemyController = enemyController;
|
||||
Debug.Log("## Flee 상태 진입");
|
||||
|
||||
_detectPlayerTransform = _enemyController.TraceTargetTransform;
|
||||
if (!_detectPlayerTransform)
|
||||
{
|
||||
_enemyController.SetState(EnemyState.Idle);
|
||||
return;
|
||||
}
|
||||
_playerTransform = _enemyController.TraceTargetTransform;
|
||||
_lastPosition = _enemyController.transform.position;
|
||||
_stuckTimer = 0f;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// 도망치는 방향 계산
|
||||
Vector3 fleeDirection = (_enemyController.transform.position - _detectPlayerTransform.position).normalized;
|
||||
if (!_playerTransform)
|
||||
{
|
||||
_enemyController.SetState(EnemyState.Idle);
|
||||
return;
|
||||
}
|
||||
|
||||
FindPositionFlee();
|
||||
|
||||
// 막힘 감지 (실제 이동 체크)
|
||||
CheckPath();
|
||||
|
||||
_lastPosition = _enemyController.transform.position;
|
||||
}
|
||||
|
||||
private void CheckPath()
|
||||
{
|
||||
float distance = Vector3.Distance(_enemyController.transform.position, _playerTransform.position);
|
||||
if (distance < StuckMoveThreshold)
|
||||
{
|
||||
_stuckTimer += Time.deltaTime;
|
||||
if (_stuckTimer >= StuckThresholdTime)
|
||||
{
|
||||
// 막다른 길임 : 대체 행동 실행
|
||||
HandleDeadEnd();
|
||||
_stuckTimer = 0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상적인 길: 배틀 루프 실행
|
||||
_enemyController.BattleSequence();
|
||||
_stuckTimer = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void FindPositionFlee()
|
||||
{
|
||||
// 1) 목표 도망 위치 계산
|
||||
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
|
||||
Vector3 fleeTarget = _enemyController.transform.position + fleeDirection * _fleeDistance;
|
||||
|
||||
_enemyController.Agent.SetDestination(fleeTarget);
|
||||
// 2) 경로 계산해 보기
|
||||
NavMeshPath path = new NavMeshPath();
|
||||
_enemyController.Agent.CalculatePath(fleeTarget, path);
|
||||
|
||||
float distance = Vector3.Distance(_enemyController.transform.position, _detectPlayerTransform.position);
|
||||
if (path.status == NavMeshPathStatus.PathComplete)
|
||||
{
|
||||
// 제대로 도망갈 수 있으면 목적지 설정
|
||||
_enemyController.Agent.SetDestination(fleeTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 막다른 길임 : 대체 행동 실행
|
||||
HandleDeadEnd();
|
||||
}
|
||||
}
|
||||
|
||||
_enemyController.BattleSequence();
|
||||
private void HandleDeadEnd()
|
||||
{
|
||||
// 무작위 도망 지점 샘플링 시도
|
||||
Vector3 randomDirection = Random.insideUnitSphere * (_fleeDistance * 2);
|
||||
randomDirection += _playerTransform.position;
|
||||
|
||||
if (NavMesh.SamplePosition(randomDirection, out var hit, (_fleeDistance * 2), NavMesh.AllAreas))
|
||||
{
|
||||
_enemyController.Agent.SetDestination(hit.position);
|
||||
return;
|
||||
}
|
||||
|
||||
// 대체 경로도 찾을 수 없는 경우
|
||||
_enemyController.OnCannotFleeBehaviour();
|
||||
}
|
||||
|
||||
public void Exit()
|
||||
{
|
||||
_detectPlayerTransform = null;
|
||||
_playerTransform = null;
|
||||
_enemyController = null;
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ public class PldDogController : EnemyController
|
||||
[SerializeField] private GameObject horizontalWarning;
|
||||
[SerializeField] private GameObject horizontalSlash;
|
||||
|
||||
[SerializeField] private float _patternTimer = 0f;
|
||||
private float _patternTimer = 0f;
|
||||
private int _lastPatternIndex = -1;
|
||||
private bool _isPatternRunning = false;
|
||||
private bool _isFirstAttack = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user