카메라 흔들림

This commit is contained in:
윤기주_playm 2026-01-30 15:30:27 +09:00
parent 75462cab9b
commit 5e4e9dc6bf
7 changed files with 59987 additions and 34 deletions

View File

@ -62447,7 +62447,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
healthSource: {fileID: 2112919314}
hpFillImage: {fileID: 0}
hpFillImage: {fileID: 910004995}
hpText: {fileID: 0}
--- !u!1001 &603601734
PrefabInstance:
@ -81844,6 +81844,10 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: df5024494d479b4498082208d661953d, type: 3}
m_Name:
m_EditorClassIdentifier:
_vCam: {fileID: 398512783}
defaultFOV: 60
zoomedFOV: 45
zoomSpeed: 5
--- !u!4 &797851020
Transform:
m_ObjectHideFlags: 0
@ -81911,7 +81915,7 @@ MonoBehaviour:
m_DissipationMode: 2
m_DissipationDistance: 100
m_PropagationSpeed: 343
m_DefaultVelocity: {x: 1, y: 0, z: 0}
m_DefaultVelocity: {x: 1, y: 1, z: 0}
--- !u!1001 &798036354
PrefabInstance:
m_ObjectHideFlags: 0
@ -146817,6 +146821,7 @@ MonoBehaviour:
aim: {fileID: 1432447528}
interaction: {fileID: 1432447532}
attack: {fileID: 1432447527}
statsUI: {fileID: 0}
--- !u!114 &1432447530
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@ -57,14 +57,21 @@ ModelImporter:
bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
curves: []
events:
- time: 0.5073891
- time: 0.60481036
functionName: StartWeaponCollision
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.7897755
- time: 0.6131805
functionName: OnAttackShake
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.8470821
functionName: StopWeaponCollision
data:
objectReferenceParameter: {instanceID: 0}
@ -107,13 +114,20 @@ ModelImporter:
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.5366044
- time: 0.44848183
functionName: StartWeaponCollision
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.4597701
functionName: OnAttackShake
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.8300493
functionName: StartWeaponCollision
data:
@ -157,13 +171,20 @@ ModelImporter:
bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
curves: []
events:
- time: 0.15307902
- time: 0.13009052
functionName: StartWeaponCollision
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.14239462
functionName: OnAttackShake
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.5402832
functionName: StopWeaponCollision
data:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,12 +11,11 @@ public class PlayerAttack : MonoBehaviour
[Header("--- 설정 ---")]
[SerializeField] private float attackCooldown = 0.5f;
[SerializeField] private float fullChargeTime = 2f; // 차징 기준 시간
[SerializeField] private float fullChargeTime = 2f;
private float _lastAttackTime, _chargeTimer;
private bool _isCharging;
// UI와 이동 스크립트에서 참조하는 통로
public float ChargeProgress => Mathf.Clamp01(_chargeTimer / fullChargeTime);
public bool IsCharging => _isCharging;
@ -25,12 +24,7 @@ public class PlayerAttack : MonoBehaviour
if (_isCharging)
{
_chargeTimer += Time.deltaTime;
if (Input.GetMouseButtonDown(1))
{
CancelCharging();
Debug.Log("차징 취소됨");
}
if (Input.GetMouseButtonDown(1)) { CancelCharging(); Debug.Log("차징 취소됨"); }
}
}
@ -42,8 +36,20 @@ public class PlayerAttack : MonoBehaviour
pAnim.TriggerAttack();
_lastAttackTime = Time.time;
// ❌ 여기서 ShakeAttack()을 호출하지 않습니다. (애니메이션 이벤트로 이동)
}
// ⭐ [추가] 애니메이션 이벤트에서 실제 타격 시점에 호출할 함수
public void OnAttackShake()
{
Debug.Log("<color=cyan>[Event]</color> 타격 타이밍! 카메라 흔들기 명령 전송");
if (CinemachineShake.Instance != null)
{
CinemachineShake.Instance.ShakeAttack(); // 애니메이션 타이밍에 맞춰 쾅!
}
}
// (기존 StartWeaponCollision, StopWeaponCollision 로직 유지...)
public void StartWeaponCollision()
{
if (interaction.CurrentWeapon == null || weaponHitBox == null) return;
@ -63,7 +69,7 @@ public class PlayerAttack : MonoBehaviour
pAnim.TriggerThrow();
pAnim.SetCharging(false);
// 1. 레이캐스트 정밀 조준
// 레이캐스트 조준 로직
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, transform.position);
float rayDistance;
@ -78,25 +84,22 @@ public class PlayerAttack : MonoBehaviour
if (targetDirection != Vector3.zero) transform.rotation = Quaternion.LookRotation(targetDirection);
// 2. ⭐ [핵심 수정] 무기 컨피그에서 데이터 직접 가져오기
// 차징 시간에 따라 단계를 나눕니다. (1초 미만 Lv1, 1~2초 Lv2, 2초 이상 Lv3)
// 차징 레벨 계산 및 무기 던지기
int lv = _chargeTimer >= 2f ? 3 : (_chargeTimer >= 1f ? 2 : 1);
// WeaponConfig에 있는 GetSpread와 GetForce 함수를 사용합니다.
float currentSpread = interaction.CurrentWeapon.Config.GetSpread(lv);
float throwForce = interaction.CurrentWeapon.Config.GetForce(lv);
// 3. 정확도(Spread)가 적용된 최종 방향 계산
Vector3 finalThrowDir = Quaternion.Euler(0, Random.Range(-currentSpread, currentSpread), 0) * targetDirection;
// 무기 던지기 실행
interaction.CurrentWeapon.OnThrown(finalThrowDir, throwForce, lv, stats);
// 상태 초기화
// 상태 초기화 및 카메라 효과
interaction.ClearCurrentWeapon();
stats.ResetWeight();
_isCharging = false;
_chargeTimer = 0f;
CinemachineShake.Instance.SetZoom(false);
CinemachineShake.Instance.ShakeAttack(); // 강공격도 묵직하게 흔들어줌
}
public void StartCharging()
@ -106,6 +109,7 @@ public class PlayerAttack : MonoBehaviour
_isCharging = true;
_chargeTimer = 0f;
pAnim.SetCharging(true);
CinemachineShake.Instance.SetZoom(true);
}
public void CancelCharging()
@ -113,5 +117,6 @@ public class PlayerAttack : MonoBehaviour
_isCharging = false;
_chargeTimer = 0f;
if (pAnim != null) pAnim.SetCharging(false);
CinemachineShake.Instance.SetZoom(false);
}
}

