using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using MoreMountains.Feedbacks;
namespace MoreMountains.FeedbacksForThirdParty
{
///
/// Add this component to your Cinemachine Virtual Camera to have it shake when calling its ShakeCamera methods.
///
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MMCinemachineCameraShaker")]
[RequireComponent(typeof(CinemachineVirtualCamera))]
public class MMCinemachineCameraShaker : MonoBehaviour
{
[Header("Settings")]
/// the channel to receive events on
[Tooltip("the channel to receive events on")]
public int Channel = 0;
/// The default amplitude that will be applied to your shakes if you don't specify one
[Tooltip("The default amplitude that will be applied to your shakes if you don't specify one")]
public float DefaultShakeAmplitude = .5f;
/// The default frequency that will be applied to your shakes if you don't specify one
[Tooltip("The default frequency that will be applied to your shakes if you don't specify one")]
public float DefaultShakeFrequency = 10f;
/// the amplitude of the camera's noise when it's idle
[Tooltip("the amplitude of the camera's noise when it's idle")]
[MMFReadOnly]
public float IdleAmplitude;
/// the frequency of the camera's noise when it's idle
[Tooltip("the frequency of the camera's noise when it's idle")]
[MMFReadOnly]
public float IdleFrequency = 1f;
/// the speed at which to interpolate the shake
[Tooltip("the speed at which to interpolate the shake")]
public float LerpSpeed = 5f;
[Header("Test")]
/// a duration (in seconds) to apply when testing this shake via the TestShake button
[Tooltip("a duration (in seconds) to apply when testing this shake via the TestShake button")]
public float TestDuration = 0.3f;
/// the amplitude to apply when testing this shake via the TestShake button
[Tooltip("the amplitude to apply when testing this shake via the TestShake button")]
public float TestAmplitude = 2f;
/// the frequency to apply when testing this shake via the TestShake button
[Tooltip("the frequency to apply when testing this shake via the TestShake button")]
public float TestFrequency = 20f;
[MMFInspectorButton("TestShake")]
public bool TestShakeButton;
public virtual float GetTime() { return (_timescaleMode == TimescaleModes.Scaled) ? Time.time : Time.unscaledTime; }
public virtual float GetDeltaTime() { return (_timescaleMode == TimescaleModes.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime; }
protected TimescaleModes _timescaleMode;
protected Vector3 _initialPosition;
protected Quaternion _initialRotation;
protected Cinemachine.CinemachineBasicMultiChannelPerlin _perlin;
protected Cinemachine.CinemachineVirtualCamera _virtualCamera;
protected float _targetAmplitude;
protected float _targetFrequency;
private Coroutine _shakeCoroutine;
///
/// On awake we grab our components
///
protected virtual void Awake()
{
_virtualCamera = this.gameObject.GetComponent();
_perlin = _virtualCamera.GetCinemachineComponent();
}
///
/// On Start we reset our camera to apply our base amplitude and frequency
///
protected virtual void Start()
{
if (_perlin != null)
{
IdleAmplitude = _perlin.m_AmplitudeGain;
IdleFrequency = _perlin.m_FrequencyGain;
}
_targetAmplitude = IdleAmplitude;
_targetFrequency = IdleFrequency;
}
protected virtual void Update()
{
if (_perlin != null)
{
_perlin.m_AmplitudeGain = _targetAmplitude;
_perlin.m_FrequencyGain = Mathf.Lerp(_perlin.m_FrequencyGain, _targetFrequency, GetDeltaTime() * LerpSpeed);
}
}
///
/// Use this method to shake the camera for the specified duration (in seconds) with the default amplitude and frequency
///
/// Duration.
public virtual void ShakeCamera(float duration, bool infinite, bool useUnscaledTime = false)
{
StartCoroutine(ShakeCameraCo(duration, DefaultShakeAmplitude, DefaultShakeFrequency, infinite, useUnscaledTime));
}
///
/// Use this method to shake the camera for the specified duration (in seconds), amplitude and frequency
///
/// Duration.
/// Amplitude.
/// Frequency.
public virtual void ShakeCamera(float duration, float amplitude, float frequency, bool infinite, bool useUnscaledTime = false)
{
if (_shakeCoroutine != null)
{
StopCoroutine(_shakeCoroutine);
}
_shakeCoroutine = StartCoroutine(ShakeCameraCo(duration, amplitude, frequency, infinite, useUnscaledTime));
}
///
/// This coroutine will shake the
///
/// The camera co.
/// Duration.
/// Amplitude.
/// Frequency.
protected virtual IEnumerator ShakeCameraCo(float duration, float amplitude, float frequency, bool infinite, bool useUnscaledTime)
{
_targetAmplitude = amplitude;
_targetFrequency = frequency;
_timescaleMode = useUnscaledTime ? TimescaleModes.Unscaled : TimescaleModes.Scaled;
if (!infinite)
{
yield return new WaitForSeconds(duration);
CameraReset();
}
}
///
/// Resets the camera's noise values to their idle values
///
public virtual void CameraReset()
{
_targetAmplitude = IdleAmplitude;
_targetFrequency = IdleFrequency;
}
public virtual void OnCameraShakeEvent(float duration, float amplitude, float frequency, float amplitudeX, float amplitudeY, float amplitudeZ, bool infinite, int channel, bool useUnscaledTime)
{
if ((channel != Channel) && (channel != -1) && (Channel != -1))
{
return;
}
this.ShakeCamera(duration, amplitude, frequency, infinite, useUnscaledTime);
}
public virtual void OnCameraShakeStopEvent(int channel)
{
if ((channel != Channel) && (channel != -1) && (Channel != -1))
{
return;
}
if (_shakeCoroutine != null)
{
StopCoroutine(_shakeCoroutine);
}
CameraReset();
}
protected virtual void OnEnable()
{
MMCameraShakeEvent.Register(OnCameraShakeEvent);
MMCameraShakeStopEvent.Register(OnCameraShakeStopEvent);
}
protected virtual void OnDisable()
{
MMCameraShakeEvent.Unregister(OnCameraShakeEvent);
MMCameraShakeStopEvent.Unregister(OnCameraShakeStopEvent);
}
protected virtual void TestShake()
{
MMCameraShakeEvent.Trigger(TestDuration, TestAmplitude, TestFrequency, 0f, 0f, 0f, false, 0);
}
}
}