Projext/Assets/Scripts/Camera/Effects/CamShake.cs

88 lines
6.8 KiB
C#
Raw Permalink Normal View History

2026-02-12 15:23:25 +00:00
using UnityEngine; // 유니티 기본 기능(Time, Vector3, Coroutine 등)을 쓰기 위해 불러올거에요 -> UnityEngine를
using Cinemachine; // 시네머신 카메라/임펄스 기능을 쓰기 위해 불러올거에요 -> Cinemachine을
using System.Collections; // 코루틴(IEnumerator)을 쓰기 위해 불러올거에요 -> System.Collections를
2026-02-12 15:23:25 +00:00
public class CinemachineShake : MonoBehaviour // 클래스를 선언할거에요 -> 카메라 흔들림/줌/히트슬로우를 담당하는 CinemachineShake를
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
public static CinemachineShake Instance { get; private set; } // 프로퍼티를 선언할거에요 -> 싱글톤 인스턴스를 외부에서 읽기만 가능하게
2026-01-30 06:30:27 +00:00
2026-02-12 15:23:25 +00:00
[Header("--- 컴포넌트 연결 ---")] // 인스펙터에 제목을 표시할거에요 -> 컴포넌트 연결 섹션을
private CinemachineImpulseSource _impulseSource; // 변수를 선언할거에요 -> 임펄스(카메라 흔들림) 발사기 컴포넌트를 담을 _impulseSource를
[SerializeField] private CinemachineVirtualCamera _vCam; // 변수를 선언할거에요 -> 조절할 가상 카메라를 담을 _vCam을
2026-01-30 06:30:27 +00:00
2026-02-12 15:23:25 +00:00
[Header("--- 줌 설정 ---")] // 인스펙터에 제목을 표시할거에요 -> 줌 설정 섹션을
2026-02-22 13:37:34 +00:00
[Tooltip("줌 시 FOV 변화량 (음수 = 줌인, 양수 = 줌아웃). 예: -15면 기본FOV에서 15만큼 줌인")]
[SerializeField] private float zoomFOVOffset = -15f; // 변수를 선언할거에요 -> 줌 시 FOV 변화량을 (기본 FOV에서 이만큼 더하기)
2026-02-12 15:23:25 +00:00
[SerializeField] private float zoomSpeed = 5f; // 변수를 선언할거에요 -> 줌 보간 속도를 zoomSpeed에
2026-02-22 13:37:34 +00:00
private float _defaultFOV; // 변수를 선언할거에요 -> 게임 시작 시 자동 저장되는 기본 FOV를
2026-02-12 15:23:25 +00:00
private Coroutine _zoomCoroutine; // 변수를 선언할거에요 -> 현재 실행 중인 줌 코루틴을 담을 _zoomCoroutine을
2026-02-12 15:23:25 +00:00
private void Awake() // 함수를 선언할거에요 -> 오브젝트가 켜질 때 1번 실행되는 Awake를
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
Instance = this; // 값을 넣을거에요 -> 싱글톤 인스턴스를 자기 자신으로 설정
_impulseSource = GetComponent<CinemachineImpulseSource>(); // 컴포넌트를 가져올거에요 -> 내 오브젝트에서 임펄스 소스를 찾아 저장
if (_vCam == null) _vCam = GetComponent<CinemachineVirtualCamera>(); // 조건이 맞으면 실행할거에요 -> vCam이 비어있으면 내 오브젝트에서 찾아 채우기
2026-01-30 07:45:11 +00:00
2026-02-22 13:37:34 +00:00
// [FIX] 게임 시작 시 Virtual Camera의 실제 FOV를 읽어서 기본값으로 저장
if (_vCam != null) // 조건이 맞으면 실행할거에요 -> 카메라가 있다면
{
_defaultFOV = _vCam.m_Lens.FieldOfView; // 값을 저장할거에요 -> 인스펙터에 설정된 실제 FOV를 기본값으로
Debug.Log($"[CinemachineShake] 기본 FOV 자동 감지: {_defaultFOV}"); // 로그를 출력할거에요 -> 감지된 FOV 값을
}
}
// ⭐ 렉 없는 타격감: 시간을 0.1배속으로 늘림 (Hit-Slow)
2026-02-12 15:23:25 +00:00
public void HitSlow(float duration = 0.15f, float timeScale = 0.1f) // 함수를 선언할거에요 -> duration/timeScale로 히트슬로우를 주는 HitSlow를
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
StartCoroutine(DoHitSlow(duration, timeScale)); // 코루틴을 실행할거에요 -> 실제 슬로우 처리를 하는 DoHitSlow를
2026-02-22 13:37:34 +00:00
}
2026-01-30 07:45:11 +00:00
2026-02-12 15:23:25 +00:00
private IEnumerator DoHitSlow(float duration, float timeScale) // 코루틴 함수를 선언할거에요 -> 히트슬로우를 수행하는 DoHitSlow를
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
Time.timeScale = timeScale; // 값을 바꿀거에요 -> 전체 게임 시간을 느리게(멈춤은 아님)
yield return new WaitForSecondsRealtime(duration); // 기다릴거에요 -> 실제 시간 기준으로 duration만큼
Time.timeScale = 1.0f; // 값을 복구할거에요 -> 게임 시간을 정상(1)으로
2026-02-22 13:37:34 +00:00
}
2026-01-30 07:45:11 +00:00
2026-02-22 13:37:34 +00:00
// ⭐ 카메라 킥: 순간적으로 FOV를 확 줄여 충격을 줌
2026-02-12 15:23:25 +00:00
public void CameraKick(float kickAmount = 8f) // 함수를 선언할거에요 -> FOV를 순간 감소시키는 CameraKick을
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
if (_vCam == null) return; // 조건이 맞으면 종료할거에요 -> 카메라가 없으면 처리 불가
_vCam.m_Lens.FieldOfView -= kickAmount; // 값을 바꿀거에요 -> FOV를 줄여서 순간 줌인 효과
SetZoom(false); // 함수를 실행할거에요 -> 기본 FOV로 부드럽게 돌아가도록 줌 애니메이션 시작
2026-02-22 13:37:34 +00:00
}
2026-02-12 15:23:25 +00:00
public void ShakeAttack() // 함수를 선언할거에요 -> 공격용 흔들림을 주는 ShakeAttack을
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
if (_impulseSource == null) return; // 조건이 맞으면 종료할거에요 -> 임펄스 소스가 없으면 불가
_impulseSource.GenerateImpulse(Vector3.down * 1.5f); // 임펄스를 발생시킬거에요 -> 아래 방향으로 강하게 흔들기
2026-02-22 13:37:34 +00:00
}
2026-01-30 06:30:27 +00:00
2026-02-12 15:23:25 +00:00
public void ShakeNoNo() // 함수를 선언할거에요 -> 좌우로 살짝 흔드는 ShakeNoNo를
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
if (_impulseSource == null) return; // 조건이 맞으면 종료할거에요 -> 임펄스 소스가 없으면 불가
_impulseSource.GenerateImpulse(Vector3.right * 0.4f); // 임펄스를 발생시킬거에요 -> 오른쪽 방향으로 약하게 흔들기
2026-02-22 13:37:34 +00:00
}
2026-01-30 06:30:27 +00:00
2026-02-12 15:23:25 +00:00
public void SetZoom(bool isZooming) // 함수를 선언할거에요 -> 줌인/줌아웃 목표를 설정하는 SetZoom을
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
if (_vCam == null) return; // 조건이 맞으면 종료할거에요 -> 카메라가 없으면 불가
if (_zoomCoroutine != null) StopCoroutine(_zoomCoroutine); // 조건이 맞으면 실행할거에요 -> 기존 줌 코루틴이 있으면 중지해서 중첩 방지
2026-02-22 13:37:34 +00:00
// [FIX] 줌 목표 = 기본 FOV + offset (줌인 시), 기본 FOV (줌아웃 시)
float targetFOV = isZooming ? _defaultFOV + zoomFOVOffset : _defaultFOV; // 목표 FOV를 정할거에요 -> 줌이면 기본FOV+오프셋, 아니면 기본FOV
2026-02-12 15:23:25 +00:00
_zoomCoroutine = StartCoroutine(AnimateZoom(targetFOV)); // 코루틴을 실행할거에요 -> 목표 FOV로 부드럽게 이동하는 AnimateZoom을
2026-02-22 13:37:34 +00:00
}
2026-02-12 15:23:25 +00:00
private IEnumerator AnimateZoom(float target) // 코루틴 함수를 선언할거에요 -> FOV를 목표값까지 보간하는 AnimateZoom을
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
if (_vCam == null) yield break; // 조건이 맞으면 중단할거에요 -> 카메라가 없으면 코루틴 종료
while (Mathf.Abs(_vCam.m_Lens.FieldOfView - target) > 0.1f) // 반복할거에요 -> 현재 FOV가 목표값과 충분히 가까워질 때까지
2026-02-22 13:37:34 +00:00
{
2026-02-12 15:23:25 +00:00
_vCam.m_Lens.FieldOfView = Mathf.Lerp(_vCam.m_Lens.FieldOfView, target, Time.deltaTime * zoomSpeed); // 값을 보간할거에요 -> 현재 FOV를 target 쪽으로 부드럽게
yield return null; // 다음 프레임까지 기다릴거에요 -> 프레임 단위로 갱신
2026-02-22 13:37:34 +00:00
}
2026-02-12 15:23:25 +00:00
_vCam.m_Lens.FieldOfView = target; // 값을 확정할거에요 -> 마지막에 정확히 target으로 맞추기
2026-02-22 13:37:34 +00:00
}
}