using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using Cinemachine;
using MoreMountains.Feedbacks;
namespace MoreMountains.FeedbacksForThirdParty
{
///
/// This class will allow you to trigger zooms on your cinemachine camera by sending MMCameraZoomEvents from any other class
///
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MMCinemachineZoom")]
[RequireComponent(typeof(Cinemachine.CinemachineVirtualCamera))]
public class MMCinemachineZoom : MonoBehaviour
{
public int Channel = 0;
[Header("Transition Speed")]
/// the animation curve to apply to the zoom transition
[Tooltip("the animation curve to apply to the zoom transition")]
public AnimationCurve ZoomCurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f));
[Header("Test Zoom")]
/// the mode to apply the zoom in when using the test button in the inspector
[Tooltip("the mode to apply the zoom in when using the test button in the inspector")]
public MMCameraZoomModes TestMode;
/// the target field of view to apply the zoom in when using the test button in the inspector
[Tooltip("the target field of view to apply the zoom in when using the test button in the inspector")]
public float TestFieldOfView = 30f;
/// the transition duration to apply the zoom in when using the test button in the inspector
[Tooltip("the transition duration to apply the zoom in when using the test button in the inspector")]
public float TestTransitionDuration = 0.1f;
/// the duration to apply the zoom in when using the test button in the inspector
[Tooltip("the duration to apply the zoom in when using the test button in the inspector")]
public float TestDuration = 0.05f;
[MMFInspectorButton("TestZoom")]
/// an inspector button to test the zoom in play mode
public bool TestZoomButton;
public virtual float GetTime() { return (TimescaleMode == TimescaleModes.Scaled) ? Time.time : Time.unscaledTime; }
public virtual float GetDeltaTime() { return (TimescaleMode == TimescaleModes.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime; }
public TimescaleModes TimescaleMode { get; set; }
protected Cinemachine.CinemachineVirtualCamera _virtualCamera;
protected float _initialFieldOfView;
protected MMCameraZoomModes _mode;
protected bool _zooming = false;
protected float _startFieldOfView;
protected float _transitionDuration;
protected float _duration;
protected float _targetFieldOfView;
protected float _delta = 0f;
protected int _direction = 1;
protected float _reachedDestinationTimestamp;
protected bool _destinationReached = false;
///
/// On Awake we grab our virtual camera
///
protected virtual void Awake()
{
_virtualCamera = this.gameObject.GetComponent();
_initialFieldOfView = _virtualCamera.m_Lens.FieldOfView;
}
///
/// On Update if we're zooming we modify our field of view accordingly
///
protected virtual void Update()
{
if (!_zooming)
{
return;
}
if (_virtualCamera.m_Lens.FieldOfView != _targetFieldOfView)
{
_delta += GetDeltaTime() / _transitionDuration;
_virtualCamera.m_Lens.FieldOfView = Mathf.LerpUnclamped(_startFieldOfView, _targetFieldOfView, ZoomCurve.Evaluate(_delta));
}
else
{
if (!_destinationReached)
{
_reachedDestinationTimestamp = GetTime();
_destinationReached = true;
}
if ((_mode == MMCameraZoomModes.For) && (_direction == 1))
{
if (GetTime() - _reachedDestinationTimestamp > _duration)
{
_direction = -1;
_startFieldOfView = _targetFieldOfView;
_targetFieldOfView = _initialFieldOfView;
_delta = 0f;
}
}
else
{
_zooming = false;
}
}
}
///
/// A method that triggers the zoom, ideally only to be called via an event, but public for convenience
///
///
///
///
///
public virtual void Zoom(MMCameraZoomModes mode, float newFieldOfView, float transitionDuration, float duration, bool useUnscaledTime, bool relative = false)
{
if (_zooming)
{
return;
}
_zooming = true;
_delta = 0f;
_mode = mode;
TimescaleMode = useUnscaledTime ? TimescaleModes.Unscaled : TimescaleModes.Scaled;
_startFieldOfView = _virtualCamera.m_Lens.FieldOfView;
_transitionDuration = transitionDuration;
_duration = duration;
_transitionDuration = transitionDuration;
_direction = 1;
_destinationReached = false;
switch (mode)
{
case MMCameraZoomModes.For:
_targetFieldOfView = newFieldOfView;
break;
case MMCameraZoomModes.Set:
_targetFieldOfView = newFieldOfView;
break;
case MMCameraZoomModes.Reset:
_targetFieldOfView = _initialFieldOfView;
break;
}
if (relative)
{
_targetFieldOfView += _initialFieldOfView;
}
}
///
/// The method used by the test button to trigger a test zoom
///
protected virtual void TestZoom()
{
Zoom(TestMode, TestFieldOfView, TestTransitionDuration, TestDuration, false);
}
///
/// When we get an MMCameraZoomEvent we call our zoom method
///
///
public virtual void OnCameraZoomEvent(MMCameraZoomModes mode, float newFieldOfView, float transitionDuration, float duration, int channel, bool useUnscaledTime, bool stop = false, bool relative = false)
{
if ((channel != Channel) && (channel != -1) && (Channel != -1))
{
return;
}
if (stop)
{
_zooming = false;
return;
}
this.Zoom(mode, newFieldOfView, transitionDuration, duration, useUnscaledTime, relative);
}
///
/// Starts listening for MMCameraZoomEvents
///
protected virtual void OnEnable()
{
MMCameraZoomEvent.Register(OnCameraZoomEvent);
}
///
/// Stops listening for MMCameraZoomEvents
///
protected virtual void OnDisable()
{
MMCameraZoomEvent.Unregister(OnCameraZoomEvent);
}
}
}