October3d55/M/LGUI/Source/LTween/Public/LTweener.h

701 lines
22 KiB
C++

// Copyright 2019-Present LexLiu. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Engine/EngineTypes.h"
#include "Engine/EngineBaseTypes.h"
#include "Engine/HitResult.h"
#include "LTweener.generated.h"
DECLARE_DELEGATE_RetVal_FourParams(float, FLTweenFunction, float, float, float, float);
DECLARE_DELEGATE_OneParam(FLTweenUpdateDelegate, float);
DECLARE_MULTICAST_DELEGATE_OneParam(FLTweenUpdateMulticastDelegate, float);
#ifndef LTweenUpdateDelegate
#define LTweenUpdateDelegate UE_DEPRECATED_MACRO(5.0, "LTweenUpdateDelegate has been renamed to FLTweenUpdateDelegate") FLTweenUpdateDelegate
#endif
#ifndef LTweenUpdateMulticastDelegate
#define LTweenUpdateMulticastDelegate UE_DEPRECATED_MACRO(5.0, "LTweenUpdateMulticastDelegate has been renamed to FLTweenUpdateMulticastDelegate") FLTweenUpdateMulticastDelegate
#endif
DECLARE_DELEGATE_RetVal(float, FLTweenFloatGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenFloatSetterFunction, float);
DECLARE_DELEGATE_RetVal(double, FLTweenDoubleGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenDoubleSetterFunction, double);
DECLARE_DELEGATE_RetVal(int, FLTweenIntGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenIntSetterFunction, int);
DECLARE_DELEGATE_RetVal(FVector, FLTweenVectorGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenVectorSetterFunction, FVector);
DECLARE_DELEGATE_RetVal(FColor, FLTweenColorGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenColorSetterFunction, FColor);
DECLARE_DELEGATE_RetVal(FLinearColor, FLTweenLinearColorGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenLinearColorSetterFunction, FLinearColor);
DECLARE_DELEGATE_RetVal(FVector2D, FLTweenVector2DGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenVector2DSetterFunction, FVector2D);
DECLARE_DELEGATE_RetVal(FVector4, FLTweenVector4GetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenVector4SetterFunction, FVector4);
DECLARE_DELEGATE_RetVal(FQuat, FLTweenQuaternionGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenQuaternionSetterFunction, const FQuat&);
DECLARE_DELEGATE_RetVal(FRotator, FLTweenRotatorGetterFunction);
DECLARE_DELEGATE_OneParam(FLTweenRotatorSetterFunction, FRotator);
DECLARE_DELEGATE_RetVal(FVector, FLTweenPositionGetterFunction);
DECLARE_DELEGATE_FourParams(FLTweenPositionSetterFunction, FVector, bool, FHitResult*, ETeleportType);
DECLARE_DELEGATE_RetVal(FQuat, FLTweenRotationQuatGetterFunction);
DECLARE_DELEGATE_FourParams(FLTweenRotationQuatSetterFunction, const FQuat&, bool, FHitResult*, ETeleportType);
DECLARE_DELEGATE_RetVal_OneParam(bool, FLTweenMaterialScalarGetterFunction, float&);
DECLARE_DELEGATE_RetVal_TwoParams(bool, FLTweenMaterialScalarSetterFunction, int32, float);
DECLARE_DELEGATE_RetVal_OneParam(bool, FLTweenMaterialVectorGetterFunction, FLinearColor&);
DECLARE_DELEGATE_RetVal_TwoParams(bool, FLTweenMaterialVectorSetterFunction, int32, const FLinearColor&);
/** simple delegate */
DECLARE_DYNAMIC_DELEGATE(FLTweenerSimpleDynamicDelegate);
/** @param InProgress Progress of this tween, from 0 to 1 */
DECLARE_DYNAMIC_DELEGATE_OneParam(FLTweenerFloatDynamicDelegate, float, InProgress);
/** */
UENUM(BlueprintType, Category = LTween)
enum class ELTweenTickType:uint8
{
PrePhysics = ETickingGroup::TG_PrePhysics UMETA(DisplayName = "Pre Physics"),
DuringPhysics = ETickingGroup::TG_DuringPhysics UMETA(DisplayName = "During Physics"),
PostPhysics = ETickingGroup::TG_PostPhysics UMETA(DisplayName = "Post Physics"),
PostUpdateWork = ETickingGroup::TG_PostUpdateWork UMETA(DisplayName = "Post Update Work"),
/** This tween will use manual tick. You need to call LTweenManager::ManualTick to make it work. */
Manual,
};
/**
* Animation curve type
*/
UENUM(BlueprintType, Category = LTween)
enum class ELTweenEase :uint8
{
Linear,
InQuad,
OutQuad,
InOutQuad,
InCubic,
OutCubic,
InOutCubic,
InQuart,
OutQuart,
InOutQuart,
InSine,
OutSine,
InOutSine,
InExpo,
OutExpo,
InOutExpo,
InCirc,
OutCirc,
InOutCirc,
InElastic,
OutElastic,
InOutElastic,
InBack,
OutBack,
InOutBack,
InBounce,
OutBounce,
InOutBounce,
/** Use CurveFloat to animate, only range 0-1 is valid. If use this you must assign curveFloat, or fallback to Linear. */
CurveFloat,
};
#ifndef LTweenEase
#define LTweenEase UE_DEPRECATED_MACRO(5.0, "LTweenEase has been renamed to ELTweenEase") ELTweenEase
#endif
/**
* Loop type
*/
UENUM(BlueprintType, Category = LGUI)
enum class ELTweenLoop :uint8
{
/** Play once, not loop */
Once,
/** Each loop cycle restarts from beginning */
Restart,
/** The tween move forward and backward at alternate cycles */
Yoyo,
/** Continuously increments the tween at the end of each loop cycle (A to B, B to B+(A-B), and so on). */
Incremental,
};
#ifndef LTweenLoop
#define LTweenLoop UE_DEPRECATED_MACRO(5.0, "LTweenLoop has been renamed to ELTweenLoop") ELTweenLoop
#endif
class UCurveFloat;
/** Class for manage single tween */
UCLASS(BlueprintType, Abstract)
class LTWEEN_API ULTweener : public UObject
{
GENERATED_BODY()
public:
ULTweener();
protected:
friend class ULTweenerSequence;
/** animation duration */
float duration = 0.0f;
/** delay time before animation start */
float delay = 0.0f;
/** total elapse time, include delay */
float elapseTime = 0.0f;
/** use CurveFloat as animation function,horizontal is time (0-1),vertical is value (0-1) */
TWeakObjectPtr<UCurveFloat> curveFloat = nullptr;
/** loop type */
ELTweenLoop loopType = ELTweenLoop::Once;
/** max loop count when loop type is Restart/Yoyo/Incremental */
int32 maxLoopCount = 0;
/** current completed cycle count */
int32 loopCycleCount = 0;
/** how this tween update */
ELTweenTickType tickType = ELTweenTickType::DuringPhysics;
/** reverse animation */
bool reverseTween = false;
/** if animation start play */
bool startToTween = false;
/** mark this tween for kill, so when the next update came, the tween will be killed */
bool isMarkedToKill = false;
/** mark this tween as pause, it will keep pause until call Resume() */
bool isMarkedPause = false;
/** will this tween be affected when GamePause? usually set to false for UI */
bool affectByGamePause = true;
/** will this tween use dilation-time or real-time? */
bool affectByTimeDilation = true;
/** tween function */
FLTweenFunction tweenFunc;
/** call once after animation complete */
FSimpleDelegate onCompleteCpp;
/** if use loop, this will call every time when begin tween in every cycle */
FSimpleDelegate onCycleStartCpp;
/** if use loop, this will call every time after tween complete in every cycle */
FSimpleDelegate onCycleCompleteCpp;
/** call every frame after animation starts */
FLTweenUpdateDelegate onUpdateCpp;
/** call once when animation starts */
FSimpleDelegate onStartCpp;
public:
/**
* Set animation curve type.
* Has no effect if the Tween has already started.
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* SetEase(ELTweenEase easetype);
/** set ease to CurveFloat and use CurveFloat as animation function, horizontal is time (0-1),vertical is value (0-1) */
UE_DEPRECATED(4.23, "SetEaseCurve is not valid anymore, use SetEase and SetCurveFloat instead.")
UFUNCTION(BlueprintCallable, Category = "LTween", meta = (DeprecatedFunction, DeprecationMessage = "SetEaseCurve is not valid anymore, use SetEase and SetCurveFloat instead."))
ULTweener* SetEaseCurve(UCurveFloat* newCurve);
/**
* Set delay time before start animation.
* Has no effect if the Tween has already started.
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual ULTweener* SetDelay(float newDelay);
UE_DEPRECATED(4.23, "SetLoopType not valid anymore, use SetLoop instead.")
UFUNCTION(BlueprintCallable, Category = "LTween", meta = (DeprecatedFunction, DeprecationMessage = "SetLoopType not valid anymore, use SetLoop instead."))
virtual ULTweener* SetLoopType(ELTweenLoop newLoopType)
{
return SetLoop(newLoopType, -1);
}
/**
* Set loop of tween.
* Has no effect if the Tween has already started.
* @param newLoopType loop type
* @param newLoopCount number of cycles to play (-1 for infinite)
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual ULTweener* SetLoop(ELTweenLoop newLoopType, int32 newLoopCount = 1);
UE_DEPRECATED(4.23, "GetLoopCount not valid anymore, use GetLoopCycleCount instead.")
UFUNCTION(BlueprintCallable, Category = "LTween", meta = (DeprecatedFunction, DeprecationMessage = "GetLoopCount not valid anymore, use GetLoopCycleCount instead."))
int32 GetLoopCount() { return loopCycleCount; }
/** curently completed loop cycle count */
UFUNCTION(BlueprintCallable, Category = "LTween")
int32 GetLoopCycleCount()const { return loopCycleCount; }
/** execute when animation complete */
ULTweener* OnComplete(const FSimpleDelegate& newComplete)
{
this->onCompleteCpp = newComplete;
return this;
}
/** execute when animation complete */
ULTweener* OnComplete(const TFunction<void()>& newComplete)
{
if (newComplete != nullptr)
{
this->onCompleteCpp.BindLambda(newComplete);
}
return this;
}
/** execute when animation complete */
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* OnComplete(const FLTweenerSimpleDynamicDelegate& newComplete)
{
this->onCompleteCpp.BindLambda([newComplete] {
newComplete.ExecuteIfBound();
});
return this;
}
/** if use loop, this will call every time after tween complete in every cycle */
ULTweener* OnCycleComplete(const FSimpleDelegate& newCycleComplete)
{
this->onCycleCompleteCpp = newCycleComplete;
return this;
}
/** if use loop, this will call every time after tween complete in every cycle */
ULTweener* OnCycleComplete(const TFunction<void()>& newCycleComplete)
{
if (newCycleComplete != nullptr)
{
this->onCycleCompleteCpp.BindLambda(newCycleComplete);
}
return this;
}
/** if use loop, this will call every time after tween complete in every cycle */
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* OnCycleComplete(const FLTweenerSimpleDynamicDelegate& newCycleComplete)
{
this->onCycleCompleteCpp.BindLambda([newCycleComplete] {
newCycleComplete.ExecuteIfBound();
});
return this;
}
/** if use loop, this will call every time when begin tween in every cycle */
ULTweener* OnCycleStart(const FSimpleDelegate& newCycleStart)
{
this->onCycleStartCpp = newCycleStart;
return this;
}
/** if use loop, this will call every time when begin tween in every cycle */
ULTweener* OnCycleStart(const TFunction<void()>& newCycleStart)
{
if (newCycleStart != nullptr)
{
this->onCycleStartCpp.BindLambda(newCycleStart);
}
return this;
}
/** if use loop, this will call every time when begin tween in every cycle */
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* OnCycleStart(const FLTweenerSimpleDynamicDelegate& newCycleStart)
{
this->onCycleStartCpp.BindLambda([newCycleStart] {
newCycleStart.ExecuteIfBound();
});
return this;
}
/** execute every frame if animation is playing */
ULTweener* OnUpdate(const FLTweenUpdateDelegate& newUpdate)
{
this->onUpdateCpp = newUpdate;
return this;
}
/** execute every frame if animation is playing */
ULTweener* OnUpdate(const TFunction<void(float)>& newUpdate)
{
if (newUpdate != nullptr)
{
this->onUpdateCpp.BindLambda(newUpdate);
}
return this;
}
/** execute every frame if animation is playing */
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* OnUpdate(const FLTweenerFloatDynamicDelegate& newUpdate)
{
this->onUpdateCpp.BindLambda([newUpdate](float progress) {
newUpdate.ExecuteIfBound(progress);
});
return this;
}
/** execute when animation start*/
ULTweener* OnStart(const FSimpleDelegate& newStart)
{
this->onStartCpp = newStart;
return this;
}
/** execute when animation start, blueprint version*/
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* OnStart(const FLTweenerSimpleDynamicDelegate& newStart)
{
this->onStartCpp.BindLambda([newStart] {
newStart.ExecuteIfBound();
});
return this;
}
/** execute when animation start, lambda version*/
ULTweener* OnStart(const TFunction<void()>& newStart)
{
if (newStart != nullptr)
{
this->onStartCpp.BindLambda(newStart);
}
return this;
}
/**
* Set CurveFloat as animation curve. Make sure ease type is CurveFloat. (Call SetEase function to set ease type)
* Has no effect if the Tween has already started.
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* SetCurveFloat(UCurveFloat* newCurveFloat);
/**
* @return false: the tween is complete and need to be killed. true: the tween is still processing.
*/
virtual bool ToNext(float deltaTime, float unscaledDeltaTime);
/**
* @return false: the tween is complete and need to be killed. true: the tween is still processing.
*/
bool ToNextWithElapsedTime(float InElapseTime);
/** Force stop this animation. if callComplete = true, will call OnComplete after stop*/
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual void Kill(bool callComplete = false);
/** Force stop this animation at this frame, set value to end, call OnComplete. */
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual void ForceComplete();
/** Pause this animation. */
UFUNCTION(BlueprintCallable, Category = "LTween")
void Pause()
{
isMarkedPause = true;
}
/** Continue play animation if is paused. */
UFUNCTION(BlueprintCallable, Category = "LTween")
void Resume()
{
isMarkedPause = false;
}
/** Will this tween be affected when GamePause? Default is true, usually set to false for UI. */
UFUNCTION(BlueprintCallable, Category = "LTween")
bool GetAffectByGamePause()const { return affectByGamePause; }
/** Will this tween be affected when GamePause? Default is true, usually set to false for UI. */
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* SetAffectByGamePause(bool value);
/** will this tween use dilated-time or real-time? */
UFUNCTION(BlueprintCallable, Category = "LTween")
bool GetAffectByTimeDilation()const { return affectByTimeDilation; }
/** will this tween use dilated-time or real-time? */
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* SetAffectByTimeDilation(bool value);
/**
* Restart animation.
* Has no effect if the Tween is not started.
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual void Restart();
/**
* Send the tween to the given position in time.
* @param timePoint Time position to reach (if higher than the whole tween duration the tween will simply reach its end).
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual void Goto(float timePoint);
/** Return progress 0-1 */
UFUNCTION(BlueprintCallable, Category = "LTween")
virtual float GetProgress()const;
UFUNCTION(BlueprintCallable, Category = "LTween")
float GetElapsedTime()const { return elapseTime; }
UFUNCTION(BlueprintCallable, Category = "LTween")
float GetDuration()const { return duration; }
/** Return tickType of this tween, default is DuringPhysics. */
UFUNCTION(BlueprintCallable, Category = "LTween")
ELTweenTickType GetTickType()const { return tickType; }
/**
* Set TickType of this tween.
* Has no effect if the Tween has already started.
*/
UFUNCTION(BlueprintCallable, Category = "LTween")
ULTweener* SetTickType(ELTweenTickType value = ELTweenTickType::DuringPhysics);
protected:
/** get value when start. child class must override this, check LTweenerFloat for reference */
virtual void OnStartGetValue() PURE_VIRTUAL(ULTweener::OnStartGetValue, );
/** set value when tweening. child class must override this, check LTweenerFloat for reference */
virtual void TweenAndApplyValue(float currentTime) PURE_VIRTUAL(ULTweener::TweenAndApplyValue, );
/** set start and end value if looptype is Incremental. */
virtual void SetValueForIncremental() PURE_VIRTUAL(ULTweener::SetValueForIncremental, );
/** set start and end value before the animation wan't to restart */
virtual void SetOriginValueForRestart() PURE_VIRTUAL(ULTweener::SetOriginValueForRestart, );
virtual void SetValueForYoyo() {};
virtual void SetValueForRestart() {};
#pragma region tweenFunctions
public:
/**
* @param c Change needed in value.
* @param b Starting value.
* @param t Current time (in frames or seconds).
* @param d Expected eaSing duration (in frames or seconds).
* @return The correct value.
*/
static float Linear(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return c*t / d + b;
}
static float InQuad(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d;
return c*t*t + b;
}
static float OutQuad(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d;
return -c*t*(t - 2) + b;
}
static float InOutQuad(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d * 0.5f;
if (t < 1)
{
return c * 0.5f * t*t + b;
}
else
{
--t;
return -c * 0.5f * (t*(t - 2) - 1) + b;
}
}
static float InCubic(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d;
return c*t*t*t + b;
}
static float OutCubic(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t = t / d - 1.0f;
return c*(t*t*t + 1) + b;
}
static float InOutCubic(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d * 0.5f;
if (t < 1)
{
return c * 0.5f * t*t*t + b;
}
else
{
t -= 2;
return c * 0.5f * (t*t*t + 2) + b;
}
}
static float InQuart(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d;
return c*t*t*t*t + b;
}
static float OutQuart(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t = t / d - 1.0f;
return -c * (t*t*t*t - 1) + b;
}
static float InOutQuart(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d * 0.5f;
if (t < 1)
{
return c * 0.5f * t*t*t*t + b;
}
else
{
t -= 2;
return -c * 0.5f * (t*t*t*t - 2) + b;
}
}
static float InSine(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return -c * FMath::Cos(t / d * HALF_PI) + c + b;
}
static float OutSine(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return c * FMath::Sin(t / d * HALF_PI) + b;
}
static float InOutSine(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return -c * 0.5f * (FMath::Cos(PI * t / d) - 1) + b;
}
static float InExpo(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return (t == 0.0f) ? b : c * FMath::Pow(2.0f, 10.0f * (t / d - 1.0f)) + b - c * 0.001f;
}
static float OutExpo(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return (t == d) ? b + c : c * 1.001f * (-FMath::Pow(2.0f, -10.0f * t / d) + 1.0f) + b;
}
static float InOutExpo(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
if (t == 0) return b;
if (t == d) return b + c;
t /= d * 0.5f;
if (t < 1.0f)
{
return c * 0.5f * FMath::Pow(2.0f, 10.0f * (t - 1.0f)) + b - c * 0.0005f;
}
else
{
return c * 0.5f * 1.0005f * (-FMath::Pow(2.0f, -10.0f * (t - 1.0f)) + 2.0f) + b;
}
}
static float InCirc(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d;
return -c * (FMath::Sqrt(1.0f - t*t) - 1.0f) + b;
}
static float OutCirc(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t = t / d - 1.0f;
return c * FMath::Sqrt(1.0f - t*t) + b;
}
static float InOutCirc(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d * 0.5f;
if (t < 1)
{
return -c * 0.5f * (FMath::Sqrt(1 - t * t) - 1) + b;
}
else
{
t -= 2.0f;
return c * 0.5f * (FMath::Sqrt(1.0f - t*t) + 1.0f) + b;
}
}
static float InElastic(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
if (t == 0) return b;
t /= d;
if (t == 1) return b + c;
float p = d*0.3f;
float s = p / 4;
float a = c;
t -= 1.0f;
return -(a*FMath::Pow(2.0f, 10.0f * t) * FMath::Sin((t*d - s)*(2.0f * PI) / p)) + b;
}
static float OutElastic(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
if (t == 0) return b;
t /= d;
if (t == 1) return b + c;
float p = d*0.3f;
float s = p / 4;
float a = c;
return (a*FMath::Pow(2.0f, -10.0f * t) * FMath::Sin((t*d - s)*(2.0f * PI) / p) + c + b);
}
static float InOutElastic(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
if (t == 0) return b;
t /= d * 0.5f;
if (t == 2) return b + c;
float p = d*0.3f;
float s = p / 4;
float a = c;
if (t < 1.0f)
{
t -= 1.0f;
return -0.5f*(a*FMath::Pow(2.0f, 10.0f * t) * FMath::Sin((t*d - s)*(2.0f * PI) / p)) + b;
}
else
{
t -= 1.0f;
return a * FMath::Pow(2.0f, -10.0f * t) * FMath::Sin((t*d - s)*(2.0f * PI) / p)*0.5f + c + b;
}
}
static float InBack(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
static float s = 1.70158f;
t /= d;
return c*t*t*((s + 1)*t - s) + b;
}
static float OutBack(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
static float s = 1.70158f;
t = t / d - 1;
return c*(t*t*((s + 1)*t + s) + 1) + b;
}
static float InOutBack(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
if (t < d * 0.5f) return InBack(c, 0, t * 2, d) * .5f + b;
else return OutBack(c, 0, t * 2 - d, d) * .5f + c * .5f + b;
}
static float OutBounce(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
t /= d;
if (t < (1.0f / 2.75f)) {
return c*(7.5625f*t*t) + b;
}
else if (t < (2.0f / 2.75f)) {
t -= (1.5f / 2.75f);
return c*(7.5625f*t*t + .75f) + b;
}
else if (t < (2.5f / 2.75f)) {
t -= (2.25f / 2.75f);
return c*(7.5625f*t*t + .9375f) + b;
}
else {
t -= (2.625f / 2.75f);
return c*(7.5625f*t*t + .984375f) + b;
}
}
static float InBounce(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
return c - OutBounce(c, 0, d - t, d) + b;
}
static float InOutBounce(float c, float b, float t, float d)
{
if (d < KINDA_SMALL_NUMBER)return c + b;
if (t < d * 0.5f) return InBounce(c, 0, t * 2, d) * .5f + b;
else return OutBounce(c, 0, t * 2 - d, d) * .5f + c * .5f + b;
}
/** Tween use CurveFloat, in range of 0-1. if curveFloat is null, fallback to Linear */
float CurveFloat(float c, float b, float t, float d);
#pragma endregion
};