Last active
October 26, 2020 23:57
-
-
Save Donnotron666/c923e6d2b4ce3d55726bb0144d53dd81 to your computer and use it in GitHub Desktop.
Simple controller for managing squash n stretch on transforms.
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
namespace Core.Utils | |
{ | |
static public class Easing | |
{ | |
/// <summary> | |
/// Constant Pi. | |
/// </summary> | |
private const float PI = Math.PI; | |
/// <summary> | |
/// Constant Pi / 2. | |
/// </summary> | |
private const float HALFPI = Math.PI / 2.0f; | |
/// <summary> | |
/// Easing Functions enumeration | |
/// </summary> | |
public enum Functions | |
{ | |
Linear, | |
QuadraticEaseIn, | |
QuadraticEaseOut, | |
QuadraticEaseInOut, | |
CubicEaseIn, | |
CubicEaseOut, | |
CubicEaseInOut, | |
QuarticEaseIn, | |
QuarticEaseOut, | |
QuarticEaseInOut, | |
QuinticEaseIn, | |
QuinticEaseOut, | |
QuinticEaseInOut, | |
SineEaseIn, | |
SineEaseOut, | |
SineEaseInOut, | |
CircularEaseIn, | |
CircularEaseOut, | |
CircularEaseInOut, | |
ExponentialEaseIn, | |
ExponentialEaseOut, | |
ExponentialEaseInOut, | |
ElasticEaseIn, | |
ElasticEaseOut, | |
ElasticEaseInOut, | |
BackEaseIn, | |
BackEaseOut, | |
BackEaseInOut, | |
BounceEaseIn, | |
BounceEaseOut, | |
BounceEaseInOut | |
} | |
/// <summary> | |
/// Interpolate using the specified function. | |
/// </summary> | |
static public float Interpolate(float p, Functions function) | |
{ | |
switch (function) | |
{ | |
default: | |
case Functions.Linear: return Linear(p); | |
case Functions.QuadraticEaseOut: return QuadraticEaseOut(p); | |
case Functions.QuadraticEaseIn: return QuadraticEaseIn(p); | |
case Functions.QuadraticEaseInOut: return QuadraticEaseInOut(p); | |
case Functions.CubicEaseIn: return CubicEaseIn(p); | |
case Functions.CubicEaseOut: return CubicEaseOut(p); | |
case Functions.CubicEaseInOut: return CubicEaseInOut(p); | |
case Functions.QuarticEaseIn: return QuarticEaseIn(p); | |
case Functions.QuarticEaseOut: return QuarticEaseOut(p); | |
case Functions.QuarticEaseInOut: return QuarticEaseInOut(p); | |
case Functions.QuinticEaseIn: return QuinticEaseIn(p); | |
case Functions.QuinticEaseOut: return QuinticEaseOut(p); | |
case Functions.QuinticEaseInOut: return QuinticEaseInOut(p); | |
case Functions.SineEaseIn: return SineEaseIn(p); | |
case Functions.SineEaseOut: return SineEaseOut(p); | |
case Functions.SineEaseInOut: return SineEaseInOut(p); | |
case Functions.CircularEaseIn: return CircularEaseIn(p); | |
case Functions.CircularEaseOut: return CircularEaseOut(p); | |
case Functions.CircularEaseInOut: return CircularEaseInOut(p); | |
case Functions.ExponentialEaseIn: return ExponentialEaseIn(p); | |
case Functions.ExponentialEaseOut: return ExponentialEaseOut(p); | |
case Functions.ExponentialEaseInOut: return ExponentialEaseInOut(p); | |
case Functions.ElasticEaseIn: return ElasticEaseIn(p); | |
case Functions.ElasticEaseOut: return ElasticEaseOut(p); | |
case Functions.ElasticEaseInOut: return ElasticEaseInOut(p); | |
case Functions.BackEaseIn: return BackEaseIn(p); | |
case Functions.BackEaseOut: return BackEaseOut(p); | |
case Functions.BackEaseInOut: return BackEaseInOut(p); | |
case Functions.BounceEaseIn: return BounceEaseIn(p); | |
case Functions.BounceEaseOut: return BounceEaseOut(p); | |
case Functions.BounceEaseInOut: return BounceEaseInOut(p); | |
} | |
} | |
/// <summary> | |
/// Modeled after the line y = x | |
/// </summary> | |
static public float Linear(float p) | |
{ | |
return p; | |
} | |
/// <summary> | |
/// Modeled after the parabola y = x^2 | |
/// </summary> | |
static public float QuadraticEaseIn(float p) | |
{ | |
return p * p; | |
} | |
/// <summary> | |
/// Modeled after the parabola y = -x^2 + 2x | |
/// </summary> | |
static public float QuadraticEaseOut(float p) | |
{ | |
return -(p * (p - 2)); | |
} | |
/// <summary> | |
/// Modeled after the piecewise quadratic | |
/// y = (1/2)((2x)^2) ; [0, 0.5) | |
/// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] | |
/// </summary> | |
static public float QuadraticEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 2 * p * p; | |
} | |
else | |
{ | |
return (-2 * p * p) + (4 * p) - 1; | |
} | |
} | |
/// <summary> | |
/// Modeled after the cubic y = x^3 | |
/// </summary> | |
static public float CubicEaseIn(float p) | |
{ | |
return p * p * p; | |
} | |
/// <summary> | |
/// Modeled after the cubic y = (x - 1)^3 + 1 | |
/// </summary> | |
static public float CubicEaseOut(float p) | |
{ | |
float f = (p - 1); | |
return f * f * f + 1; | |
} | |
/// <summary> | |
/// Modeled after the piecewise cubic | |
/// y = (1/2)((2x)^3) ; [0, 0.5) | |
/// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] | |
/// </summary> | |
static public float CubicEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 4 * p * p * p; | |
} | |
else | |
{ | |
float f = ((2 * p) - 2); | |
return 0.5f * f * f * f + 1; | |
} | |
} | |
/// <summary> | |
/// Modeled after the quartic x^4 | |
/// </summary> | |
static public float QuarticEaseIn(float p) | |
{ | |
return p * p * p * p; | |
} | |
/// <summary> | |
/// Modeled after the quartic y = 1 - (x - 1)^4 | |
/// </summary> | |
static public float QuarticEaseOut(float p) | |
{ | |
float f = (p - 1); | |
return f * f * f * (1 - p) + 1; | |
} | |
/// <summary> | |
// Modeled after the piecewise quartic | |
// y = (1/2)((2x)^4) ; [0, 0.5) | |
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] | |
/// </summary> | |
static public float QuarticEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 8 * p * p * p * p; | |
} | |
else | |
{ | |
float f = (p - 1); | |
return -8 * f * f * f * f + 1; | |
} | |
} | |
/// <summary> | |
/// Modeled after the quintic y = x^5 | |
/// </summary> | |
static public float QuinticEaseIn(float p) | |
{ | |
return p * p * p * p * p; | |
} | |
/// <summary> | |
/// Modeled after the quintic y = (x - 1)^5 + 1 | |
/// </summary> | |
static public float QuinticEaseOut(float p) | |
{ | |
float f = (p - 1); | |
return f * f * f * f * f + 1; | |
} | |
/// <summary> | |
/// Modeled after the piecewise quintic | |
/// y = (1/2)((2x)^5) ; [0, 0.5) | |
/// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] | |
/// </summary> | |
static public float QuinticEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 16 * p * p * p * p * p; | |
} | |
else | |
{ | |
float f = ((2 * p) - 2); | |
return 0.5f * f * f * f * f * f + 1; | |
} | |
} | |
/// <summary> | |
/// Modeled after quarter-cycle of sine wave | |
/// </summary> | |
static public float SineEaseIn(float p) | |
{ | |
return Math.Sin((p - 1) * HALFPI) + 1; | |
} | |
/// <summary> | |
/// Modeled after quarter-cycle of sine wave (different phase) | |
/// </summary> | |
static public float SineEaseOut(float p) | |
{ | |
return Math.Sin(p * HALFPI); | |
} | |
/// <summary> | |
/// Modeled after half sine wave | |
/// </summary> | |
static public float SineEaseInOut(float p) | |
{ | |
return 0.5f * (1 - Math.Cos(p * PI)); | |
} | |
/// <summary> | |
/// Modeled after shifted quadrant IV of unit circle | |
/// </summary> | |
static public float CircularEaseIn(float p) | |
{ | |
return 1 - Math.Sqrt(1 - (p * p)); | |
} | |
/// <summary> | |
/// Modeled after shifted quadrant II of unit circle | |
/// </summary> | |
static public float CircularEaseOut(float p) | |
{ | |
return Math.Sqrt((2 - p) * p); | |
} | |
/// <summary> | |
/// Modeled after the piecewise circular function | |
/// y = (1/2)(1 - Math.Sqrt(1 - 4x^2)) ; [0, 0.5) | |
/// y = (1/2)(Math.Sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] | |
/// </summary> | |
static public float CircularEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 0.5f * (1 - Math.Sqrt(1 - 4 * (p * p))); | |
} | |
else | |
{ | |
return 0.5f * (Math.Sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); | |
} | |
} | |
/// <summary> | |
/// Modeled after the exponential function y = 2^(10(x - 1)) | |
/// </summary> | |
static public float ExponentialEaseIn(float p) | |
{ | |
return (p == 0.0f) ? p : Math.Pow(2, 10 * (p - 1)); | |
} | |
/// <summary> | |
/// Modeled after the exponential function y = -2^(-10x) + 1 | |
/// </summary> | |
static public float ExponentialEaseOut(float p) | |
{ | |
return (p == 1.0f) ? p : 1 - Math.Pow(2, -10 * p); | |
} | |
/// <summary> | |
/// 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] | |
/// </summary> | |
static public float ExponentialEaseInOut(float p) | |
{ | |
if (p == 0.0 || p == 1.0) return p; | |
if (p < 0.5f) | |
{ | |
return 0.5f * Math.Pow(2, (20 * p) - 10); | |
} | |
else | |
{ | |
return -0.5f * Math.Pow(2, (-20 * p) + 10) + 1; | |
} | |
} | |
/// <summary> | |
/// Modeled after the damped sine wave y = sin(13pi/2*x)*Math.Pow(2, 10 * (x - 1)) | |
/// </summary> | |
static public float ElasticEaseIn(float p) | |
{ | |
return Math.Sin(13 * HALFPI * p) * Math.Pow(2, 10 * (p - 1)); | |
} | |
/// <summary> | |
/// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*Math.Pow(2, -10x) + 1 | |
/// </summary> | |
static public float ElasticEaseOut(float p) | |
{ | |
return Math.Sin(-13 * HALFPI * (p + 1)) * Math.Pow(2, -10 * p) + 1; | |
} | |
/// <summary> | |
/// Modeled after the piecewise exponentially-damped sine wave: | |
/// y = (1/2)*sin(13pi/2*(2*x))*Math.Pow(2, 10 * ((2*x) - 1)) ; [0,0.5) | |
/// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*Math.Pow(2,-10(2*x-1)) + 2) ; [0.5, 1] | |
/// </summary> | |
static public float ElasticEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 0.5f * Math.Sin(13 * HALFPI * (2 * p)) * Math.Pow(2, 10 * ((2 * p) - 1)); | |
} | |
else | |
{ | |
return 0.5f * (Math.Sin(-13 * HALFPI * ((2 * p - 1) + 1)) * Math.Pow(2, -10 * (2 * p - 1)) + 2); | |
} | |
} | |
/// <summary> | |
/// Modeled after the overshooting cubic y = x^3-x*sin(x*pi) | |
/// </summary> | |
static public float BackEaseIn(float p) | |
{ | |
return p * p * p - p * Math.Sin(p * PI); | |
} | |
/// <summary> | |
/// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) | |
/// </summary> | |
static public float BackEaseOut(float p) | |
{ | |
float f = (1 - p); | |
return 1 - (f * f * f - f * Math.Sin(f * PI)); | |
} | |
/// <summary> | |
/// 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] | |
/// </summary> | |
static public float BackEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
float f = 2 * p; | |
return 0.5f * (f * f * f - f * Math.Sin(f * PI)); | |
} | |
else | |
{ | |
float f = (1 - (2 * p - 1)); | |
return 0.5f * (1 - (f * f * f - f * Math.Sin(f * PI))) + 0.5f; | |
} | |
} | |
/// <summary> | |
/// </summary> | |
static public float BounceEaseIn(float p) | |
{ | |
return 1 - BounceEaseOut(1 - p); | |
} | |
/// <summary> | |
/// </summary> | |
static public float BounceEaseOut(float p) | |
{ | |
if (p < 4 / 11.0f) | |
{ | |
return (121 * p * p) / 16.0f; | |
} | |
else if (p < 8 / 11.0f) | |
{ | |
return (363 / 40.0f * p * p) - (99 / 10.0f * p) + 17 / 5.0f; | |
} | |
else if (p < 9 / 10.0f) | |
{ | |
return (4356 / 361.0f * p * p) - (35442 / 1805.0f * p) + 16061 / 1805.0f; | |
} | |
else | |
{ | |
return (54 / 5.0f * p * p) - (513 / 25.0f * p) + 268 / 25.0f; | |
} | |
} | |
/// <summary> | |
/// </summary> | |
static public float BounceEaseInOut(float p) | |
{ | |
if (p < 0.5f) | |
{ | |
return 0.5f * BounceEaseIn(p * 2); | |
} | |
else | |
{ | |
return 0.5f * BounceEaseOut(p * 2 - 1) + 0.5f; | |
} | |
} | |
//goes from 0 -> 1 -> 0 | |
static public float PingPong(float p) | |
{ | |
if (p <= .5f) | |
{ | |
return p * 2f; | |
} | |
else | |
{ | |
return 1f - 2 * (p - .5f); | |
} | |
} | |
} | |
} |
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
using Core.Utils; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace Core.Movement | |
{ | |
public class SquashController : HashSet<Squash> | |
{ | |
public float SquashAmt; | |
public Transform SquashTarget; | |
public SquashController(Transform trans, float amt) | |
{ | |
this.SquashTarget = trans; | |
this.SquashAmt = amt; | |
} | |
Queue<Squash> removeQueue = new Queue<Squash>(); | |
public void Update(float dt) | |
{ | |
Vector2 buffer = Vector2.zero; | |
foreach( var s in this) | |
{ | |
s.Update(dt); | |
if (s.IsComplete) | |
removeQueue.Enqueue(s); | |
buffer += s.Value; | |
} | |
while (removeQueue.Count > 0) | |
{ | |
var removal = removeQueue.Dequeue(); | |
if (removal.Next != null) | |
this.Add(removal.Next); | |
this.Remove(removal); | |
} | |
var targetSquash = new Vector3(1 + buffer.x * SquashAmt, 1 + buffer.y * SquashAmt, 1f); | |
SquashTarget.localScale = targetSquash; | |
} | |
} | |
public class Squash | |
{ | |
public float Duration; | |
private Vector2 StartAlpha; | |
public Vector2 EndAlpha; | |
private Easing.Functions EaseFunc; | |
public static Vector2 Wide = new Vector2(1f, -1f); | |
public static Vector2 Thin = new Vector2(-1f, 1f); | |
public static Vector2 Zero = new Vector2(0f, 0f); | |
public Squash Next; | |
float Alpha => Mathf.Clamp01(accum / Duration); | |
float EasedAlpha { | |
get { | |
return Easing.Interpolate(Alpha, EaseFunc); | |
} | |
} | |
public bool IsComplete => Alpha == 1f; | |
float accum = 0f; | |
public Vector2 Value { | |
get { | |
return Vector2.LerpUnclamped(StartAlpha, EndAlpha, EasedAlpha); | |
} | |
} | |
public Squash(float duration, Vector2 startAlpha, Vector2 endAlpha, float axisNoise = 0f, Easing.Functions func = Easing.Functions.ElasticEaseOut) | |
{ | |
Duration = duration; | |
this.StartAlpha = startAlpha; | |
if(axisNoise != 0f) | |
{ | |
var noise = UnityEngine.Random.Range(-axisNoise, axisNoise); | |
StartAlpha.x += noise; | |
StartAlpha.y -= noise; | |
} | |
this.EndAlpha = endAlpha; | |
this.EaseFunc = func; | |
} | |
public Squash(float duration, Vector2 endAlpha, Easing.Functions func = Easing.Functions.ElasticEaseOut) | |
{ | |
Duration = duration; | |
this.StartAlpha = Zero; | |
this.EndAlpha = endAlpha; | |
this.EaseFunc = func; | |
} | |
public Squash Then(Squash next) | |
{ | |
this.Next = next; | |
this.Next.StartAlpha = this.EndAlpha; | |
return this; | |
} | |
public void Update(float dt) | |
{ | |
accum += dt; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment