// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved. // This code can only be used under the standard Unity Asset Store End User License Agreement // A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms using System; using static UnityEngine.Mathf; namespace Doozy.Runtime.Reactor.Easings { public static class EasingFunction { #region Constants // ReSharper disable UnusedMember.Local private const float PI = (float)Math.PI; /// 1.57079632679 private const float HALF_PI = PI * 0.5f; /// 6.28318530718 private const float TWO_PI = PI * 2f; private const float C1 = 1.70158f; private const float C2 = C1 * 1.525f; private const float C3 = C1 + 1f; private const float C4 = 2f * PI / 3f; private const float C5 = 2f * PI / 4.5f; // ReSharper restore UnusedMember.Local #endregion #region Linear interpolation (no easing) /// /// Linear interpolation (no easing) /// Modeled after the line y = x /// /// Value clamped between 0 and 1 public static float LinearInterpolation(float progress) { progress = Clamp01(progress); return progress; } #endregion #region Quadratic easing; p^2 /// /// Quadratic easing; p^2 /// Modeled after the parabola y = x^2 /// /// Value clamped between 0 and 1 public static float QuadraticEaseIn(float progress) { progress = Clamp01(progress); return Pow(progress, 2); } /// /// Quadratic easing; p^2 /// Modeled after the parabola y = -x^2 + 2x /// /// Value clamped between 0 and 1 public static float QuadraticEaseOut(float progress) { progress = Clamp01(progress); return -(progress * (progress - 2f)); } /// /// Quadratic easing; p^2 /// Modeled after the piecewise quadratic /// y = (1/2)((2x)^2) ; [0, 0.5) /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float QuadraticEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { return 2f * Pow(progress, 2); } else { return -2f * Pow(progress, 2) + 4 * progress - 1; } } #endregion #region Cubic easing; p^3 /// /// Cubic easing; p^3 /// Modeled after the cubic y = x^3 /// /// Value clamped between 0 and 1 public static float CubicEaseIn(float progress) { progress = Clamp01(progress); return Pow(progress, 3); } /// /// Cubic easing; p^3 /// Modeled after the cubic y = (x - 1)^3 + 1 /// /// Value clamped between 0 and 1 public static float CubicEaseOut(float progress) { progress = Clamp01(progress); float value = progress - 1f; return Pow(value, 3) + 1f; } /// /// Cubic easing; p^3 /// Modeled after the piecewise cubic /// y = (1/2)((2x)^3) ; [0, 0.5) /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float CubicEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { return 4f * Pow(progress, 3); } else { float value = 2f * progress - 2f; return 0.5f * Pow(value, 3) + 1f; } } #endregion #region Quartic easing; p^4 /// /// Quartic easing; p^4 /// Modeled after the quartic y = x^4 /// /// Value clamped between 0 and 1 public static float QuarticEaseIn(float progress) { progress = Clamp01(progress); return Pow(progress, 4); } /// /// Quartic easing; p^4 /// Modeled after the quartic y = 1 - (x - 1)^4 /// /// Value clamped between 0 and 1 public static float QuarticEaseOut(float progress) { progress = Clamp01(progress); float value = progress - 1f; return Pow(value, 3) * (1f - progress) + 1f; } /// /// Quartic easing; p^4 /// Modeled after the piecewise quartic /// y = (1/2)((2x)^4) ; [0, 0.5) /// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float QuarticEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { return 8f * Pow(progress, 4); } else { float value = progress - 1f; return -8f * Pow(value, 4) + 1f; } } #endregion #region Quintic easing; p^5 /// /// Quintic easing; p^5 /// Modeled after the quintic y = x^5 /// /// Value clamped between 0 and 1 public static float QuinticEaseIn(float progress) { progress = Clamp01(progress); return Pow(progress, 5); } /// /// Quintic easing; p^5 /// Modeled after the quintic y = (x - 1)^5 + 1 /// /// Value clamped between 0 and 1 public static float QuinticEaseOut(float progress) { progress = Clamp01(progress); float value = progress - 1f; return Pow(value, 5) + 1f; } /// /// Quintic easing; p^5 /// Modeled after the piecewise quintic /// y = (1/2)((2x)^5) ; [0, 0.5) /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float QuinticEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { return 16f * Pow(progress, 5); } else { float value = 2f * progress - 2f; return 0.5f * Pow(value, 5) + 1f; } } #endregion #region Sine wave easing; sin(p * PI/2) /// /// Sine wave easing; sin(p * PI/2) /// Modeled after quarter-cycle of sine wave /// /// Value clamped between 0 and 1 public static float SineEaseIn(float progress) { progress = Clamp01(progress); return Sin((progress - 1f) * HALF_PI) + 1f; } /// /// Sine wave easing; sin(p * PI/2) /// Modeled after quarter-cycle of sine wave (different phase) /// /// Value clamped between 0 and 1 public static float SineEaseOut(float progress) { progress = Clamp01(progress); return Sin(progress * HALF_PI); } /// /// Sine wave easing; sin(p * PI/2) /// Modeled after half sine wave /// /// Value clamped between 0 and 1 public static float SineEaseInOut(float progress) { progress = Clamp01(progress); return 0.5f * (1f - Cos(progress * PI)); } #endregion #region Circular easing; sqrt(1 - p^2) /// /// Circular easing; sqrt(1 - p^2) /// Modeled after shifted quadrant IV of unit circle /// /// Value clamped between 0 and 1 public static float CircularEaseIn(float progress) { progress = Clamp01(progress); return 1f - Sqrt(1 - Pow(progress, 2)); } /// /// Circular easing; sqrt(1 - p^2) /// Modeled after shifted quadrant II of unit circle /// /// Value clamped between 0 and 1 public static float CircularEaseOut(float progress) { progress = Clamp01(progress); return Sqrt((2 - progress) * progress); } /// /// Circular easing; sqrt(1 - p^2) /// Modeled after the piecewise circular function /// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) /// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float CircularEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { return 0.5f * (1f - Sqrt(1f - 4f * Pow(progress, 2))); } else { return 0.5f * (Sqrt(-(2f * progress - 3f) * (2f * progress - 1f)) + 1f); } } #endregion #region Exponential easing, base 2 /// /// Exponential easing, base 2 /// Modeled after the exponential function y = 2^(10(x - 1)) /// /// Value clamped between 0 and 1 public static float ExponentialEaseIn(float progress) { progress = Clamp01(progress); return Approximately(progress, 0f) ? progress : Pow(2f, 10f * (progress - 1f)); } /// /// Exponential easing, base 2 /// Modeled after the exponential function y = -2^(-10x) + 1 /// /// Value clamped between 0 and 1 public static float ExponentialEaseOut(float progress) { progress = Clamp01(progress); return Approximately(progress, 1f) ? progress : 1f - Pow(2f, -10f * progress); } /// /// Exponential easing, base 2 /// Modeled after the piecewise exponential /// y = (1/2)2^(10(2x - 1)) ; [0,0.5) /// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] /// /// Value clamped between 0 and 1 public static float ExponentialEaseInOut(float progress) { progress = Clamp01(progress); if (Approximately(progress, 0f) || Approximately(progress, 1f)) return progress; if (progress < 0.5f) { return 0.5f * Pow(2f, 20f * progress - 10f); } else { return -0.5f * Pow(2f, -20f * progress + 10f) + 1f; } } #endregion #region Exponentially-damped sine wave easing (Elastic) /// /// Exponentially-damped sine wave easing (Elastic) /// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) /// /// Value clamped between 0 and 1 public static float ElasticEaseIn(float progress) { progress = Clamp01(progress); return Sin(13f * HALF_PI * progress) * Pow(2f, 10f * (progress - 1f)); } /// /// Exponentially-damped sine wave easing (Elastic) /// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 /// /// Value clamped between 0 and 1 public static float ElasticEaseOut(float progress) { progress = Clamp01(progress); return Sin(-13f * HALF_PI * (progress + 1f)) * Pow(2f, -10f * progress) + 1f; } /// /// Exponentially-damped sine wave easing (Elastic) /// Modeled after the piecewise exponentially-damped sine wave: /// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) /// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float ElasticEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5) { return 0.5f * Sin(13f * HALF_PI * (2f * progress)) * Pow(2f, 10f * (2f * progress - 1f)); } else { return 0.5f * (Sin(-13f * HALF_PI * (2f * progress - 1f + 1f)) * Pow(2f, -10f * (2f * progress - 1f)) + 2); } } #endregion #region Overshooting cubic easing (Back) /// /// Overshooting cubic easing (Back) /// Modeled after the overshooting cubic y = x^3-x*sin(x*pi) /// /// Value clamped between 0 and 1 public static float BackEaseIn(float progress) { progress = Clamp01(progress); return Pow(progress, 3) - progress * Sin(progress * PI); } /// /// Overshooting cubic easing (Back) /// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) /// /// Value clamped between 0 and 1 public static float BackEaseOut(float progress) { progress = Clamp01(progress); float value = 1 - progress; return 1 - (Pow(value, 3) - value * Sin(value * PI)); } /// /// Overshooting cubic easing (Back) /// Modeled after the piecewise overshooting cubic function: /// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) /// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] /// /// Value clamped between 0 and 1 public static float BackEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { float value = 2f * progress; return 0.5f * (Pow(value, 3) - value * Sin(value * PI)); } else { float value = 1f - (2f * progress - 1f); return 0.5f * (1f - (Pow(value, 3) - value * Sin(value * PI))) + 0.5f; } } #endregion #region Exponentially-decaying bounce easing (Bounce) /// /// Exponentially-decaying bounce easing (Bounce) /// /// Value clamped between 0 and 1 public static float BounceEaseIn(float progress) { progress = Clamp01(progress); return 1f - BounceEaseOut(1f - progress); } /// /// Exponentially-decaying bounce easing (Bounce) /// /// Value clamped between 0 and 1 public static float BounceEaseOut(float progress) { progress = Clamp01(progress); if (progress < 4f / 11f) { return 121f * Pow(progress, 2) / 16f; } else if (progress < 8f / 11f) { return 363f / 40f * Pow(progress, 2) - 99f / 10f * progress + 17f / 5f; } else if (progress < 9 / 10.0) { return 4356f / 361f * Pow(progress, 2) - 35442f / 1805f * progress + 16061f / 1805f; } else { return 54f / 5f * Pow(progress, 2) - 513f / 25f * progress + 268f / 25f; } } /// /// Exponentially-decaying bounce easing (Bounce) /// /// Value clamped between 0 and 1 public static float BounceEaseInOut(float progress) { progress = Clamp01(progress); if (progress < 0.5f) { return 0.5f * BounceEaseIn(progress * 2f); } else { return 0.5f * BounceEaseOut(progress * 2f - 1f) + 0.5f; } } #endregion } }