// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using System.Linq; using UltimateXR.Animation.Interpolation; using UltimateXR.Attributes; using UltimateXR.Core.Components; using UltimateXR.Extensions.System.Collections; using UnityEngine; namespace UltimateXR.Animation.UI { /// /// /// Base abstract class to create tweening components to animate Unity UI elements. /// /// /// Tweens are components to allow access to the global list of tweens /// or filter by type. /// /// /// They are also to allow access to the global list of tweens in a /// given parent canvas. /// /// public abstract class UxrTween : UxrComponent { #region Inspector Properties/Serialized Fields [SerializeField] [ReadOnly(HideInEditMode = true)] private bool _hasFinished; [SerializeField] private UxrInterpolationSettings _interpolationSettings = new UxrInterpolationSettings(); [SerializeField] private UxrTweenFinishedActions _finishedActions = UxrTweenFinishedActions.None; #endregion #region Public Types & Data /// /// Called when the animation finished. /// public event Action Finished; /// /// Gets the current animation time in seconds. The animation time is the scaled or unscaled time relative to the time /// the component was enabled. /// public float AnimationTime => CurrentTime - _startTime; /// /// Gets or sets the interpolation settings. /// public UxrInterpolationSettings InterpolationSettings { get => _interpolationSettings; protected set => _interpolationSettings = value; } /// /// Gets whether the animation finished. /// public bool HasFinished { get => _hasFinished; private set => _hasFinished = value; } #endregion #region Public Methods /// /// Checks if the given behaviour has a running tween of any type. /// /// Whether there is a running tween animation. public static bool HasActiveTween(Behaviour behaviour) { UxrTween[] tweens = behaviour.GetComponents(); return tweens.Length > 0 && tweens.Any(t => !t.HasFinished); } /// /// Checks if the given behaviour has a running tween of a specific type. /// /// Type of s to check for. /// Whether there is a running animation of the given type. public static bool HasActiveTween(Behaviour behaviour) where T : UxrTween { T tween = behaviour.GetComponent(); return tween && !tween.HasFinished; } /// /// Stops all enabled tweens. /// /// Whether to reset each animated component to the state before its animation started public static void StopAll(bool restoreOriginal = true) { EnabledComponents.ForEach(t => t.Stop(restoreOriginal)); } /// /// Stops all enabled tweens of a given type. /// /// Whether to reset each animated component to the state before its animation started /// Type of s to stop public static void StopAll(bool restoreOriginal = true) where T : UxrTween { EnabledComponents.OfType().ForEach(t => t.Stop(restoreOriginal)); } /// /// Stops all enabled tweens that are in a given canvas. /// /// Canvas to disable all enabled tweens from /// Whether to reset each animated component to the state before its animation started public static void StopAllInParentCanvas(Canvas canvas, bool restoreOriginal = true) { GetParentChildren(canvas).ForEach(t => t.Stop(restoreOriginal)); } /// /// Stops all enabled tweens of a given type that are in a given canvas. /// /// Whether to reset each animated component to the state before its animation started /// Canvas to disable all enabled tweens from /// Type of s to stop public static void StopAllInParentCanvas(Canvas canvas, bool restoreOriginal = true) where T : UxrTween { GetParentChildren(canvas).OfType().ForEach(t => t.Stop(restoreOriginal)); } /// /// Stops all the tweening components of a . /// /// whose tweens to stop /// Whether to reset each animated component to the state before its animation started public static void StopAll(Behaviour behaviour, bool restoreOriginal = true) { foreach (UxrTween tween in behaviour.gameObject.GetComponents()) { tween.Stop(restoreOriginal); } } /// /// Stops the tweening animation on an object if it has a component currently added. /// /// UI Component whose GameObject has the tween added /// Whether to reset the animated component to the state before the animation started /// Type of to stop public static void Stop(Behaviour behaviour, bool restoreOriginal = true) where T : UxrTween { T tween = behaviour.GetComponent(); if (tween) { tween.Stop(restoreOriginal); } } /// /// Stops the tweening animation. /// /// Whether to reset the animated component to the state before the animation started public void Stop(bool restoreOriginal = true) { HasFinished = true; if (restoreOriginal) { RestoreOriginalValue(); } } /// /// Sets the actions to perform when the animation finished. /// /// Action flags /// The component to concatenate additional calls if desired. public UxrTween SetFinishedActions(UxrTweenFinishedActions actions) { _finishedActions = actions; return this; } #endregion #region Unity /// /// Stores the start time each time the component is enabled. /// protected override void OnEnable() { base.OnEnable(); _startTime = CurrentTime; if (!HasOriginalValueStored) { HasOriginalValueStored = true; StoreOriginalValue(); } if (InterpolationSettings != null) { Interpolate(InterpolationSettings.GetInterpolationFactor(0.0f)); } HasFinished = false; } /// /// Updates the interpolation. /// private void Update() { if (HasFinished || InterpolationSettings == null) { return; } Interpolate(InterpolationSettings.GetInterpolationFactor(AnimationTime)); if (InterpolationSettings.CheckInterpolationHasFinished(AnimationTime)) { Interpolate(1.0f); HasFinished = true; OnFinished(); } } #endregion #region Event Trigger Methods /// /// Event trigger for the event. /// protected virtual void OnFinished() { Finished?.Invoke(); FinishedCallback?.Invoke(this); if (_finishedActions.HasFlag(UxrTweenFinishedActions.RestoreOriginalValue)) { RestoreOriginalValue(); } if (_finishedActions.HasFlag(UxrTweenFinishedActions.DisableTargetComponent) && TargetBehaviour) { TargetBehaviour.enabled = false; } if (_finishedActions.HasFlag(UxrTweenFinishedActions.DeactivateGameObject) && TargetBehaviour && TargetBehaviour.gameObject) { TargetBehaviour.gameObject.SetActive(false); } if (_finishedActions.HasFlag(UxrTweenFinishedActions.DestroyTween)) { Destroy(this); } if (_finishedActions.HasFlag(UxrTweenFinishedActions.DestroyTargetComponent) && TargetBehaviour) { Destroy(TargetBehaviour); } if (_finishedActions.HasFlag(UxrTweenFinishedActions.DestroyGameObject)) { Destroy(gameObject); } } #endregion #region Protected Methods /// /// Restores the animated component to the state before the animation started. /// protected abstract void RestoreOriginalValue(); /// /// Stores the original value before the animation, in order to be able to restore it later using /// . /// protected abstract void StoreOriginalValue(); /// /// Interpolates and assigns the value corresponding to the given LERP value. /// /// LERP interpolation t value [0.0, 1.0] protected abstract void Interpolate(float t); /// /// Restarts the animation with the current parameters. /// It also forces the execution of the first frame. /// protected void Restart() { if (InterpolationSettings != null) { _startTime = CurrentTime; _finishedActions = UxrTweenFinishedActions.None; HasFinished = false; Interpolate(InterpolationSettings.GetInterpolationFactor(0.0f)); } } #endregion #region Protected Types & Data /// /// Gets the the tween animates. /// protected abstract Behaviour TargetBehaviour { get; } /// /// Gets if the tween has gathered the original animated parameter value. /// protected bool HasOriginalValueStored { get; private set; } /// /// Optional finished callback assigned by child classes. /// protected Action FinishedCallback { get; set; } #endregion #region Private Types & Data /// /// Gets the current time in seconds. It computes the correct time, either or /// , depending on the animation configuration. /// private float CurrentTime { get { if (InterpolationSettings != null) { return InterpolationSettings.UseUnscaledTime ? Time.unscaledTime : Time.time; } return Time.time; } } private float _startTime; #endregion } }