using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using System;
using UnityEngine.Events;
public enum Direction
{
Reverse = -1,
Toggle = 0,
Forward = 1,
}
public enum EnableCondition
{
DoNothing = 0,
EnableThenPlay,
}
public enum DisableCondition
{
DisableAfterReverse = -1,
DoNotDisable = 0,
DisableAfterForward = 1,
}
///
/// Base class for all tweening operations.
///
public abstract class Tweener : MonoBehaviour
{
///
/// Current tween that triggered the callback function.
///
static public Tweener current {
get;
private set;
}
public enum Method
{
Linear,
EaseIn,
EaseOut,
EaseInOut,
BounceIn,
BounceOut,
}
public enum Style
{
Once,
Loop,
PingPong,
}
///
/// Tweening method used.
///
public Method method = Method.Linear;
///
/// Does it play once? Does it loop?
///
public Style style = Style.Once;
///
/// Optional curve to apply to the tween's time factor value.
///
public AnimationCurve animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
///
/// How long will the tweener wait before starting the tween?
///
public float delay = 0f;
public bool noDelayWhenReverse = false;
///
/// How long is the duration of the tween?
///
public float duration = 1f;
///
/// Whether the tweener will use steeper curves for ease in / out style interpolation.
///
public bool steeperCurves = false;
///
/// Used by buttons and tween sequences. Group of '0' means not in a sequence.
///
public int tweenGroup = 0;
///
/// Event delegates called when the anim finishes.
///
[SerializeField, HideInInspector]
UnityEvent m_OnFinished = new UnityEvent();
public Action onFinished;
bool mStarted = false;
float mStartTime = 0f;
float mDuration = 0f;
float mAmountPerDelta = 1000f;
float mFactor = 0f;
///
/// Amount advanced per delta time.
///
public float amountPerDelta {
get {
if (mDuration != duration)
{
mDuration = duration;
mAmountPerDelta = Mathf.Abs((duration > 0f) ? 1f / duration : 1000f);
}
return mAmountPerDelta;
}
}
///
/// Tween factor, 0-1 range.
///
public float tweenFactor {
get {
return mFactor;
}
set {
mFactor = Mathf.Clamp01(value);
}
}
///
/// Direction that the tween is currently playing in.
///
public Direction direction {
get {
return mAmountPerDelta < 0f ? Direction.Reverse : Direction.Forward;
}
}
void Reset()
{
if (!mStarted)
{
SetStartToCurrentValue();
SetEndToCurrentValue();
}
}
protected virtual void Awake()
{
onFinished += m_OnFinished.Invoke;
}
protected virtual void Start()
{
Update();
}
void Update()
{
float delta = Time.deltaTime;
float time = Time.time;
if (!mStarted)
{
mStarted = true;
if (noDelayWhenReverse)
{
if (direction == Direction.Reverse)
mStartTime = time;
else
mStartTime = time + delay;
}
else
{
mStartTime = time + delay;
}
}
if (time < mStartTime)
return;
// Advance the sampling factor
mFactor += amountPerDelta * delta;
// Loop style simply resets the play factor after it exceeds 1.
if (style == Style.Loop)
{
if (mFactor > 1f)
{
mFactor -= Mathf.Floor(mFactor);
}
}
else if (style == Style.PingPong)
{
// Ping-pong style reverses the direction
if (mFactor > 1f)
{
mFactor = 1f - (mFactor - Mathf.Floor(mFactor));
mAmountPerDelta = -mAmountPerDelta;
}
else if (mFactor < 0f)
{
mFactor = -mFactor;
mFactor -= Mathf.Floor(mFactor);
mAmountPerDelta = -mAmountPerDelta;
}
}
// If the factor goes out of range and this is a one-time tweening operation, disable the script
if ((style == Style.Once) && (duration == 0f || mFactor > 1f || mFactor < 0f))
{
mFactor = Mathf.Clamp01(mFactor);
Sample(mFactor, true);
// Disable this script unless the function calls above changed something
if (duration == 0f || (mFactor == 1f && mAmountPerDelta > 0f || mFactor == 0f && mAmountPerDelta < 0f))
enabled = false;
current = this;
if (onFinished != null)
{
onFinished();
}
current = null;
}
else
Sample(mFactor, false);
}
///
/// Mark as not started when finished to enable delay on next play.
///
void OnDisable()
{
mStarted = false;
}
///
/// Sample the tween at the specified factor.
///
public void Sample(float factor, bool isFinished)
{
// Calculate the sampling value
float val = Mathf.Clamp01(factor);
if (method == Method.EaseIn)
{
val = 1f - Mathf.Sin(0.5f * Mathf.PI * (1f - val));
if (steeperCurves)
val *= val;
}
else if (method == Method.EaseOut)
{
val = Mathf.Sin(0.5f * Mathf.PI * val);
if (steeperCurves)
{
val = 1f - val;
val = 1f - val * val;
}
}
else if (method == Method.EaseInOut)
{
const float pi2 = Mathf.PI * 2f;
val = val - Mathf.Sin(val * pi2) / pi2;
if (steeperCurves)
{
val = val * 2f - 1f;
float sign = Mathf.Sign(val);
val = 1f - Mathf.Abs(val);
val = 1f - val * val;
val = sign * val * 0.5f + 0.5f;
}
}
else if (method == Method.BounceIn)
{
val = BounceLogic(val);
}
else if (method == Method.BounceOut)
{
val = 1f - BounceLogic(1f - val);
}
// Call the virtual update
OnUpdate((animationCurve != null) ? animationCurve.Evaluate(val) : val, isFinished);
}
///
/// main Bounce logic to simplify the Sample function
///
float BounceLogic(float val)
{
if (val < 0.363636f) // 0.363636 = (1/ 2.75)
{
val = 7.5685f * val * val;
}
else if (val < 0.727272f) // 0.727272 = (2 / 2.75)
{
val = 7.5625f * (val -= 0.545454f) * val + 0.75f; // 0.545454f = (1.5 / 2.75)
}
else if (val < 0.909090f) // 0.909090 = (2.5 / 2.75)
{
val = 7.5625f * (val -= 0.818181f) * val + 0.9375f; // 0.818181 = (2.25 / 2.75)
}
else
{
val = 7.5625f * (val -= 0.9545454f) * val + 0.984375f; // 0.9545454 = (2.625 / 2.75)
}
return val;
}
///
/// Play the tween forward.
///
public void PlayForward()
{
Play(true);
}
///
/// Play the tween in reverse.
///
public void PlayReverse()
{
Play(false);
}
///
/// Stop the tween.
///
public void Stop()
{
enabled = false;
}
///
/// Manually activate the tweening process, reversing it if necessary.
///
public virtual void Play(bool forward)
{
enabled = true;
mAmountPerDelta = Mathf.Abs(amountPerDelta);
if (!forward)
mAmountPerDelta = -mAmountPerDelta;
ResetToBeginning();
Update();
}
///
/// Manually reset the tweener's state to the beginning.
///
public void ResetToBeginning()
{
mStarted = false;
mFactor = (mAmountPerDelta < 0f) ? 1f : 0f;
Sample(mFactor, false);
}
///
/// Manually start the tweening process, reversing its direction.
///
public void Toggle()
{
if (mFactor > 0f)
{
mAmountPerDelta = -amountPerDelta;
}
else
{
mAmountPerDelta = Mathf.Abs(amountPerDelta);
}
enabled = true;
}
///
/// Actual tweening logic should go here.
///
abstract protected void OnUpdate(float factor, bool isFinished);
///
/// Starts the tweening operation.
///
static public T Begin(GameObject go, float duration) where T : Tweener
{
T comp = go.GetComponent();
if (comp == null)
comp = go.AddComponent();
//comp.onFinished = null;
comp.mStarted = false;
comp.duration = duration;
comp.mFactor = 0f;
comp.mAmountPerDelta = Mathf.Abs(comp.mAmountPerDelta);
comp.style = Style.Once;
comp.animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
comp.enabled = true;
comp.onFinished = null;
comp.m_OnFinished = new UnityEvent();
if (duration <= 0f)
{
comp.Sample(1f, true);
comp.enabled = false;
}
return comp;
}
///
/// Set the 'from' value to the current one.
///
public virtual void SetStartToCurrentValue()
{
}
///
/// Set the 'to' value to the current one.
///
public virtual void SetEndToCurrentValue()
{
}
}