using UnityEngine; namespace OnlyScove.Scripts { [System.Serializable] public class CameraShakeManager { [SerializeField] private bool useShake = true; [SerializeField] private float shakeFrequency = 25f; // How fast the shake oscillates [SerializeField] private AnimationCurve decayCurve = AnimationCurve.EaseInOut(0, 1, 1, 0); // How intensity decays over duration [Header("Fall Impact Settings")] [SerializeField] private bool enableFallImpactShake = true; [SerializeField] private float minFallHeightForShake = 2f; [SerializeField] private float maxFallHeightForShake = 10f; [SerializeField] private float minFallShakeIntensity = 0.5f; [SerializeField] private float maxFallShakeIntensity = 3f; [SerializeField] private float minFallShakeDuration = 0.2f; [SerializeField] private float maxFallShakeDuration = 0.8f; [SerializeField] private AnimationCurve fallHeightToIntensityCurve = AnimationCurve.Linear(0, 0, 1, 1); [SerializeField] private AnimationCurve fallHeightToDurationCurve = AnimationCurve.Linear(0, 0, 1, 1); private float _shakeIntensity = 0f; private float _shakeDuration = 0f; private float _shakeTimer = 0f; // Counts down from _shakeDuration private Vector3 _shakeOffset; public Vector3 ShakeOffset => _shakeOffset; public void HandleShake() { if (!useShake || _shakeTimer <= 0) { _shakeOffset = Vector3.zero; return; } _shakeTimer -= Time.deltaTime; float progress = 1f - (_shakeTimer / _shakeDuration); // 0 at start, 1 at end // Apply decay curve to intensity float currentIntensity = _shakeIntensity * decayCurve.Evaluate(progress); // Use shakeFrequency for Perlin noise float shakeX = (Mathf.PerlinNoise(Time.time * shakeFrequency, 0f) - 0.5f) * 2f; float shakeY = (Mathf.PerlinNoise(0f, Time.time * shakeFrequency) - 0.5f) * 2f; float shakeZ = (Mathf.PerlinNoise(Time.time * shakeFrequency, Time.time * shakeFrequency) - 0.5f) * 2f; _shakeOffset = new Vector3(shakeX, shakeY, shakeZ) * currentIntensity; } public void Shake(float intensity, float duration) { _shakeIntensity = intensity; _shakeDuration = duration; _shakeTimer = duration; // Reset timer } public void TriggerFallImpactShake(float fallHeight) { if (!enableFallImpactShake || fallHeight < minFallHeightForShake) return; // Normalize fall height between 0 and 1 relative to min/max thresholds float normalizedFallHeight = Mathf.InverseLerp(minFallHeightForShake, maxFallHeightForShake, fallHeight); // Calculate intensity and duration using curves and ranges float intensity = Mathf.Lerp(minFallShakeIntensity, maxFallShakeIntensity, fallHeightToIntensityCurve.Evaluate(normalizedFallHeight)); float duration = Mathf.Lerp(minFallShakeDuration, maxFallShakeDuration, fallHeightToDurationCurve.Evaluate(normalizedFallHeight)); Shake(intensity, duration); } } }