100 lines
7.3 KiB
C#
100 lines
7.3 KiB
C#
|
|
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
|
||
|
|
|
||
|
|
// ============================================================
|
||
|
|
// NorcielBoss.Tracking.cs — 플레이어 행동 추적 (partial class)
|
||
|
|
//
|
||
|
|
// [역할]
|
||
|
|
// 매 프레임 플레이어의 행동을 분석하여 적응형 AI에 데이터를 제공합니다.
|
||
|
|
// - 정지 감지 (서있으면 공격적 패턴)
|
||
|
|
// - 접근/도주 감지 (다가오면 카운터, 도망치면 갭클로저)
|
||
|
|
// - 카이팅 감지 (거리 유지 + 피격 → 대시 돌진)
|
||
|
|
// - 피격 카운터 감쇠 (시간이 지나면 카운터 감소)
|
||
|
|
// - 뒤잡기 감지 → counterSystem에 위임
|
||
|
|
//
|
||
|
|
// [설계]
|
||
|
|
// partial class로 NorcielBoss의 private 필드에 직접 접근.
|
||
|
|
// Update()에서 TrackPlayerBehavior() 한 줄로 호출됩니다.
|
||
|
|
// ============================================================
|
||
|
|
|
||
|
|
public partial class NorcielBoss : MonsterClass // 부분 클래스를 선언할거에요 -> NorcielBoss의 플레이어 추적 부분으로
|
||
|
|
{
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 플레이어 행동 추적 런타임 변수
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
private Vector3 _prevTargetPos; // 변수를 선언할거에요 -> 이전 프레임 플레이어 위치를 (행동 추적 기준점)
|
||
|
|
private float _playerStillTimer = 0f; // 변수를 선언할거에요 -> 플레이어 정지 누적 시간을 (멈춰있으면 공격적으로)
|
||
|
|
private float _playerApproachTimer = 0f; // 변수를 선언할거에요 -> 플레이어 접근 누적 시간을 (다가오면 카운터 기회)
|
||
|
|
private float _playerFleeTimer = 0f; // 변수를 선언할거에요 -> 플레이어 도주 누적 시간을 (도망치면 갭클로저)
|
||
|
|
private float _kitingTimer = 0f; // 변수를 선언할거에요 -> 카이팅 감지 누적 시간을 (거리 유지 + 활 쏘기)
|
||
|
|
private int _recentHitCount = 0; // 변수를 선언할거에요 -> 최근 피격 횟수를 (짧은 시간 내 여러 번 맞으면 카이팅)
|
||
|
|
private float _recentHitDecay = 0f; // 변수를 선언할거에요 -> 피격 카운터 감쇠 타이머를
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 매 프레임 플레이어 행동 추적 (Update에서 호출)
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>플레이어의 정지/접근/도주/카이팅 행동을 매 프레임 분석</summary>
|
||
|
|
private void TrackPlayerBehavior() // 함수를 선언할거에요 -> 플레이어 행동을 추적하는
|
||
|
|
{
|
||
|
|
if (_target == null) return; // 중단할거에요 -> 타겟 없으면
|
||
|
|
|
||
|
|
Vector3 curPos = _target.position; // 가져올거에요 -> 현재 플레이어 위치를
|
||
|
|
Vector3 delta = curPos - _prevTargetPos; // 계산할거에요 -> 이전 프레임 대비 이동량을
|
||
|
|
float speed = delta.magnitude / Mathf.Max(Time.deltaTime, 0.001f); // 계산할거에요 -> 플레이어 이동 속도를 (m/s)
|
||
|
|
|
||
|
|
// ── 정지 감지 ───────────────────────────────────
|
||
|
|
if (speed < playerStillThreshold) // 조건이 맞으면 실행할거에요 -> 거의 안 움직이면
|
||
|
|
_playerStillTimer += Time.deltaTime; // 누적할거에요 -> 정지 시간을
|
||
|
|
else // 아니면 (움직이고 있으면)
|
||
|
|
_playerStillTimer = 0f; // 초기화할거에요 -> 움직이면 리셋
|
||
|
|
|
||
|
|
// ── 접근 / 도주 감지 ────────────────────────────
|
||
|
|
float prevDist = Vector3.Distance(transform.position, _prevTargetPos); // 계산할거에요 -> 이전 프레임 거리를
|
||
|
|
float curDist = Vector3.Distance(transform.position, curPos); // 계산할거에요 -> 현재 프레임 거리를
|
||
|
|
float distDelta = prevDist - curDist; // 계산할거에요 -> 거리 변화를 (양수 = 접근, 음수 = 도주)
|
||
|
|
|
||
|
|
if (distDelta > 0.01f) // 조건이 맞으면 실행할거에요 -> 플레이어가 다가오고 있으면
|
||
|
|
{
|
||
|
|
_playerApproachTimer += Time.deltaTime; // 누적할거에요 -> 접근 시간을
|
||
|
|
_playerFleeTimer = 0f; // 초기화할거에요 -> 도주 타이머를
|
||
|
|
}
|
||
|
|
else if (distDelta < -0.01f) // 조건이 맞으면 실행할거에요 -> 도망가고 있으면
|
||
|
|
{
|
||
|
|
_playerFleeTimer += Time.deltaTime; // 누적할거에요 -> 도주 시간을
|
||
|
|
_playerApproachTimer = 0f; // 초기화할거에요 -> 접근 타이머를
|
||
|
|
}
|
||
|
|
else // 거리 변화 거의 없으면 (옆으로 이동 등)
|
||
|
|
{
|
||
|
|
_playerApproachTimer = Mathf.Max(_playerApproachTimer - Time.deltaTime, 0f); // 감소할거에요 -> 천천히 소멸
|
||
|
|
_playerFleeTimer = Mathf.Max(_playerFleeTimer - Time.deltaTime, 0f); // 감소할거에요 -> 천천히 소멸
|
||
|
|
}
|
||
|
|
|
||
|
|
_prevTargetPos = curPos; // 갱신할거에요 -> 다음 프레임 비교용 위치를
|
||
|
|
|
||
|
|
// ── 카이팅 감지 ─────────────────────────────────
|
||
|
|
// 조건: 플레이어가 meleeRange 밖에 있으면서 + 최근에 피격당한 적이 있으면
|
||
|
|
// → "거리 유지하며 원거리 공격하는 중" = 카이팅
|
||
|
|
float curDist2 = Vector3.Distance(transform.position, curPos); // 계산할거에요 -> 현재 거리를
|
||
|
|
if (curDist2 > meleeRange && _recentHitCount >= 1) // 조건이 맞으면 실행할거에요 -> 원거리 + 최근 피격이면
|
||
|
|
_kitingTimer += Time.deltaTime; // 누적할거에요 -> 카이팅 시간을
|
||
|
|
else // 아니면
|
||
|
|
_kitingTimer = Mathf.Max(_kitingTimer - Time.deltaTime * 2f, 0f); // 감소할거에요 -> 빠르게 소멸
|
||
|
|
|
||
|
|
// ── 피격 카운터 감쇠 ────────────────────────────
|
||
|
|
// 3초 동안 안 맞으면 피격 카운터 1씩 감소
|
||
|
|
_recentHitDecay += Time.deltaTime; // 누적할거에요 -> 감쇠 타이머를
|
||
|
|
if (_recentHitDecay >= 3f) // 조건이 맞으면 실행할거에요 -> 3초 경과하면
|
||
|
|
{
|
||
|
|
_recentHitDecay = 0f; // 초기화할거에요 -> 타이머를
|
||
|
|
_recentHitCount = Mathf.Max(_recentHitCount - 1, 0); // 감소시킬거에요 -> 피격 카운터를 (최소 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── 뒤잡기 감지 → counterSystem에 위임 ──────────────
|
||
|
|
if (_target != null && counterSystem != null) // 조건이 맞으면 실행할거에요 -> 플레이어와 카운터 시스템 있으면
|
||
|
|
{
|
||
|
|
counterSystem.UpdateBehindTimer(transform.forward, transform.position, _target.position); // 업데이트할거에요 -> 뒤잡기 타이머를 (카운터 시스템에서 관리)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|