mirror of
https://github.com/Cardidi/dotween-upm-fork.git
synced 2025-12-20 09:16:02 +08:00
500 lines
21 KiB
C#
500 lines
21 KiB
C#
// Author: Daniele Giardini - http://www.demigiant.com
|
|
// Created: 2014/07/05 18:31
|
|
//
|
|
// License Copyright (c) Daniele Giardini.
|
|
// This work is subject to the terms at http://dotween.demigiant.com/license.php
|
|
|
|
using DG.Tweening.Core;
|
|
using DG.Tweening.Core.Easing;
|
|
using DG.Tweening.Plugins.Core.PathCore;
|
|
using DG.Tweening.Plugins.Options;
|
|
using UnityEngine;
|
|
|
|
#pragma warning disable 1573
|
|
namespace DG.Tweening
|
|
{
|
|
/// <summary>
|
|
/// Methods that extend Tween objects and allow to control or get data from them
|
|
/// </summary>
|
|
public static class TweenExtensions
|
|
{
|
|
// ===================================================================================
|
|
// TWEENERS + SEQUENCES --------------------------------------------------------------
|
|
|
|
#region Runtime Operations
|
|
|
|
/// <summary>Completes the tween</summary>
|
|
public static void Complete(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.Complete(t);
|
|
}
|
|
|
|
/// <summary>Flips the direction of this tween (backwards if it was going forward or viceversa)</summary>
|
|
public static void Flip(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.Flip(t);
|
|
}
|
|
|
|
/// <summary>Forces the tween to initialize its settings immediately</summary>
|
|
public static void ForceInit(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.ForceInit(t);
|
|
}
|
|
|
|
/// <summary>Send the tween to the given position in time</summary>
|
|
/// <param name="to">Time position to reach
|
|
/// (if higher than the whole tween duration the tween will simply reach its end)</param>
|
|
/// <param name="andPlay">If TRUE will play the tween after reaching the given position, otherwise it will pause it</param>
|
|
public static void Goto(this Tween t, float to, bool andPlay = false)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
if (to < 0) to = 0;
|
|
TweenManager.Goto(t, to, andPlay);
|
|
}
|
|
|
|
/// <summary>Kills the tween</summary>
|
|
/// <param name="complete">If TRUE completes the tween before killing it</param>
|
|
public static void Kill(this Tween t, bool complete = false)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
if (complete) {
|
|
TweenManager.Complete(t);
|
|
if (t.autoKill) return; // Already killed by Complete, so no need to go on
|
|
}
|
|
|
|
if (TweenManager.isUpdateLoop) {
|
|
// Just mark it for killing, so the update loop will take care of it
|
|
t.active = false;
|
|
} else TweenManager.Despawn(t);
|
|
}
|
|
|
|
/// <summary>Pauses the tween</summary>
|
|
public static T Pause<T>(this T t) where T : Tween
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return t;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return t;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return t;
|
|
}
|
|
|
|
TweenManager.Pause(t);
|
|
return t;
|
|
}
|
|
|
|
/// <summary>Plays the tween</summary>
|
|
public static T Play<T>(this T t) where T : Tween
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return t;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return t;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return t;
|
|
}
|
|
|
|
TweenManager.Play(t);
|
|
return t;
|
|
}
|
|
|
|
/// <summary>Sets the tween in a backwards direction and plays it</summary>
|
|
public static void PlayBackwards(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.PlayBackwards(t);
|
|
}
|
|
|
|
/// <summary>Sets the tween in a forward direction and plays it</summary>
|
|
public static void PlayForward(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.PlayForward(t);
|
|
}
|
|
|
|
/// <summary>Restarts the tween from the beginning</summary>
|
|
/// <param name="includeDelay">If TRUE includes the eventual tween delay, otherwise skips it</param>
|
|
public static void Restart(this Tween t, bool includeDelay = true)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.Restart(t, includeDelay);
|
|
}
|
|
|
|
/// <summary>Rewinds the tween</summary>
|
|
/// <param name="includeDelay">If TRUE includes the eventual tween delay, otherwise skips it</param>
|
|
public static void Rewind(this Tween t, bool includeDelay = true)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.Rewind(t, includeDelay);
|
|
}
|
|
|
|
/// <summary>Plays the tween if it was paused, pauses it if it was playing</summary>
|
|
public static void TogglePause(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenManager.TogglePause(t);
|
|
}
|
|
|
|
#region Path Tweens
|
|
|
|
/// <summary>Send a path tween to the given waypoint.
|
|
/// Has no effect if this is not a path tween.
|
|
/// <para>BEWARE, this is a special utility method:
|
|
/// it works only with Linear eases. Also, the lookAt direction might be wrong after calling this and might need to be set manually
|
|
/// (because it relies on a smooth path movement and doesn't work well with jumps that encompass dramatic direction changes)</para></summary>
|
|
/// <param name="waypointIndex">Waypoint index to reach
|
|
/// (if higher than the max waypoint index the tween will simply go to the last one)</param>
|
|
/// <param name="andPlay">If TRUE will play the tween after reaching the given waypoint, otherwise it will pause it</param>
|
|
public static void GotoWaypoint(this Tween t, int waypointIndex, bool andPlay = false)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return;
|
|
}
|
|
|
|
TweenerCore<Vector3, Path, PathOptions> pathTween = t as TweenerCore<Vector3, Path, PathOptions>;
|
|
if (pathTween == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNonPathTween(t); return;
|
|
}
|
|
|
|
if (!t.startupDone) TweenManager.ForceInit(t); // Initialize the tween if it's not initialized already (required)
|
|
if (waypointIndex < 0) waypointIndex = 0;
|
|
else if (waypointIndex > pathTween.changeValue.wps.Length - 1) waypointIndex = pathTween.changeValue.wps.Length - 1;
|
|
// Find path percentage relative to given waypoint
|
|
float wpLength = 0; // Total length from start to the given waypoint
|
|
for (int i = 0; i < waypointIndex + 1; i++) wpLength += pathTween.changeValue.wpLengths[i];
|
|
float wpPerc = wpLength / pathTween.changeValue.length;
|
|
// Convert to time taking eventual inverse direction into account
|
|
bool useInversePosition = t.loopType == LoopType.Yoyo
|
|
&& (t.position < t.duration ? t.completedLoops % 2 != 0 : t.completedLoops % 2 == 0);
|
|
if (useInversePosition) wpPerc = 1 - wpPerc;
|
|
float to = (t.isComplete ? t.completedLoops - 1 : t.completedLoops) * t.duration + wpPerc * t.duration;
|
|
TweenManager.Goto(t, to, andPlay);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Yield Coroutines
|
|
|
|
/// <summary>
|
|
/// Creates a yield instruction that waits until the tween is killed or complete.
|
|
/// It can be used inside a coroutine as a yield.
|
|
/// <para>Example usage:</para><code>yield return myTween.WaitForCompletion();</code>
|
|
/// </summary>
|
|
public static YieldInstruction WaitForCompletion(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return null;
|
|
}
|
|
|
|
return DOTween.instance.StartCoroutine(DOTween.instance.WaitForCompletion(t));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a yield instruction that waits until the tween is killed or rewinded.
|
|
/// It can be used inside a coroutine as a yield.
|
|
/// <para>Example usage:</para><code>yield return myTween.WaitForRewind();</code>
|
|
/// </summary>
|
|
public static YieldInstruction WaitForRewind(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return null;
|
|
}
|
|
|
|
return DOTween.instance.StartCoroutine(DOTween.instance.WaitForRewind(t));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a yield instruction that waits until the tween is killed.
|
|
/// It can be used inside a coroutine as a yield.
|
|
/// <para>Example usage:</para><code>yield return myTween.WaitForKill();</code>
|
|
/// </summary>
|
|
public static YieldInstruction WaitForKill(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return null;
|
|
}
|
|
|
|
return DOTween.instance.StartCoroutine(DOTween.instance.WaitForKill(t));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a yield instruction that waits until the tween is killed or has gone through the given amount of loops.
|
|
/// It can be used inside a coroutine as a yield.
|
|
/// <para>Example usage:</para><code>yield return myTween.WaitForElapsedLoops(2);</code>
|
|
/// </summary>
|
|
/// <param name="elapsedLoops">Elapsed loops to wait for</param>
|
|
public static YieldInstruction WaitForElapsedLoops(this Tween t, int elapsedLoops)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return null;
|
|
}
|
|
|
|
return DOTween.instance.StartCoroutine(DOTween.instance.WaitForElapsedLoops(t, elapsedLoops));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a yield instruction that waits until the tween is killed or has reached the given position (loops included, delays excluded).
|
|
/// It can be used inside a coroutine as a yield.
|
|
/// <para>Example usage:</para><code>yield return myTween.WaitForPosition(2.5f);</code>
|
|
/// </summary>
|
|
/// <param name="position">Position (loops included, delays excluded) to wait for</param>
|
|
public static YieldInstruction WaitForPosition(this Tween t, float position)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return null;
|
|
}
|
|
|
|
return DOTween.instance.StartCoroutine(DOTween.instance.WaitForPosition(t, position));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a yield instruction that waits until the tween is killed or started
|
|
/// (meaning when the tween is set in a playing state the first time, after any eventual delay).
|
|
/// It can be used inside a coroutine as a yield.
|
|
/// <para>Example usage:</para><code>yield return myTween.WaitForStart();</code>
|
|
/// </summary>
|
|
public static Coroutine WaitForStart(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return null;
|
|
}
|
|
|
|
return DOTween.instance.StartCoroutine(DOTween.instance.WaitForStart(t));
|
|
}
|
|
#endregion
|
|
|
|
#region Info Getters
|
|
|
|
/// <summary>Returns the total number of loops completed by this tween</summary>
|
|
public static int CompletedLoops(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return 0;
|
|
}
|
|
|
|
return t.completedLoops;
|
|
}
|
|
|
|
/// <summary>Returns the eventual delay set for this tween</summary>
|
|
public static float Delay(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return 0;
|
|
}
|
|
|
|
return t.delay;
|
|
}
|
|
|
|
/// <summary>Returns the duration of this tween (delays excluded).
|
|
/// <para>NOTE: when using settings like SpeedBased, the duration will be recalculated when the tween starts</para></summary>
|
|
/// <param name="includeLoops">If TRUE returns the full duration loops included,
|
|
/// otherwise the duration of a single loop cycle</param>
|
|
public static float Duration(this Tween t, bool includeLoops = true)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return 0;
|
|
}
|
|
|
|
// Calculate duration here instead than getting fullDuration because fullDuration might
|
|
// not be set yet, since it's set inside DoStartup
|
|
if (includeLoops) return t.loops == -1 ? Mathf.Infinity : t.duration * t.loops;
|
|
return t.duration;
|
|
}
|
|
|
|
/// <summary>Returns the elapsed time for this tween (delays exluded)</summary>
|
|
/// <param name="includeLoops">If TRUE returns the elapsed time since startup loops included,
|
|
/// otherwise the elapsed time within the current loop cycle</param>
|
|
public static float Elapsed(this Tween t, bool includeLoops = true)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return 0;
|
|
}
|
|
|
|
if (includeLoops) {
|
|
int loopsToCount = t.position >= t.duration ? t.completedLoops - 1 : t.completedLoops;
|
|
return (loopsToCount * t.duration) + t.position;
|
|
}
|
|
return t.position;
|
|
}
|
|
/// <summary>Returns the elapsed percentage (0 to 1) of this tween (delays exluded)</summary>
|
|
/// <param name="includeLoops">If TRUE returns the elapsed percentage since startup loops included,
|
|
/// otherwise the elapsed percentage within the current loop cycle</param>
|
|
public static float ElapsedPercentage(this Tween t, bool includeLoops = true)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return 0;
|
|
}
|
|
|
|
if (includeLoops) {
|
|
int loopsToCount = t.position >= t.duration ? t.completedLoops - 1 : t.completedLoops;
|
|
return ((loopsToCount * t.duration) + t.position) / t.fullDuration;
|
|
}
|
|
return t.position / t.duration;
|
|
}
|
|
|
|
/// <summary>Returns FALSE if this tween has been killed.
|
|
/// <para>BEWARE: if this tween is recyclable it might have been spawned again for another use and thus return TRUE anyway.</para>
|
|
/// When working with recyclable tweens you should take care to know when a tween has been killed and manually set your references to NULL.
|
|
/// If you want to be sure your references are set to NULL when a tween is killed you can use the <code>OnKill</code> callback like this:
|
|
/// <para><code>.OnKill(()=> myTweenReference = null)</code></para></summary>
|
|
public static bool IsActive(this Tween t)
|
|
{
|
|
return t.active;
|
|
}
|
|
|
|
/// <summary>Returns TRUE if this tween was reversed and is set to go backwards</summary>
|
|
public static bool IsBackwards(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return false;
|
|
}
|
|
|
|
return t.isBackwards;
|
|
}
|
|
|
|
/// <summary>Returns TRUE if the tween is complete
|
|
/// (silently fails and returns FALSE if the tween has been killed)</summary>
|
|
public static bool IsComplete(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return false;
|
|
}
|
|
|
|
return t.isComplete;
|
|
}
|
|
|
|
/// <summary>Returns TRUE if this tween is playing</summary>
|
|
public static bool IsPlaying(this Tween t)
|
|
{
|
|
if (!t.active) {
|
|
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
|
|
return false;
|
|
}
|
|
|
|
return t.isPlaying;
|
|
}
|
|
|
|
#region Path Tweens
|
|
|
|
/// <summary>
|
|
/// Returns the length of a path (returns -1 if this is not a path tween, if the tween is invalid, or if the path is not yet initialized).
|
|
/// A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature).
|
|
/// You can force a path to be initialized by calling <code>myTween.ForceInit()</code>.
|
|
/// </summary>
|
|
public static float PathLength(this Tween t)
|
|
{
|
|
if (t == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNullTween(t); return -1;
|
|
} else if (!t.active) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return -1;
|
|
} else if (t.isSequenced) {
|
|
if (Debugger.logPriority > 1) Debugger.LogInvalidTween(t); return -1;
|
|
}
|
|
|
|
TweenerCore<Vector3, Path, PathOptions> pathTween = t as TweenerCore<Vector3, Path, PathOptions>;
|
|
if (pathTween == null) {
|
|
if (Debugger.logPriority > 1) Debugger.LogNonPathTween(t); return -1;
|
|
} else if (!pathTween.endValue.isFinalized) {
|
|
if (Debugger.logPriority > 1) Debugger.LogWarning("The path is not finalized yet"); return -1;
|
|
}
|
|
|
|
return pathTween.endValue.length;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
} |