View File

@ -1,24 +1,69 @@
using UnityEngine;
using Cinemachine;
using System.Collections;
public class CinemachineShake : MonoBehaviour
{
public static CinemachineShake Instance { get; private set; }
[Header("--- 컴포넌트 연결 ---")]
private CinemachineImpulseSource _impulseSource;
[SerializeField] private CinemachineVirtualCamera _vCam;
[Header("--- 줌 설정 ---")]
[SerializeField] private float defaultFOV = 60f;
[SerializeField] private float zoomedFOV = 45f;
[SerializeField] private float zoomSpeed = 5f;
private Coroutine _zoomCoroutine;
private void Awake()
{
Instance = this;
_impulseSource = GetComponent<CinemachineImpulseSource>();
// ⭐ 가상 카메라가 연결 안 되어 있으면 자동으로 찾아보는 안전장치
if (_vCam == null) _vCam = GetComponent<CinemachineVirtualCamera>();
}
// ⭐ 힘 부족 시 호출할 도리도리 (좌우 흔들림)
// 1. ⭐ [수정] 일반 공격 흔들림 (수직으로 묵직하게!)
public void ShakeAttack()
{
if (_impulseSource == null) return;
// Vector3.down 방향으로 힘을 주어 아래로 쾅! 찍는 느낌을 줍니다.
_impulseSource.GenerateImpulse(Vector3.down * 0.5f);
}
// 2. ⭐ [수정] 힘 부족 시 도리도리 (수평으로 가볍게!)
public void ShakeNoNo()
{
if (_impulseSource == null) return;
// Vector3.right 방향으로 신호를 주어 좌우로 흔들리게 합니다.
_impulseSource.GenerateImpulse(Vector3.right * 0.5f);
// Vector3.right 방향으로 힘을 주어 고개를 좌우로 흔드는 느낌을 줍니다.
_impulseSource.GenerateImpulse(Vector3.right * 0.4f);
Debug.Log("<color=red>[Shake]</color> 힘 수치 부족! 도리도리 실행");
}
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;
}
}