145 lines
9.6 KiB
C#
145 lines
9.6 KiB
C#
using System.Collections.Generic; // 리스트 기능을 사용할거에요 -> System.Collections.Generic을
|
|
using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을
|
|
|
|
/// <summary>
|
|
/// 플레이어의 전투 행동을 슬라이딩 윈도우(최근 N초) 기반으로 추적합니다.
|
|
/// </summary>
|
|
public class PlayerBehaviorTracker : MonoBehaviour // 클래스를 선언할거에요 -> MonoBehaviour를 상속받는 PlayerBehaviorTracker를
|
|
{
|
|
public static PlayerBehaviorTracker Instance { get; private set; } // 프로퍼티를 선언할거에요 -> 싱글톤 인스턴스 접근용 Instance를
|
|
|
|
[Header("슬라이딩 윈도우 설정")] // 인스펙터 창에 제목을 표시할거에요 -> 슬라이딩 윈도우 설정 을
|
|
[Tooltip("행동 추적 윈도우 크기(초)")] // 마우스를 올리면 설명을 보여줄거에요 -> 툴팁 내용을
|
|
[SerializeField] private float windowDuration = 10f; // 변수를 선언할거에요 -> 추적 시간 범위(10초)를 windowDuration에
|
|
|
|
// ── 내부 기록용 타임스탬프 리스트 ──
|
|
private List<float> dodgeTimestamps = new List<float>(); // 리스트를 만들거에요 -> 회피 시간들을 저장할 dodgeTimestamps를
|
|
private List<float> aimStartTimes = new List<float>(); // 리스트를 만들거에요 -> 조준 시작 시간들을 저장할 aimStartTimes를
|
|
private List<float> aimEndTimes = new List<float>(); // 리스트를 만들거에요 -> 조준 종료 시간들을 저장할 aimEndTimes를
|
|
private List<float> pierceShotTimestamps = new List<float>(); // 리스트를 만들거에요 -> 관통샷 시간들을 저장할 pierceShotTimestamps를
|
|
private List<float> totalShotTimestamps = new List<float>(); // 리스트를 만들거에요 -> 전체 사격 시간들을 저장할 totalShotTimestamps를
|
|
|
|
// ── 현재 조준 상태 ──
|
|
private bool isAiming = false; // 변수를 초기화할거에요 -> 조준 중 여부를 거짓(false)으로
|
|
private float currentAimStartTime; // 변수를 선언할거에요 -> 현재 조준 시작 시간을 저장할 currentAimStartTime을
|
|
|
|
// ── 외부에서 읽는 프로퍼티 ──
|
|
public int DodgeCount => CountInWindow(dodgeTimestamps); // 값을 반환할거에요 -> 최근 회피 횟수를 계산해서
|
|
public float AimHoldTime => CalculateAimHoldTime(); // 값을 반환할거에요 -> 최근 조준 유지 시간을 계산해서
|
|
public float PierceRatio => CalculatePierceRatio(); // 값을 반환할거에요 -> 최근 관통샷 비율을 계산해서
|
|
public int TotalShotsInWindow => CountInWindow(totalShotTimestamps); // 값을 반환할거에요 -> 최근 총 발사 횟수를 계산해서
|
|
|
|
private void Awake() // 함수를 실행할거에요 -> 스크립트 시작 시 호출되는 Awake를
|
|
{
|
|
if (Instance != null && Instance != this) // 조건이 맞으면 실행할거에요 -> 이미 다른 인스턴스가 존재한다면
|
|
{
|
|
Destroy(gameObject); // 파괴할거에요 -> 중복된 이 오브젝트를
|
|
return; // 중단할거에요 -> 초기화 로직을
|
|
}
|
|
Instance = this; // 값을 저장할거에요 -> 내 자신(this)을 싱글톤 인스턴스에
|
|
}
|
|
|
|
// ═══════════════════════════════════════════
|
|
// 외부에서 호출하는 이벤트 기록 메서드
|
|
// ═══════════════════════════════════════════
|
|
|
|
/// <summary>플레이어가 회피(대시/구르기)를 수행했을 때 호출</summary>
|
|
public void RecordDodge() // 함수를 선언할거에요 -> 회피를 기록하는 RecordDodge를
|
|
{
|
|
dodgeTimestamps.Add(Time.time); // 추가할거에요 -> 현재 시간을 회피 목록에
|
|
}
|
|
|
|
/// <summary>플레이어가 조준을 시작했을 때 호출</summary>
|
|
public void RecordAimStart() // 함수를 선언할거에요 -> 조준 시작을 기록하는 RecordAimStart를
|
|
{
|
|
if (!isAiming) // 조건이 맞으면 실행할거에요 -> 이미 조준 중이 아니라면
|
|
{
|
|
isAiming = true; // 상태를 바꿀거에요 -> 조준 중 상태를 참(true)으로
|
|
currentAimStartTime = Time.time; // 값을 저장할거에요 -> 현재 시간을 조준 시작 시간으로
|
|
}
|
|
}
|
|
|
|
/// <summary>플레이어가 조준을 해제했을 때 호출</summary>
|
|
public void RecordAimEnd() // 함수를 선언할거에요 -> 조준 종료를 기록하는 RecordAimEnd를
|
|
{
|
|
if (isAiming) // 조건이 맞으면 실행할거에요 -> 조준 중이었다면
|
|
{
|
|
isAiming = false; // 상태를 바꿀거에요 -> 조준 중 상태를 거짓(false)으로
|
|
aimStartTimes.Add(currentAimStartTime); // 추가할거에요 -> 시작 시간을 리스트에
|
|
aimEndTimes.Add(Time.time); // 추가할거에요 -> 종료(현재) 시간을 리스트에
|
|
}
|
|
}
|
|
|
|
/// <summary>화살 발사 시 호출. isPierce=true면 관통 화살</summary>
|
|
public void RecordShot(bool isPierce) // 함수를 선언할거에요 -> 발사를 기록하는 RecordShot을
|
|
{
|
|
totalShotTimestamps.Add(Time.time); // 추가할거에요 -> 현재 시간을 전체 사격 목록에
|
|
if (isPierce) // 조건이 맞으면 실행할거에요 -> 관통 화살이라면
|
|
{
|
|
pierceShotTimestamps.Add(Time.time); // 추가할거에요 -> 현재 시간을 관통 사격 목록에
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════
|
|
// 런 리셋 (새 런 시작 시 호출)
|
|
// ═══════════════════════════════════════════
|
|
|
|
/// <summary>새 런 시작 시 모든 행동 기록을 초기화</summary>
|
|
public void ResetForNewRun() // 함수를 선언할거에요 -> 모든 기록을 초기화하는 ResetForNewRun을
|
|
{
|
|
dodgeTimestamps.Clear(); // 비울거에요 -> 회피 기록을
|
|
aimStartTimes.Clear(); // 비울거에요 -> 조준 시작 기록을
|
|
aimEndTimes.Clear(); // 비울거에요 -> 조준 종료 기록을
|
|
pierceShotTimestamps.Clear(); // 비울거에요 -> 관통 사격 기록을
|
|
totalShotTimestamps.Clear(); // 비울거에요 -> 전체 사격 기록을
|
|
isAiming = false; // 초기화할거에요 -> 조준 상태를 거짓(false)으로
|
|
}
|
|
|
|
// ═══════════════════════════════════════════
|
|
// 내부 계산
|
|
// ═══════════════════════════════════════════
|
|
|
|
private int CountInWindow(List<float> timestamps) // 함수를 선언할거에요 -> 윈도우 내 개수를 세는 CountInWindow를
|
|
{
|
|
float cutoff = Time.time - windowDuration; // 값을 계산할거에요 -> 현재 시간에서 윈도우 크기를 뺀 기준 시간을
|
|
timestamps.RemoveAll(t => t < cutoff); // 삭제할거에요 -> 기준 시간보다 오래된 기록들을 리스트에서
|
|
return timestamps.Count; // 반환할거에요 -> 남은 기록의 개수를
|
|
}
|
|
|
|
private float CalculateAimHoldTime() // 함수를 선언할거에요 -> 총 조준 시간을 계산하는 CalculateAimHoldTime을
|
|
{
|
|
float cutoff = Time.time - windowDuration; // 값을 계산할거에요 -> 기준 시간(현재 - 윈도우)을
|
|
float total = 0f; // 변수를 초기화할거에요 -> 총 시간을 0으로
|
|
|
|
// 완료된 조준 세션
|
|
for (int i = aimStartTimes.Count - 1; i >= 0; i--) // 반복할거에요 -> 저장된 조준 기록들을 역순으로
|
|
{
|
|
if (aimEndTimes[i] < cutoff) // 조건이 맞으면 실행할거에요 -> 종료 시간이 기준보다 옛날이라면
|
|
{
|
|
aimStartTimes.RemoveAt(i); // 삭제할거에요 -> 해당 시작 기록을
|
|
aimEndTimes.RemoveAt(i); // 삭제할거에요 -> 해당 종료 기록을
|
|
continue; // 건너뛸거에요 -> 다음 반복으로
|
|
}
|
|
float start = Mathf.Max(aimStartTimes[i], cutoff); // 값을 계산할거에요 -> 시작 시간과 기준 시간 중 더 최근 것을
|
|
total += aimEndTimes[i] - start; // 값을 더할거에요 -> 유효한 조준 기간을 총 시간에
|
|
}
|
|
|
|
// 현재 조준 중인 시간도 포함
|
|
if (isAiming) // 조건이 맞으면 실행할거에요 -> 현재 조준 중이라면
|
|
{
|
|
float start = Mathf.Max(currentAimStartTime, cutoff); // 값을 계산할거에요 -> 조준 시작과 기준 중 최근 것을
|
|
total += Time.time - start; // 값을 더할거에요 -> 지금까지의 조준 시간을 총 시간에
|
|
}
|
|
|
|
return total; // 반환할거에요 -> 계산된 총 조준 시간을
|
|
}
|
|
|
|
private float CalculatePierceRatio() // 함수를 선언할거에요 -> 관통 비율을 계산하는 CalculatePierceRatio를
|
|
{
|
|
int totalShots = CountInWindow(totalShotTimestamps); // 값을 가져올거에요 -> 최근 총 발사 횟수를
|
|
if (totalShots == 0) return 0f; // 조건이 맞으면 반환할거에요 -> 발사 기록이 없으면 0을
|
|
|
|
int pierceShots = CountInWindow(pierceShotTimestamps); // 값을 가져올거에요 -> 최근 관통 발사 횟수를
|
|
return (float)pierceShots / totalShots; // 반환할거에요 -> 관통 횟수 나누기 전체 횟수(비율)를
|
|
}
|
|
} |