using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을
public class PlayerAnimator : MonoBehaviour // 클래스를 선언할거에요 -> MonoBehaviour를 상속받는 PlayerAnimator를
{
[SerializeField] private Animator anim; // 변수를 선언할거에요 -> 애니메이터 컴포넌트 anim을
[SerializeField] private PlayerHealth health; // 변수를 선언할거에요 -> 플레이어 체력 스크립트 health를
// ⭐ 추가: 진짜 공격 로직이 있는 스크립트 연결
[SerializeField] private PlayerAttack attack; // 변수를 선언할거에요 -> 플레이어 공격 스크립트 attack을
// ── [v8] 일반 공격 애니메이션 속도 배율 ──────────────────────
[Header("=== 일반 공격 애니메이션 속도 ===")]
[Tooltip("일반 공격(좌클릭) 시 Throw 애니메이션 재생 속도 배율\n" +
"1.0 = 원본 속도, 2.0 = 2배 빠르게, 3.0 = 3배 빠르게\n" +
"연사가 빠를수록 높여야 애니메이션이 안 밀려요\n" +
"추천: 2.5~4.0")]
[Range(1f, 6f)]
[SerializeField] private float normalAttackAnimSpeed = 3.0f; // 변수를 선언할거에요 -> 일반 공격 시 애니 속도 배율을 (3배속 = 연사에 맞게 빠르게)
// ── 내부 캐싱 ──────────────────────────────────────────────
private float _defaultAnimSpeed = 1f; // 변수를 선언할거에요 -> 원본 애니메이터 속도를 저장할 변수를
private void Awake() // 함수를 실행할거에요 -> 스크립트 시작 시 Awake를
{
if (anim != null) _defaultAnimSpeed = anim.speed; // 저장할거에요 -> 애니메이터의 원본 속도를 (나중에 복원용)
if (health != null) // 조건이 맞으면 실행할거에요 -> 체력 스크립트가 있다면
{
health.OnHitEvent += () => anim.SetTrigger("Hit"); // 이벤트를 구독할거에요 -> 피격 시 Hit 트리거 발동을
health.OnDead += () => anim.SetBool("Die", true); // 이벤트를 구독할거에요 -> 사망 시 Die 상태 변경을
}
}
// ---------------------------------------------------------
// ⭐ [애니메이션 이벤트 전달자]
// 애니메이션 창에 적은 이름과 똑같은 함수를 만듭니다.
// ---------------------------------------------------------
public void StartWeaponCollision() // 함수를 선언할거에요 -> 무기 충돌 시작 이벤트 StartWeaponCollision을
{
if (attack != null) attack.StartWeaponCollision(); // 실행할거에요 -> 공격 스크립트의 충돌 시작 함수를
}
public void StopWeaponCollision() // 함수를 선언할거에요 -> 무기 충돌 종료 이벤트 StopWeaponCollision을
{
if (attack != null) attack.StopWeaponCollision(); // 실행할거에요 -> 공격 스크립트의 충돌 종료 함수를
}
// ---------------------------------------------------------
public void UpdateMove(float speedValue) => anim.SetFloat("Speed", speedValue); // 값을 전달할거에요 -> 애니메이터의 Speed 파라미터에
// ── 기존 TriggerThrow (차징 공격용 — 원본 속도 재생) ────────
// Throw 트리거는 Animator Parameters에서 모든 레이어가 공유하므로
// Draw 레이어의 트랜지션 조건에 Throw가 있으면 정상 동작해요
public void TriggerThrow() // 함수를 선언할거에요 -> 차징 발사 시 Throw 트리거를 발동하는
{
if (anim == null) return; // 방어할거에요 -> 애니메이터가 없으면 스킵
anim.speed = _defaultAnimSpeed; // 복원할거에요 -> 차징 공격은 원본 속도로 재생 (일반 공격의 빠른 속도가 남아있을 수 있음)
anim.SetTrigger("Throw"); // 신호를 보낼거에요 -> 애니메이터의 Throw 트리거에
}
// ══════════════════════════════════════════════════════════
// [v8 신규] 일반 공격 전용 — 빠른 애니메이션 재생
// ══════════════════════════════════════════════════════════
//
// 문제: TriggerThrow()는 트리거 방식이라 이전 애니가 끝나야 다음이 재생됨
// → 연사 시 애니메이션이 화살 발사 속도를 못 따라감
//
// 해결: CrossFadeInFixedTime()으로 현재 애니를 강제 끊고 처음부터 재시작
// + 애니메이터 speed를 빠르게 올려서 쿨타임 안에 재생 완료
// + 애니 끝나면 원래 속도로 자동 복원
// ══════════════════════════════════════════════════════════
///
/// [v8] 일반 공격 시 호출 — Throw 애니메이션을 원래 속도로 강제 재시작해요.
/// 이전 애니가 재생 중이어도 즉시 끊고 처음부터 다시 재생해요.
/// 속도는 변경하지 않으므로 활 당기는 모션이 자연스럽게 보여요.
///
public void PlayFastThrow() // 함수를 선언할거에요 -> Throw 애니메이션 강제 재시작을
{
if (anim == null) return; // 방어할거에요 -> 애니메이터가 없으면 스킵
// ── 1. 애니메이터 속도를 빠르게 설정 ──────────────────
// 화살은 즉시 발사되므로, 애니메이션도 빠르게 재생해야 시각적으로 맞아요
// normalAttackAnimSpeed (기본 3.0f) 배율로 빠르게 재생
anim.speed = normalAttackAnimSpeed; // 설정할거에요 -> 애니메이터 속도를 빠른 속도로 (연사에 맞게)
// ── 2. Draw 레이어(1번)에서 p_walk 애니메이션 강제 재시작 ──
// CrossFadeInFixedTime: 현재 어떤 애니가 재생 중이든 즉시 전환
// 트리거 방식은 이전 애니 끝나야 다음이 재생돼서 연사 시 밀림
// CrossFade는 재생 중이던 애니를 즉시 끊고 처음부터 다시 시작해요
// → 클릭할 때마다 활 쏘는 모션이 처음부터 보여요!
// 0.02f = 전환 블렌딩 시간 (거의 즉시 전환, 약간의 부드러움 유지)
// 1 = 레이어 1 (Draw Layer — 공격 애니메이션이 있는 레이어)
// 0f = 애니메이션 시작 지점 (처음부터)
anim.CrossFadeInFixedTime("p_walk", 0.02f, 1, 0f); // 재생할거에요 -> Draw 레이어의 p_walk 애니를 처음부터 즉시 강제 전환으로
// ── 3. 밀린 트리거 초기화 ────────────────────────────────
// 이전에 SetTrigger("Throw")가 쌓여있을 수 있으니 리셋해서
// 애니메이션이 중복 재생되는 것을 방지해요
anim.ResetTrigger("Throw"); // 초기화할거에요 -> 쌓여있던 Throw 트리거를 비우기
}
///
/// [v8] 빠른 공격 애니메이션 종료 후 원래 속도로 복원해요.
/// AttackRoutine 끝날 때 호출해서 이동 애니 등이 정상 속도로 재생되게 해요.
///
public void ResetAnimSpeed() // 함수를 선언할거에요 -> 애니메이터 속도를 원래대로 복원하는
{
if (anim == null) return; // 방어할거에요 -> 애니메이터가 없으면 스킵
anim.speed = _defaultAnimSpeed; // 복원할거에요 -> 애니메이터 속도를 원본으로 (보통 1.0)
}
// ─────────────────────────────────────────────────────────
// ⭐ 애니메이션 이벤트 전달자 — 활 관련 사운드
// FBX Throw 애니메이션 Events에 아래 함수 이름으로 등록해줘요
// ─────────────────────────────────────────────────────────
public void OnBowDraw() // 함수를 선언할거에요 -> 활 당기는 순간 소리 재생을 (애니메이션 이벤트)
{
if (attack != null) attack.PlayBowDrawSound(); // 실행할거에요 -> 활 당기는 소리를
}
public void SetCharging(bool isCharging) => anim.SetBool("isCharging", isCharging); // 값을 설정할거에요 -> 애니메이터의 isCharging 불리언에
}