Projext/Assets/02_Scripts/Enemy/BossAI/NorcielBoss.Tracking.cs
hydrozen e989d20668 카툰 쉐이더 추가 + 중복 스크립트 수정 + 전체 업데이트
- ToonPostProcess.shader: 횃불 고딕 스타일 후처리 쉐이더 (Built-in RP)
- ToonCameraEffect.cs: 카메라 자동 부착 후처리 스크립트
- 중복 UI 스크립트 제거 (MenuIntroController, ToggleCustom)
- 씬, 프리팹, 애니메이션 등 전체 업데이트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:31:16 +09:00

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); // 업데이트할거에요 -> 뒤잡기 타이머를 (카운터 시스템에서 관리)
}
}
}