167 lines
7.3 KiB
C#
167 lines
7.3 KiB
C#
// 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
|
|
|
|
//https://pomax.github.io/bezierinfo/
|
|
//https://gist.github.com/cjddmut/d789b9eb78216998e95c
|
|
|
|
using System;
|
|
using UnityEngine;
|
|
using static UnityEngine.Mathf;
|
|
namespace Doozy.Runtime.Reactor.Easings
|
|
{
|
|
[Serializable]
|
|
public class Bezier : IEasing
|
|
{
|
|
[SerializeField] private float Ax;
|
|
[SerializeField] private float Ay;
|
|
[SerializeField] private float Bx;
|
|
[SerializeField] private float By;
|
|
|
|
public Vector2 a => new Vector2(ax, ay);
|
|
public float ax => Ax;
|
|
public float ay => Ay;
|
|
|
|
public Vector2 b => new Vector2(bx, By);
|
|
public float bx => Bx;
|
|
public float by => By;
|
|
|
|
public Bezier(float ax, float ay, float bx, float by)
|
|
{
|
|
Ax = ax;
|
|
Ay = ay;
|
|
Bx = bx;
|
|
By = by;
|
|
}
|
|
|
|
public Bezier(Vector2 a, Vector2 b)
|
|
: this(a.x, a.y, b.x, b.y)
|
|
{
|
|
}
|
|
|
|
public Bezier(Bezier other)
|
|
: this(other.ax, other.ay, other.bx, other.by)
|
|
{
|
|
}
|
|
|
|
public float Evaluate(float progress) =>
|
|
Evaluate(a, b, Clamp01(progress));
|
|
|
|
private static float A(float x, float y) => 1f - 3f * y + 3f * x;
|
|
private static float B(float x, float y) => 3f * y - 6f * x;
|
|
private static float C(float x) => 3f * x;
|
|
|
|
/// <summary>
|
|
/// x(t) given (t, x1, x2) or y(t) given (t, y1, y2)
|
|
/// <para/> if a=x1 then b=x2
|
|
/// <para/> if a=y1 then b=y2
|
|
/// </summary>
|
|
/// <param name="t"> Time </param>
|
|
/// <param name="a"> x1 or y1 </param>
|
|
/// <param name="b"> x2 or y2 </param>
|
|
private static float CalcBezier(float t, float a, float b) =>
|
|
((A(a, b) * t + B(a, b)) * t + C(a)) * t;
|
|
|
|
/// <summary>
|
|
/// dx/dt given (t, x1, x2) or dy/dt given (t, y1, y2)
|
|
/// <para/> if a=x1 then b=x2
|
|
/// <para/> if a=y1 then b=y2
|
|
/// </summary>
|
|
/// <param name="t"> Time </param>
|
|
/// <param name="a"> x1 or y1 </param>
|
|
/// <param name="b"> x2 or y2 </param>
|
|
private static float GetSlope(float t, float a, float b) =>
|
|
3f * A(a, b) * t * t + 2f * B(a, b) * t + C(a);
|
|
|
|
/// <summary>
|
|
/// Calculates the time for the given x1,x2 or y1,y2 values
|
|
/// <para/> if a=x1 then b=x2
|
|
/// <para/> if a=y1 then b=y2
|
|
/// </summary>
|
|
/// <param name="t"> Time </param>
|
|
/// <param name="a"> x1 or y1 </param>
|
|
/// <param name="b"> x2 or y2 </param>
|
|
/// <returns></returns>
|
|
private static float CalculateTime(float t, float a, float b)
|
|
{
|
|
float time = t;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
float slope = GetSlope(time, a, b);
|
|
if (slope == 0) return time;
|
|
float currentX = CalcBezier(time, a, b) - t;
|
|
time -= currentX / slope;
|
|
}
|
|
return time;
|
|
}
|
|
|
|
private static float Calculate(float ax, float ay, float bx, float by, float t)
|
|
{
|
|
// if (mX1 == mY1 && mX2 == mY2) return aX; //linear
|
|
if (Approximately(ax, ay) && Approximately(bx, by)) return t; //linear
|
|
return CalcBezier(CalculateTime(t, ax, bx), ay, by);
|
|
}
|
|
|
|
public static float Evaluate(float ax, float ay, float bx, float by, float t) =>
|
|
Calculate(ax, ay, bx, by, t);
|
|
|
|
public static float Evaluate(Vector2 a, Vector2 b, float t) =>
|
|
Calculate(a.x, a.y, b.x, b.y, t);
|
|
|
|
public static float Evaluate(Bezier b, float t) =>
|
|
Evaluate(b.a.x, b.a.y, b.b.x, b.b.y, t);
|
|
|
|
public static float Evaluate(float progress, Ease ease)
|
|
{
|
|
progress = Clamp01(progress);
|
|
|
|
//The switch expression does not handle all possible values of its input type (it is not exhaustive).
|
|
#pragma warning disable 8509
|
|
{
|
|
return ease switch
|
|
{
|
|
Ease.Linear => Evaluate(0f, 0f, 1f, 1f, progress),
|
|
Ease.Easy => Evaluate(0.25f, 0.1f, 0.25f, 1.0f, progress),
|
|
Ease.InEasy => Evaluate(0.42f, 0f, 1f, 1f, progress),
|
|
Ease.OutEasy => Evaluate(0f, 0f, 0.58f, 1f, progress),
|
|
Ease.InOutEasy => Evaluate(0.42f, 0, 0.58f, 1f, progress),
|
|
Ease.InSine => Evaluate(0.47f, 0, 0.745f, 0.715f, progress),
|
|
Ease.OutSine => Evaluate(0.39f, 0.575f, 0.565f, 1f, progress),
|
|
Ease.InOutSine => Evaluate(0.445f, 0.05f, 0.55f, 0.95f, progress),
|
|
Ease.InQuad => Evaluate(0.55f, 0.085f, 0.68f, 0.53f, progress),
|
|
Ease.OutQuad => Evaluate(0.25f, 0.46f, 0.45f, 0.94f, progress),
|
|
Ease.InOutQuad => Evaluate(0.455f, 0.03f, 0.515f, 0.955f, progress),
|
|
Ease.InCubic => Evaluate(0.55f, 0.055f, 0.675f, 0.19f, progress),
|
|
Ease.OutCubic => Evaluate(0.215f, 0.61f, 0.355f, 1f, progress),
|
|
Ease.InOutCubic => Evaluate(0.645f, 0.045f, 0.355f, 1f, progress),
|
|
Ease.InQuart => Evaluate(0.895f, 0.03f, 0.685f, 0.22f, progress),
|
|
Ease.OutQuart => Evaluate(0.165f, 0.84f, 0.44f, 1f, progress),
|
|
Ease.InOutQuart => Evaluate(0.77f, 0f, 0.175f, 1f, progress),
|
|
Ease.InQuint => Evaluate(0.755f, 0.05f, 0.855f, 0.06f, progress),
|
|
Ease.OutQuint => Evaluate(0.23f, 1f, 0.32f, 1f, progress),
|
|
Ease.InOutQuint => Evaluate(0.86f, 0f, 0.07f, 1f, progress),
|
|
Ease.InExpo => Evaluate(0.95f, 0.05f, 0.795f, 0.035f, progress),
|
|
Ease.OutExpo => Evaluate(0.19f, 1f, 0.22f, 1f, progress),
|
|
Ease.InOutExpo => Evaluate(1f, 0f, 0f, 1f, progress),
|
|
Ease.InCirc => Evaluate(0.6f, 0.04f, 0.98f, 0.335f, progress),
|
|
Ease.OutCirc => Evaluate(0.075f, 0.82f, 0.165f, 1f, progress),
|
|
Ease.InOutCirc => Evaluate(0.785f, 0.135f, 0.15f, 0.86f, progress),
|
|
Ease.InBack => Evaluate(0.8f, -0.4f, 0f, 1f, progress),
|
|
// Ease.OutBack => expr,
|
|
// Ease.InOutBack => expr,
|
|
// Ease.InElastic => expr,
|
|
// Ease.OutElastic => expr,
|
|
// Ease.InOutElastic => expr,
|
|
// Ease.InBounce => expr,
|
|
// Ease.OutBounce => expr,
|
|
// Ease.InOutBounce => expr,
|
|
// Ease.Spring => expr,
|
|
// _ => throw new ArgumentOutOfRangeException(nameof(ease), ease, null)
|
|
};
|
|
}
|
|
#pragma warning restore 8509
|
|
|
|
}
|
|
}
|
|
}
|