2026-01-29 16:11:10 +00:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using Cinemachine;
|
2026-01-30 06:30:27 +00:00
|
|
|
|
using System.Collections;
|
2026-01-29 16:11:10 +00:00
|
|
|
|
|
|
|
|
|
|
public class CinemachineShake : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
public static CinemachineShake Instance { get; private set; }
|
2026-01-30 06:30:27 +00:00
|
|
|
|
|
|
|
|
|
|
[Header("--- 컴포넌트 연결 ---")]
|
2026-01-29 16:11:10 +00:00
|
|
|
|
private CinemachineImpulseSource _impulseSource;
|
2026-01-30 06:30:27 +00:00
|
|
|
|
[SerializeField] private CinemachineVirtualCamera _vCam;
|
|
|
|
|
|
|
|
|
|
|
|
[Header("--- 줌 설정 ---")]
|
|
|
|
|
|
[SerializeField] private float defaultFOV = 60f;
|
|
|
|
|
|
[SerializeField] private float zoomedFOV = 45f;
|
|
|
|
|
|
[SerializeField] private float zoomSpeed = 5f;
|
|
|
|
|
|
|
|
|
|
|
|
private Coroutine _zoomCoroutine;
|
2026-01-29 16:11:10 +00:00
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
_impulseSource = GetComponent<CinemachineImpulseSource>();
|
2026-01-30 06:30:27 +00:00
|
|
|
|
|
|
|
|
|
|
// ⭐ 가상 카메라가 연결 안 되어 있으면 자동으로 찾아보는 안전장치
|
|
|
|
|
|
if (_vCam == null) _vCam = GetComponent<CinemachineVirtualCamera>();
|
2026-01-29 16:11:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 06:30:27 +00:00
|
|
|
|
// 1. ⭐ [수정] 일반 공격 흔들림 (수직으로 묵직하게!)
|
|
|
|
|
|
public void ShakeAttack()
|
2026-01-29 16:11:10 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (_impulseSource == null) return;
|
2026-01-30 06:30:27 +00:00
|
|
|
|
// Vector3.down 방향으로 힘을 주어 아래로 쾅! 찍는 느낌을 줍니다.
|
|
|
|
|
|
_impulseSource.GenerateImpulse(Vector3.down * 0.5f);
|
|
|
|
|
|
}
|
2026-01-29 16:11:10 +00:00
|
|
|
|
|
2026-01-30 06:30:27 +00:00
|
|
|
|
// 2. ⭐ [수정] 힘 부족 시 도리도리 (수평으로 가볍게!)
|
|
|
|
|
|
public void ShakeNoNo()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_impulseSource == null) return;
|
|
|
|
|
|
// Vector3.right 방향으로 힘을 주어 고개를 좌우로 흔드는 느낌을 줍니다.
|
|
|
|
|
|
_impulseSource.GenerateImpulse(Vector3.right * 0.4f);
|
2026-01-29 16:11:10 +00:00
|
|
|
|
Debug.Log("<color=red>[Shake]</color> 힘 수치 부족! 도리도리 실행");
|
|
|
|
|
|
}
|
2026-01-30 06:30:27 +00:00
|
|
|
|
|
|
|
|
|
|
public void SetZoom(bool isZooming)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ⭐ [에러 방지] 카메라가 없으면 코루틴을 실행하지 않음
|
|
|
|
|
|
if (_vCam == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (_zoomCoroutine != null) StopCoroutine(_zoomCoroutine);
|
|
|
|
|
|
float targetFOV = isZooming ? zoomedFOV : defaultFOV;
|
|
|
|
|
|
_zoomCoroutine = StartCoroutine(AnimateZoom(targetFOV));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator AnimateZoom(float target)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ⭐ [에러 방지] 실행 중 카메라가 사라질 경우 대비
|
|
|
|
|
|
if (_vCam == null) yield break;
|
|
|
|
|
|
|
|
|
|
|
|
while (Mathf.Abs(_vCam.m_Lens.FieldOfView - target) > 0.1f)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_vCam == null) yield break;
|
|
|
|
|
|
_vCam.m_Lens.FieldOfView = Mathf.Lerp(_vCam.m_Lens.FieldOfView, target, Time.deltaTime * zoomSpeed);
|
|
|
|
|
|
yield return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
_vCam.m_Lens.FieldOfView = target;
|
|
|
|
|
|
}
|
2026-01-29 16:11:10 +00:00
|
|
|
|
}
|