-
-
Save SimonDarksideJ/748ac92c3365d1fff79ac73148cee22a to your computer and use it in GitHub Desktop.
A Complete and Easy to use Tweens library in One File.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// | |
// _____ _ _____ | |
// |_ _|_|___ _ _ |_ _|_ _ _ ___ ___ ___ | |
// | | | | | | | | | | | | | -_| -_| | | |
// |_| |_|_|_|_ | |_| |_____|___|___|_|_| | |
// |___| | |
// A Complete and Easy to use Tweens library in One File | |
// | |
// Basic use: | |
// using FronkonGames.TinyTween; | |
// GameObject gameObject = new(); | |
// gameObject.TweenMove(new Vector3(10.0f, 0.0f, 0.0f), 1.0f, Ease.Bounce); | |
// | |
// Advanced use: | |
// using FronkonGames.TinyTween; | |
// GameObject clockHand = new(); | |
// TweenQuaternion.Create() | |
// .Origin(Quaternion.Euler(-30.0f, 0.0f, 0.0f)) | |
// .Destination(Quaternion.Euler(30.0f, 0.0f, 0.0f)) | |
// .Duration(1.0f) | |
// .Loop(TweenLoop.YoYo) | |
// .EasingIn(Ease.Back) | |
// .EasingOut(Ease.Elastic) | |
// .Owner(clockHand) | |
// .Condition(tween => tween.ExecutionCount < 10) | |
// .OnUpdate(tween => clockHand.transform.rotation = tween.Value) | |
// .OnEnd(() => Debug.Log("It's show time!")) | |
// .Start(); | |
// | |
// Copyright (c) 2022 Martin Bustos @FronkonGames <[email protected]> | |
// | |
// MIT License | |
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated | |
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the | |
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to | |
// permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of | |
// the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | |
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | |
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace FronkonGames.TinyTween | |
{ | |
/// <summary> State of a Tween operation. </summary> | |
public enum TweenState | |
{ | |
Running, Paused, Finished | |
} | |
/// <summary> Execution modes of a Tween operation. </summary> | |
public enum TweenLoop | |
{ | |
// Just once. Start over from the beginning. Back and forth loop. | |
Once, Loop, YoYo, | |
} | |
/// <summary> Interface of a tween. </summary> | |
public interface ITween | |
{ | |
/// <summary> Tween status. </summary> | |
TweenState State { get; } | |
/// <summary> Update the Tween operation. </summary> | |
void Update(); | |
} | |
/// <summary> Generic interface of a tween. </summary> | |
public interface ITween<T> : ITween where T : struct | |
{ | |
/// <summary> Current value. </summary> | |
T Value { get; } | |
/// <summary> Tween operation progress (0, 1). </summary> | |
float Progress { get; } | |
/// <summary> Executions counter. </summary> | |
int ExecutionCount { get; } | |
/// <summary> Tween status. </summary> | |
TweenState State { get; } | |
/// <summary> Execute a tween operation. </summary> | |
Tween<T> Start(); | |
/// <summary> Pause the tween. </summary> | |
void Pause(); | |
/// <summary> Continue the tween. </summary> | |
void Resume(); | |
/// <summary> Finish the Tween operation. </summary> | |
/// <param name="moveToEnd">Move the value at the end or leave it as this.</param> | |
void Stop(bool moveToEnd = true); | |
/// <summary> Sets tween value at origin and time to 0. </summary> | |
void Reset(); | |
/// <summary> Update the Tween operation. </summary> | |
void Update(); | |
} | |
/// <summary> Tween operation. If it is created manually, Update() must be called. </summary> | |
public abstract class Tween<T> : ITween<T> where T : struct | |
{ | |
/// <inheritdoc/> | |
public TweenState State { get; private set; } = TweenState.Paused; | |
/// <inheritdoc/> | |
public T Value { get; private set; } | |
/// <inheritdoc/> | |
public float Progress { get; private set; } | |
/// <inheritdoc/> | |
public int ExecutionCount { get; private set; } | |
/// <summary> Time that the operation takes. </summary> | |
public float Time { get; private set; } | |
/// <summary> Does the Tween depend on another object? </summary> | |
private bool IsOwned { get; set; } | |
private object owner = null; | |
private T origin, destination; | |
private Ease easeIn = Ease.None, easeOut = Ease.None; | |
private TweenLoop loop = TweenLoop.Once; | |
private float duration = 1.0f; | |
private float currentTime; | |
private bool clamp; | |
private int residueCount = -1; | |
private Action<Tween<T>> updateFunction; | |
private Action<Tween<T>> endFunction; | |
private Func<Tween<T>, bool> condition; | |
private readonly Func<Tween<T>, T, T, float, bool, T> interpolationFunction; // Tween, start, end, progress, clamp. | |
/// <summary> Constructor. </summary> | |
/// <param name="lerpFunc">Interpolation function.</param> | |
protected Tween(Func<Tween<T>, T, T, float, bool, T> interpolationFunction) => this.interpolationFunction = interpolationFunction; | |
/// <summary> Initial value. Use it only to create a new Tween. </summary> | |
/// <returns>This.</returns> | |
public Tween<T> Origin(T start) { origin = start; return this; } | |
/// <summary> Final value. Use it only to create a new Tween. </summary> | |
/// <returns>This.</returns> | |
public Tween<T> Destination(T end) { destination = end; return this; } | |
/// <summary> Time to execute the operation, must be greater than 0. Use it only to create a new Tween. </summary> | |
/// <returns>This.</returns> | |
public Tween<T> Duration(float duration) { this.duration = Mathf.Max(duration, 0.0f); return this; } | |
/// <summary> Execution mode. Use it only to create a new Tween. </summary> | |
/// <returns>This.</returns> | |
public Tween<T> Loop(TweenLoop loop) { this.loop = loop; return this; } | |
/// <summary> Easing function. Overwrite the In and Out functions. Use it only to create a new Tween. </summary> | |
/// <param name="ease">Easing function.</param> | |
/// <returns>This.</returns> | |
public Tween<T> Easing(Ease ease) { easeIn = easeOut = ease; return this; } | |
/// <summary> Easing In function. Use it only to create a new Tween. </summary> | |
/// <param name="ease">Easing function.</param> | |
/// <returns>This.</returns> | |
public Tween<T> EasingIn(Ease ease) { easeIn = ease; return this; } | |
/// <summary> Easing Out function. Use it only to create a new Tween. </summary> | |
/// <param name="ease">Easing function.</param> | |
/// <returns>This.</returns> | |
public Tween<T> EasingOut(Ease ease) { easeOut = ease; return this; } | |
/// <summary> Update callback. Use it to apply the Tween values. </summary> | |
/// <param name="updateCallback">Callback.</param> | |
/// <returns>This.</returns> | |
public Tween<T> OnUpdate(Action<Tween<T>> updateCallback) { updateFunction = updateCallback; return this; } | |
/// <summary> Executed at the end of the operation (optional). </summary> | |
/// <param name="endCallback">Callback.</param> | |
/// <returns>This.</returns> | |
public Tween<T> OnEnd(Action<Tween<T>> endCallback) { endFunction = endCallback; return this; } | |
/// <summary> Condition of progress, stops if the operation is not true (optional). </summary> | |
/// <param name="condition">Condition function.</param> | |
/// <returns>This.</returns> | |
public Tween<T> Condition(Func<Tween<T>, bool> condition) { this.condition = condition; return this; } | |
/// <summary> Limits the values of the interpolation to the range [0, 1]. </summary> | |
/// <param name="clamp">Clamp.</param> | |
/// <returns>This.</returns> | |
public Tween<T> Clamp(bool clamp) { this.clamp = clamp; return this; } | |
/// <summary> | |
/// I set an object as the 'owner' of the Tween. If the object is destroyed, the Tween ends and is destroyed. | |
/// </summary> | |
/// <param name="owner">Owner</param> | |
/// <returns>This.</returns> | |
public Tween<T> Owner(object owner) { IsOwned = owner != null; this.owner = owner; return this; } | |
/// <inheritdoc/> | |
public Tween<T> Start() | |
{ | |
Debug.Assert(duration > 0.0f, "[FronkonGames.TinyTween] The duration of the tween should be greater than zero."); | |
Debug.Assert(easeIn != Ease.None && easeOut != Ease.None, "[FronkonGames.TinyTween] You must set some kind of Ease."); | |
State = TweenState.Running; | |
UpdateValue(); | |
return this; | |
} | |
/// <inheritdoc/> | |
public void Pause() => State = TweenState.Paused; | |
/// <inheritdoc/> | |
public void Resume() => State = TweenState.Running; | |
/// <inheritdoc/> | |
public void Stop(bool moveToEnd = true) | |
{ | |
if (State != TweenState.Finished) | |
{ | |
State = TweenState.Finished; | |
if (moveToEnd == true) | |
{ | |
currentTime = duration; | |
UpdateValue(); | |
} | |
endFunction?.Invoke(this); | |
} | |
} | |
/// <inheritdoc/> | |
public void Reset() | |
{ | |
currentTime = 0.0f; | |
Value = origin; | |
} | |
/// <inheritdoc/> | |
public void Update() | |
{ | |
if (IsOwned == true && owner.Equals(null) || condition != null && condition(this) == false) | |
Stop(false); | |
else | |
{ | |
currentTime += UnityEngine.Time.deltaTime; | |
if (currentTime >= duration) | |
{ | |
residueCount--; | |
ExecutionCount++; | |
switch (loop) | |
{ | |
case TweenLoop.Once: Stop(); break; | |
case TweenLoop.Loop: | |
if (residueCount == 0) | |
Stop(); | |
Value = origin; | |
currentTime = Progress = 0.0f; | |
break; | |
case TweenLoop.YoYo: | |
if (residueCount == 0) | |
Stop(); | |
(destination, origin) = (origin, destination); | |
currentTime = Progress = 0.0f; | |
break; | |
default: throw new ArgumentOutOfRangeException(); | |
} | |
} | |
else | |
UpdateValue(); | |
} | |
} | |
private void UpdateValue() | |
{ | |
float t = currentTime / duration; | |
Progress = EasingFunctions.Calculate(t > 0.5f ? easeOut : easeIn, easeIn != Ease.None, easeOut != Ease.None, t); | |
Value = interpolationFunction(this, origin, destination, Progress, clamp); | |
updateFunction?.Invoke(this); | |
} | |
} | |
/// <summary> | |
/// Tweens manager, update tweens and delete those that have already ended. | |
/// It is not necessary if you are in charge of maintaining your Tweens ;) | |
/// </summary> | |
public sealed class TinyTween : MonoBehaviour | |
{ | |
public static TinyTween Instance => LazyInstance.Value; | |
private static readonly Lazy<TinyTween> LazyInstance = new(CreateSingleton); | |
private readonly List<ITween> tweens = new(); | |
/// <summary> Add an existing tween. </summary> | |
/// <param name="tween">New tween</param> | |
/// <returns>Tween.</returns> | |
public ITween Add(ITween tween) { tweens.Add(tween); return tween; } | |
private static TinyTween CreateSingleton() | |
{ | |
GameObject ownerObject = new("TinyTween"); | |
TinyTween instance = ownerObject.AddComponent<TinyTween>(); | |
DontDestroyOnLoad(ownerObject); | |
return instance; | |
} | |
private void Update() | |
{ | |
int count = tweens.Count; | |
for (int i = count - 1; i >= 0; --i) | |
{ | |
ITween tween = tweens[i]; | |
if (tween.State == TweenState.Running) | |
tween.Update(); | |
if (tween.State == TweenState.Finished && i < count) | |
tweens.RemoveAt(i); | |
} | |
} | |
private void OnDisable() => tweens.Clear(); | |
} | |
/// <summary> Tween float. </summary> | |
public sealed class TweenFloat : Tween<float> | |
{ | |
/// <summary> Create a Tween float and add it to the TinyTween manager. </summary> | |
/// <returns>Tween.</returns> | |
public static Tween<float> Create() => TinyTween.Instance.Add(new TweenFloat()) as Tween<float>; | |
private static float Lerp(ITween<float> t, float start, float end, float progress, bool clamp) => | |
clamp == true ? Mathf.Lerp(start, end, progress) : Mathf.LerpUnclamped(start, end, progress); | |
private TweenFloat() : base(Lerp) { } | |
} | |
/// <summary> Tween Vector2. </summary> | |
public sealed class TweenVector2 : Tween<Vector2> | |
{ | |
/// <summary> Create a Tween Vector2 and add it to the TinyTween manager. </summary> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector2> Create() => TinyTween.Instance.Add(new TweenVector2()) as Tween<Vector2>; | |
private static Vector2 Lerp(ITween<Vector2> t, Vector2 start, Vector2 end, float progress, bool clamp) => | |
clamp == true ? Vector2.Lerp(start, end, progress) : Vector2.LerpUnclamped(start, end, progress); | |
private TweenVector2() : base(Lerp) { } | |
} | |
/// <summary> Tween Vector3. </summary> | |
public sealed class TweenVector3 : Tween<Vector3> | |
{ | |
/// <summary> Create a Tween Vector3 and add it to the TinyTween manager. </summary> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> Create() => TinyTween.Instance.Add(new TweenVector3()) as Tween<Vector3>; | |
private static Vector3 Lerp(ITween<Vector3> t, Vector3 start, Vector3 end, float progress, bool clamp) => | |
clamp == true ? Vector3.Lerp(start, end, progress) : Vector3.LerpUnclamped(start, end, progress); | |
private TweenVector3() : base(Lerp) { } | |
} | |
/// <summary> Tween Vector4. </summary> | |
public sealed class TweenVector4 : Tween<Vector4> | |
{ | |
/// <summary> Create a Tween Vector4 and add it to the TinyTween manager. </summary> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector4> Create() => TinyTween.Instance.Add(new TweenVector4()) as Tween<Vector4>; | |
private static Vector4 Lerp(ITween<Vector4> t, Vector4 start, Vector4 end, float progress, bool clamp) => | |
clamp == true ? Vector4.Lerp(start, end, progress) : Vector4.LerpUnclamped(start, end, progress); | |
private TweenVector4() : base(Lerp) { } | |
} | |
/// <summary> Tween Quaternion. </summary> | |
public sealed class TweenQuaternion : Tween<Quaternion> | |
{ | |
/// <summary> Create a Tween Quaternion and add it to the TinyTween manager. </summary> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> Create() => TinyTween.Instance.Add(new TweenQuaternion()) as Tween<Quaternion>; | |
private static Quaternion Lerp(ITween<Quaternion> t, Quaternion start, Quaternion end, float progress, bool clamp) => | |
clamp == true ? Quaternion.Lerp(start, end, progress) : Quaternion.LerpUnclamped(start, end, progress); | |
private TweenQuaternion() : base(Lerp) { } | |
} | |
/// <summary> Tween Color. </summary> | |
public sealed class TweenColor : Tween<Color> | |
{ | |
/// <summary> Create a Tween Color and add it to the TinyTween manager. </summary> | |
/// <returns>Tween.</returns> | |
public static Tween<Color> Create() => TinyTween.Instance.Add(new TweenColor()) as Tween<Color>; | |
private static Color Lerp(ITween<Color> t, Color start, Color end, float progress, bool clamp) => | |
clamp == true ? Color.Lerp(start, end, progress) : Color.LerpUnclamped(start, end, progress); | |
private TweenColor() : base(Lerp) { } | |
} | |
/// <summary> Extensions to make it easy to use TinyTween. </summary> | |
public static class TweenExtensions | |
{ | |
/// <summary> Create and execute a tween. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start value.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<float> Tween(this float self, float origin, float destination, float duration, Ease ease) => | |
TweenFloat.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Create and execute a tween, using as initial value the current value. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<float> Tween(this float self, float destination, float duration, Ease ease) => Tween(self, self, destination, duration, ease); | |
/// <summary> Create and execute a tween. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start value.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> Tween(this Vector3 self, Vector3 origin, Vector3 destination, float duration, Ease ease) => | |
TweenVector3.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Create and execute a tween, using as initial value the current value. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> Tween(this Vector3 self, Vector3 destination, float duration, Ease ease) => Tween(self, self, destination, duration, ease); | |
/// <summary> Create and execute a tween. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start value.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> Tween(this Quaternion self, Quaternion origin, Quaternion destination, float duration, Ease ease) => | |
TweenQuaternion.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Create and execute a tween, using as initial value the current value. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> Tween(this Quaternion self, Quaternion destination, float duration, Ease ease) => Tween(self, self, destination, duration, ease); | |
/// <summary> Create and execute a tween. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start value.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Color> Tween(this Color self, Color origin, Color destination, float duration, Ease ease) => | |
FronkonGames.TinyTween.TweenColor.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Create and execute a tween, using as initial value the current value. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End value.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Color> Tween(this Color self, Color destination, float duration, Ease ease) => Tween(self, self, destination, duration, ease); | |
/// <summary> Moves a Transform. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start position.</param> | |
/// <param name="destination">End position.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenMove(this Transform self, Vector3 origin, Vector3 destination, float duration, Ease ease) => | |
TweenVector3.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self.position = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Moves a Transform, using its current position as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End position.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenMove(this Transform self, Vector3 destination, float duration, Ease ease) => TweenMove(self, self.position, destination, duration, ease); | |
/// <summary> Scale a Transform. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start scale.</param> | |
/// <param name="destination">End scale.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenScale(this Transform self, Vector3 origin, Vector3 destination, float duration, Ease ease) => | |
TweenVector3.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self.localScale = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Scale a Transform, using its current scale as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End scale.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenScale(this Transform self, Vector3 destination, float duration, Ease ease) => TweenScale(self, self.localScale, destination, duration, ease); | |
/// <summary> Rotate a Transform. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start rotation.</param> | |
/// <param name="destination">End rotation.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> TweenRotation(this Transform self, Quaternion origin, Quaternion destination, float duration, Ease ease) => | |
TweenQuaternion.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self.rotation = tween.Value) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Rotate a Transform, using its current rotation as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End rotation.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> TweenRotation(this Transform self, Quaternion destination, float duration, Ease ease) => TweenRotation(self, self.rotation, destination, duration, ease); | |
/// <summary> Moves a GameObject. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start position.</param> | |
/// <param name="destination">End position.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenMove(this GameObject self, Vector3 origin, Vector3 destination, float duration, Ease ease) => TweenMove(self.transform, origin, destination, duration, ease); | |
/// <summary> Moves a GameObject, using its current position as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End position.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenMove(this GameObject self, Vector3 destination, float duration, Ease ease) => TweenMove(self.transform, self.transform.position, destination, duration, ease); | |
/// <summary> Scale a GameObject. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start scale.</param> | |
/// <param name="destination">End scale.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenScale(this GameObject self, Vector3 origin, Vector3 destination, float duration, Ease ease) => TweenScale(self.transform, origin, destination, duration, ease); | |
/// <summary> Scale a GameObject, using its current scale as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End scale.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Vector3> TweenScale(this GameObject self, Vector3 destination, float duration, Ease ease) => TweenScale(self.transform, self.transform.localScale, destination, duration, ease); | |
/// <summary> Rotate a GameObject. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start rotation.</param> | |
/// <param name="destination">End rotation.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> TweenRotation(this GameObject self, Quaternion origin, Quaternion destination, float duration, Ease ease) => TweenRotation(self.transform, origin, destination, duration, ease); | |
/// <summary> Rotate a GameObject, using its current rotation as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End rotation.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Quaternion> TweenRotation(this GameObject self, Quaternion destination, float duration, Ease ease) => TweenRotation(self.transform, self.transform.rotation, destination, duration, ease); | |
/// <summary> Change the color of a Material. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="origin">Start color.</param> | |
/// <param name="destination">End color.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <param name="name">The name of the color variable.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Color> TweenColor(this Material self, Color origin, Color destination, float duration, Ease ease, string name = "_Color") => | |
FronkonGames.TinyTween.TweenColor.Create() | |
.Origin(origin) | |
.Destination(destination) | |
.Duration(duration) | |
.OnUpdate(tween => self.SetColor(name, tween.Value)) | |
.Owner(self) | |
.Easing(ease) | |
.Start(); | |
/// <summary> Change the color of a Material, using its current color as origin. </summary> | |
/// <param name="self">Self.</param> | |
/// <param name="destination">End color.</param> | |
/// <param name="duration">Time in seconds.</param> | |
/// <param name="ease">Easing.</param> | |
/// <param name="name">The name of the color variable.</param> | |
/// <returns>Tween.</returns> | |
public static Tween<Color> TweenColor(this Material self, Color destination, float duration, Ease ease, string name = "_Color") => TweenColor(self, self.GetColor(name), destination, duration, ease, name); | |
} | |
/// <summary> Types of Easing functions. See https://easings.net </summary> | |
public enum Ease | |
{ | |
None, | |
Linear, | |
Sine, | |
Quad, | |
Cubic, | |
Quart, | |
Quint, | |
Expo, | |
Circ, | |
Back, | |
Elastic, | |
Bounce, | |
} | |
/// <summary> Easing functions. </summary> | |
internal static class EasingFunctions | |
{ | |
public static float Calculate(Ease ease, bool easingIn, bool easingOut, float t) => ease switch | |
{ | |
Ease.Linear => t, | |
Ease.Sine => easingIn && easingOut ? SineInOut(t) : easingIn ? SineIn(t) : SineOut(t), | |
Ease.Quad => easingIn && easingOut ? QuadInOut(t) : easingIn ? QuadIn(t) : QuadOut(t), | |
Ease.Cubic => easingIn && easingOut ? CubicInOut(t) : easingIn ? CubicIn(t) : CubicOut(t), | |
Ease.Quart => easingIn && easingOut ? QuartInOut(t) : easingIn ? QuartIn(t) : QuartOut(t), | |
Ease.Quint => easingIn && easingOut ? QuintInOut(t) : easingIn ? QuintIn(t) : QuintOut(t), | |
Ease.Expo => easingIn && easingOut ? ExpoInOut(t) : easingIn ? ExpoIn(t) : ExpoOut(t), | |
Ease.Circ => easingIn && easingOut ? CircInOut(t) : easingIn ? CircIn(t) : CircOut(t), | |
Ease.Back => easingIn && easingOut ? BackInOut(t) : easingIn ? BackIn(t) : BackOut(t), | |
Ease.Elastic => easingIn && easingOut ? ElasticInOut(t) : easingIn ? ElasticIn(t) : ElasticOut(t), | |
Ease.Bounce => easingIn && easingOut ? BounceInOut(t) : easingIn ? BounceIn(t) : BounceOut(t), | |
_ => t | |
}; | |
private static float SineIn(float t) => 1.0f - Mathf.Cos(t * Mathf.PI / 2.0f); | |
private static float SineOut(float t) => Mathf.Sin(t * Mathf.PI / 2.0f); | |
private static float SineInOut(float t) => 0.5f * (1.0f - Mathf.Cos(Mathf.PI * t)); | |
private static float QuadIn(float t) => t * t; | |
private static float QuadOut(float t) => 1.0f - (1.0f - t) * (1.0f - t); | |
private static float QuadInOut(float t) => t < 0.5f ? 2.0f * t * t : 1.0f - Mathf.Pow(-2.0f * t + 2.0f, 2.0f) / 2.0f; | |
private static float CubicIn(float t) => t * t * t; | |
private static float CubicOut(float t) => --t * t * t + 1.0f; | |
private static float CubicInOut(float t) => t < 0.5f ? 4.0f * t * t * t : 1.0f - Mathf.Pow(-2.0f * t + 2.0f, 3.0f) / 2.0f; | |
private static float QuartIn(float t) => t * t * t * t; | |
private static float QuartOut(float t) => 1.0f - (--t * t * t * t); | |
private static float QuartInOut(float t) => (t *= 2.0f) < 1.0f ? 0.5f * t * t * t * t : -0.5f * ((t -= 2.0f) * t * t * t - 2.0f); | |
private static float QuintIn(float t) => t * t * t * t * t; | |
private static float QuintOut(float t) => --t * t * t * t * t + 1.0f; | |
private static float QuintInOut(float t) => t < 0.5f ? 16.0f * t * t * t * t * t : 1.0f - Mathf.Pow(-2.0f * t + 2.0f, 5.0f) / 2.0f; | |
private static float ExpoIn(float t) => t == 0.0f ? 0.0f : Mathf.Pow(2.0f, 10.0f * t - 10.0f); | |
private static float ExpoOut(float t) => t == 1.0f ? 1.0f : 1.0f - Mathf.Pow(2.0f, -10.0f * t); | |
private static float ExpoInOut(float t) => t == 0.0f ? 0.0f | |
: t == 1.0f ? 1.0f | |
: t < 0.5f ? Mathf.Pow(2.0f, 20.0f * t - 10.0f) / 2.0f | |
: (2.0f - Mathf.Pow(2.0f, -20.0f * t + 10.0f)) / 2.0f; | |
private static float CircIn(float t) => 1.0f - Mathf.Sqrt(1.0f - Mathf.Pow(t, 2.0f)); | |
private static float CircOut(float t) => Mathf.Sqrt(1.0f - Mathf.Pow(t - 1.0f, 2.0f)); | |
private static float CircInOut(float t) => t < 0.5f ? (1.0f - Mathf.Sqrt(1.0f - Mathf.Pow(2.0f * t, 2.0f))) / 2.0f | |
: (Mathf.Sqrt(1.0f - Mathf.Pow(-2.0f * t + 2.0f, 2.0f)) + 1.0f) / 2.0f; | |
private static float BackIn(float t) => C3 * t * t * t - C1 * t * t; | |
private static float BackOut(float t) => 1.0f + C3 * Mathf.Pow(t - 1.0f, 3.0f) + C1 * Mathf.Pow(t - 1.0f, 2.0f); | |
private static float BackInOut(float t) => t < 0.5f ? Mathf.Pow(2.0f * t, 2.0f) * ((C2 + 1.0f) * 2.0f * t - C2) / 2.0f | |
: (Mathf.Pow(2.0f * t - 2.0f, 2.0f) * ((C2 + 1.0f) * (t * 2.0f - 2.0f) + C2) + 2.0f) / 2.0f; | |
private static float ElasticIn(float t) => -Mathf.Pow(2.0f, 10.0f * t - 10.0f) * Mathf.Sin((t * 10.0f - 10.75f) * C4); | |
private static float ElasticOut(float t) => Mathf.Pow(2.0f, -10.0f * t) * Mathf.Sin((t * 10.0f - 0.75f) * C4) + 1.0f; | |
private static float ElasticInOut(float t) => t < 0.5f ? -(Mathf.Pow(2.0f, 20.0f * t - 10.0f) * Mathf.Sin((20.0f * t - 11.125f) * C5)) / 2f | |
: Mathf.Pow(2.0f, -20.0f * t + 10.0f) * Mathf.Sin((20.0f * t - 11.125f) * C5) / 2.0f + 1.0f; | |
private static float BounceIn(float t) => 1.0f - BounceOut(1.0f - t); | |
private static float BounceOut(float t) | |
{ | |
if (t < 1.0f / 2.75f) | |
return 7.5625f * t * t; | |
if (t < 2.0f / 2.75f) | |
return 7.5625f * (t -= 1.5f / 2.75f) * t + 0.75f; | |
if (t < 2.5f / 2.75f) | |
return 7.5625f * (t -= 2.25f / 2.75f) * t + 0.9375f; | |
return 7.5625f * (t -= 2.625f / 2.75f) * t + 0.984375f; | |
} | |
private static float BounceInOut(float t) => t < 0.5f ? BounceIn(t * 2.0f) * 0.5f : BounceOut(t * 2.0f - 1.0f) * 0.5f + 0.5f; | |
private const float C1 = 1.70158f; | |
private const float C2 = C1 * 1.525f; | |
private const float C3 = C1 + 1.0f; | |
private const float C4 = 2.0f * Mathf.PI / 3.0f; | |
private const float C5 = 2.0f * Mathf.PI / 4.5f; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment