using System.Collections.Generic; using UnityEngine; namespace Unity.Cinemachine { /// /// Base class for a CinemachineCamera extension module. /// Hooks into the Cinemachine Pipeline. Use this to add extra processing /// to the vcam, modifying its generated state /// public abstract class CinemachineExtension : MonoBehaviour { /// /// Extensions that need to save per-vcam state should inherit from this class and add /// appropriate member variables. Use GetExtraState() to access. /// protected class VcamExtraStateBase { /// The virtual camera being modified by the extension public CinemachineVirtualCameraBase Vcam; } CinemachineVirtualCameraBase m_VcamOwner; Dictionary m_ExtraState; /// Useful constant for very small floats protected const float Epsilon = UnityVectorExtensions.Epsilon; /// Get the CinemachineVirtualCamera to which this extension is attached. /// This is distinct from the CinemachineCameras that the extension will modify, /// as extensions owned by manager cameras will be applied to all the CinemachineCamera children. public CinemachineVirtualCameraBase ComponentOwner { get { if (m_VcamOwner == null) TryGetComponent(out m_VcamOwner); return m_VcamOwner; } } /// Connect to virtual camera pipeline. /// Override implementations must call this base implementation protected virtual void Awake() => ConnectToVcam(true); /// Disconnect from virtual camera pipeline. /// Override implementations must call this base implementation protected virtual void OnDestroy() => ConnectToVcam(false); /// Does nothing. It's here for the little checkbox in the inspector. protected virtual void OnEnable() {} #if UNITY_EDITOR [UnityEditor.Callbacks.DidReloadScripts] static void OnScriptReload() { var extensions = Resources.FindObjectsOfTypeAll(); // Sort by execution order System.Array.Sort(extensions, (x, y) => UnityEditor.MonoImporter.GetExecutionOrder(UnityEditor.MonoScript.FromMonoBehaviour(y)) - UnityEditor.MonoImporter.GetExecutionOrder(UnityEditor.MonoScript.FromMonoBehaviour(x))); for (int i = 0; i < extensions.Length; ++i) extensions[i].ConnectToVcam(true); } #endif internal void EnsureStarted() => ConnectToVcam(true); /// Connect to virtual camera. Implementation must be safe to be called /// redundantly. Override implementations must call this base implementation /// True if connecting, false if disconnecting protected virtual void ConnectToVcam(bool connect) { if (ComponentOwner != null) { if (connect) ComponentOwner.AddExtension(this); else ComponentOwner.RemoveExtension(this); } m_ExtraState = null; } /// Override this to do such things as offset the ReferenceLookAt. /// Base class implementation does nothing. /// The virtual camera being processed /// Input state that must be mutated /// The current applicable deltaTime public virtual void PrePipelineMutateCameraStateCallback( CinemachineVirtualCameraBase vcam, ref CameraState curState, float deltaTime) {} /// Legacy support. This is only here to avoid changing the API /// to make PostPipelineStageCallback() public /// The virtual camera being processed /// The current pipeline stage /// The current virtual camera state /// The current applicable deltaTime public void InvokePostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { PostPipelineStageCallback(vcam, stage, ref state, deltaTime); } /// /// This callback will be called after the virtual camera has implemented /// each stage in the pipeline. This method may modify the referenced state. /// If deltaTime less than 0, reset all state info and perform no damping. /// /// The virtual camera being processed /// The current pipeline stage /// The current virtual camera state /// The current applicable deltaTime protected abstract void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime); /// This is called to notify the extension that a target got warped, /// so that the extension can update its internal state to make the camera /// also warp seamlessly. Base class implementation does nothing. /// Virtual camera to warp /// The object that was warped /// The amount the target's position changed public virtual void OnTargetObjectWarped( CinemachineVirtualCameraBase vcam, Transform target, Vector3 positionDelta) {} /// /// Force the virtual camera to assume a given position and orientation /// /// World-space position to take /// World-space orientation to take public virtual void ForceCameraPosition(Vector3 pos, Quaternion rot) {} /// Notification that this virtual camera is going live. /// Base class implementation must be called by any overridden method. /// The camera being deactivated. May be null. /// Default world Up, set by the CinemachineBrain /// Delta time for time-based effects (ignore if less than or equal to 0) /// True to request a vcam update of internal state public virtual bool OnTransitionFromCamera( ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime) => false; /// /// Report maximum damping time needed for this extension. /// Only used in editor for timeline scrubbing. /// /// Highest damping setting in this extension public virtual float GetMaxDampTime() => 0; /// Because extensions can be placed on manager cams and will in that /// case be called for all the vcam children, vcam-specific state information /// should be stored here. Just define a class to hold your state info /// and use it exclusively when calling this. /// /// The type of the extra state class /// The virtual camera being processed /// The extra state, cast as type T protected T GetExtraState(CinemachineVirtualCameraBase vcam) where T : VcamExtraStateBase, new() { if (m_ExtraState == null) m_ExtraState = new (); if (!m_ExtraState.TryGetValue(vcam, out var extra)) extra = m_ExtraState[vcam] = new T { Vcam = vcam}; return extra as T; } /// Get all extra state info for all vcams. /// The extra state type /// The list that will get populated with the extra states. protected void GetAllExtraStates(List list) where T : VcamExtraStateBase, new() { list.Clear(); if (m_ExtraState != null) { var iter = m_ExtraState.GetEnumerator(); while (iter.MoveNext()) list.Add(iter.Current.Value as T); } } } }