http://www.manew.com/forum.php?mod=viewthread&tid=40974&_dsign=defca2f0
http://www.manew.com/thread-41005-1-1.html?_dsign=5f27272b
1、EasingControl.cs 实现动画的状态、时间类型、播放开始、结束
using UnityEngine;
using System.Collections;
using System;
/// <summary>
/// 1、遵循一定的渐变曲线生成一个数值,同时将这个数值应用到动画中
/// </summary>
public class EasingControl : MonoBehaviour{
void OnEnable ()
{
Resume();
}
void OnDisable ()
{
Pause();
}
#region 注册事件类型
public event EventHandler updateEvent;
public event EventHandler stateChangeEvent;
public event EventHandler completedEvent;
public event EventHandler loopedEvent;
#endregion
#region 定义枚举类
/// <summary>
/// 1、Normal 正常更新,timescale为0时,停止运动
/// 2、Real 可以忽略timescale为0是,正常运动
/// 3、Fixed 可用于物理更新
/// <summary>
public enum TimeType
{
Normal,
Real,
Fixed,
};
/// <summary>
/// 当前控制器的状态
/// Stopped
/// Paused
/// Playing
/// Reversing
/// </summary>
public enum PlayState
{
Stopped,
Paused,
Playing,
Reversing,
};
/// <summary>
/// 当动画结束时,我们可能希望让它保持最后的位置或是重置为开始位置
/// Constant
/// Reset
/// </summary>
public enum EndBehaviour
{
Constant,
Reset,
};
/// <summary>
/// 如果启用了循环,我们可能希望重置各个循环,或是倒序播放回到开始状态
/// Repeat
/// PingPong
/// </summary>
public enum LoopType
{
Repeat,
PingPong,
};
#endregion
#region 枚举变量
public TimeType timeType = TimeType.Normal;
public PlayState playState { get; private set; }
public PlayState previousPlayState { get; private set; }
public EndBehaviour endBehaviour = EndBehaviour.Constant;
public LoopType loopType = LoopType.Repeat;
public bool IsPlaying { get { return playState == PlayState.Playing || playState == PlayState.Reversing; }}
#endregion
#region 公用变量
/// <summary>
/// 开始位置
/// </summary>
public float startValue = 0.0f;
/// <summary>
/// 结束位置
/// </summary>
public float endValue = 1.0f;
/// <summary>
/// 动画播放持续时间
/// </summary>
public float duration = 1.0f;
/// <summary>
/// 动画循环次数
/// </summary>
public int loopCount = 0;
/// <summary>
/// 代理数值
/// </summary>
public Func<float, float, float, float> equation = EasingEquations.Linear;
/// <summary>
/// 当前时间,范围为0到给定的时长之间
/// </summary>
public float currentTime { get; private set; }
/// <summary>
/// 当前值,由渐变方程在任意时间计算出的值
/// </summary>
public float currentValue { get; private set; }
/// <summary>
/// 当前偏移量,从最后一帧开始值改变的大小(大多情况下你不需要该值)
/// </summary>
public float currentOffset { get; private set; }
/// <summary>
/// 动画已经重复播放的次数
/// </summary>
public int loops { get; private set; }
#endregion
#region public methods
public void Play(){
SetPlayState (PlayState.Playing);
}
public void Reverse ()
{
SetPlayState(PlayState.Reversing);
}
public void Pause ()
{
SetPlayState(PlayState.Paused);
}
public void Resume ()
{
SetPlayState(previousPlayState);
}
public void Stop ()
{
SetPlayState(PlayState.Stopped);
loops = 0;
if (endBehaviour == EndBehaviour.Reset)
SeekToBeginning ();
}
public void SeekToTime (float time)
{
currentTime = Mathf.Clamp01(time / duration);
float newValue = (endValue - startValue) * currentTime + startValue;
currentOffset = newValue - currentValue;
currentValue = newValue;
if (updateEvent != null)
updateEvent(this, EventArgs.Empty);
}
public void SeekToBeginning ()
{
SeekToTime(0.0f);
}
public void SeekToEnd ()
{
SeekToTime(duration);
}
public void SetPlayState(PlayState target){
if(playState == target){
return;
}
previousPlayState = playState;
playState = target;
if(stateChangeEvent != null){
stateChangeEvent (this,EventArgs.Empty);
}
StopCoroutine ("Ticker");
if(IsPlaying){
StartCoroutine ("Ticker");
}
}
IEnumerator Ticker ()
{
while (true)
{
switch (timeType)
{
case TimeType.Normal:
yield return new WaitForEndOfFrame();
Tick(Time.deltaTime);
break;
case TimeType.Real:
yield return new WaitForEndOfFrame();
Tick(Time.unscaledDeltaTime);
break;
default: // Fixed
yield return new WaitForFixedUpdate();
Tick(Time.fixedDeltaTime);
break;
}
}
}
void Tick (float time)
{
bool finished = false;
if (playState == PlayState.Playing)
{
currentTime = Mathf.Clamp01( currentTime + (time / duration));
finished = Mathf.Approximately(currentTime, 1.0f);
}
else // Reversing
{
currentTime = Mathf.Clamp01( currentTime - (time / duration));
finished = Mathf.Approximately(currentTime, 0.0f);
}
float frameValue = (endValue - startValue) * equation (0.0f, 1.0f, currentTime) + startValue;
currentOffset = frameValue - currentValue;
currentValue = frameValue;
if (updateEvent != null)
updateEvent(this, EventArgs.Empty);
if (finished)
{
++loops;
if (loopCount < 0 || loopCount >= loops)
{
if (loopType == LoopType.Repeat)
SeekToBeginning();
else // PingPong
SetPlayState( playState == PlayState.Playing ? PlayState.Reversing : PlayState.Playing );
if (loopedEvent != null)
loopedEvent(this, EventArgs.Empty);
}
else
{
if (completedEvent != null)
completedEvent(this, EventArgs.Empty);
Stop ();
}
}
}
#endregion
}
2、Tweener.cs 为抽象类包装EasingControl.cs,注册EasingControl的更新、完成事件
该类是所有处理具体动画子类的抽象基类。基类将用于处理一般任务例如创建渐变控制器,回调事件,以及在动画完成后进行清理。具体子类有各自特定的目的例如移动transform等。
using UnityEngine;
using System.Collections;
using System;
public abstract class Tweener : MonoBehaviour
{
#region Propeties
public static float DefaultDuration = 1f;
public static Func<float, float, float, float> DefaultEquation = EasingEquations.EaseInOutQuad;
public EasingControl easingControl;
public bool destroyOnComplete = true;
#endregion
#region MonoBehaviour
protected virtual void Awake ()
{
easingControl = gameObject.AddComponent<EasingControl> ();
}
protected virtual void OnEnable ()
{
easingControl.updateEvent += OnUpdate;
easingControl.completedEvent += OnComplete;
}
protected virtual void OnDisable ()
{
easingControl.updateEvent -= OnUpdate;
easingControl.completedEvent -= OnComplete;
}
protected virtual void OnDestroy ()
{
if (easingControl != null)
Destroy(easingControl);
}
#endregion
#region Event Handlers
protected abstract void OnUpdate (object sender, EventArgs e);
protected virtual void OnComplete (object sender, EventArgs e)
{
if (destroyOnComplete)
Destroy(this);
}
#endregion
}
3、Vector3Tweener.cs 初始化物体开始、结束、当前位置
我们正创建的具体子类的目的是改变transform的位置。我们需要插入的值类型是Vector3而不是float,也是渐变控制器自身使用的类型。
using UnityEngine;
using System.Collections;
public abstract class Vector3Tweener : Tweener {
public Vector3 startValue;
public Vector3 endValue;
public Vector3 currentValue { get; private set; }
protected override void OnUpdate (object sender, System.EventArgs e)
{
currentValue = (endValue - startValue) * easingControl.currentValue + startValue;
}
}
4、TransformPositionTweener.cs 获取当前移动的位置
现在来创建实际会用到的具体子类。
using UnityEngine;
using System.Collections;
public class TransformPositionTweener : Vector3Tweener {
protected override void OnUpdate (object sender, System.EventArgs e)
{
base.OnUpdate (sender, e);
transform.position = currentValue;
}
}
5、TransformExtensions.cs 用于扩展组件扩展类
using UnityEngine;
using System.Collections;
using System;
public static class TransformExtensions
{
public static Tweener MoveTo (this Transform t, Vector3 position)
{
return MoveTo (t, position, Tweener.DefaultDuration);
}
public static Tweener MoveTo (this Transform t, Vector3 position, float duration)
{
return MoveTo (t, position, duration, Tweener.DefaultEquation);
}
public static Tweener MoveTo (this Transform t, Vector3 position, float duration, Func<float, float, float, float> equation)
{
TransformPositionTweener tweener = t.gameObject.AddComponent<TransformPositionTweener> ();
tweener.startValue = t.position;
tweener.endValue = position;
tweener.easingControl.duration = duration;
tweener.easingControl.equation = equation;
tweener.easingControl.Play ();
return tweener;
}
// public static Tweener MoveToLocal (this Transform t, Vector3 position)
// {
// return MoveToLocal (t, position, Tweener.DefaultDuration);
// }
//
// public static Tweener MoveToLocal (this Transform t, Vector3 position, float duration)
// {
// return MoveToLocal (t, position, duration, Tweener.DefaultEquation);
// }
//
// public static Tweener MoveToLocal (this Transform t, Vector3 position, float duration, Func<float, float, float, float> equation)
// {
// TransformLocalPositionTweener tweener = t.gameObject.AddComponent<TransformLocalPositionTweener> ();
// tweener.startValue = t.localPosition;
// tweener.endValue = position;
// tweener.easingControl.duration = duration;
// tweener.easingControl.equation = equation;
// tweener.easingControl.Play ();
// return tweener;
// }
//
// public static Tweener ScaleTo (this Transform t, Vector3 scale)
// {
// return MoveTo (t, scale, Tweener.DefaultDuration);
// }
//
// public static Tweener ScaleTo (this Transform t, Vector3 scale, float duration)
// {
// return MoveTo (t, scale, duration, Tweener.DefaultEquation);
// }
//
// public static Tweener ScaleTo (this Transform t, Vector3 scale, float duration, Func<float, float, float, float> equation)
// {
// TransformScaleTweener tweener = t.gameObject.AddComponent<TransformScaleTweener> ();
// tweener.startValue = t.localScale;
// tweener.endValue = scale;
// tweener.easingControl.duration = duration;
// tweener.easingControl.equation = equation;
// tweener.easingControl.Play ();
// return tweener;
// }
}
6、EasingEquations.cs 动画曲线函数
using UnityEngine;
using System;
public static class EasingEquations
{
public static float Linear (float start, float end, float value)
{
return (end - start) * value + start;
}
public static float Spring (float start, float end, float value)
{
value = Mathf.Clamp01 (value);
value = (Mathf.Sin (value * Mathf.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow (1f - value, 2.2f) + value) * (1f + (1.2f * (1f - value)));
return start + (end - start) * value;
}
public static float EaseInQuad (float start, float end, float value)
{
end -= start;
return end * value * value + start;
}
public static float EaseOutQuad (float start, float end, float value)
{
end -= start;
return -end * value * (value - 2) + start;
}
public static float EaseInOutQuad (float start, float end, float value)
{
value /= .5f;
end -= start;
if (value < 1)
return end / 2 * value * value + start;
value--;
return -end / 2 * (value * (value - 2) - 1) + start;
}
public static float EaseInCubic (float start, float end, float value)
{
end -= start;
return end * value * value * value + start;
}
public static float EaseOutCubic (float start, float end, float value)
{
value--;
end -= start;
return end * (value * value * value + 1) + start;
}
public static float EaseInOutCubic (float start, float end, float value)
{
value /= .5f;
end -= start;
if (value < 1)
return end / 2 * value * value * value + start;
value -= 2;
return end / 2 * (value * value * value + 2) + start;
}
public static float EaseInQuart (float start, float end, float value)
{
end -= start;
return end * value * value * value * value + start;
}
public static float EaseOutQuart (float start, float end, float value)
{
value--;
end -= start;
return -end * (value * value * value * value - 1) + start;
}
public static float EaseInOutQuart (float start, float end, float value)
{
value /= .5f;
end -= start;
if (value < 1)
return end / 2 * value * value * value * value + start;
value -= 2;
return -end / 2 * (value * value * value * value - 2) + start;
}
public static float EaseInQuint (float start, float end, float value)
{
end -= start;
return end * value * value * value * value * value + start;
}
public static float EaseOutQuint (float start, float end, float value)
{
value--;
end -= start;
return end * (value * value * value * value * value + 1) + start;
}
public static float EaseInOutQuint (float start, float end, float value)
{
value /= .5f;
end -= start;
if (value < 1)
return end / 2 * value * value * value * value * value + start;
value -= 2;
return end / 2 * (value * value * value * value * value + 2) + start;
}
public static float EaseInSine (float start, float end, float value)
{
end -= start;
return -end * Mathf.Cos (value / 1 * (Mathf.PI / 2)) + end + start;
}
public static float EaseOutSine (float start, float end, float value)
{
end -= start;
return end * Mathf.Sin (value / 1 * (Mathf.PI / 2)) + start;
}
public static float EaseInOutSine (float start, float end, float value)
{
end -= start;
return -end / 2 * (Mathf.Cos (Mathf.PI * value / 1) - 1) + start;
}
public static float EaseInExpo (float start, float end, float value)
{
end -= start;
return end * Mathf.Pow (2, 10 * (value / 1 - 1)) + start;
}
public static float EaseOutExpo (float start, float end, float value)
{
end -= start;
return end * (-Mathf.Pow (2, -10 * value / 1) + 1) + start;
}
public static float EaseInOutExpo (float start, float end, float value)
{
value /= .5f;
end -= start;
if (value < 1)
return end / 2 * Mathf.Pow (2, 10 * (value - 1)) + start;
value--;
return end / 2 * (-Mathf.Pow (2, -10 * value) + 2) + start;
}
public static float EaseInCirc (float start, float end, float value)
{
end -= start;
return -end * (Mathf.Sqrt (1 - value * value) - 1) + start;
}
public static float EaseOutCirc (float start, float end, float value)
{
value--;
end -= start;
return end * Mathf.Sqrt (1 - value * value) + start;
}
public static float EaseInOutCirc (float start, float end, float value)
{
value /= .5f;
end -= start;
if (value < 1)
return -end / 2 * (Mathf.Sqrt (1 - value * value) - 1) + start;
value -= 2;
return end / 2 * (Mathf.Sqrt (1 - value * value) + 1) + start;
}
public static float EaseInBounce (float start, float end, float value)
{
end -= start;
float d = 1f;
return end - EaseOutBounce (0, end, d - value) + start;
}
public static float EaseOutBounce (float start, float end, float value)
{
value /= 1f;
end -= start;
if (value < (1 / 2.75f)) {
return end * (7.5625f * value * value) + start;
} else if (value < (2 / 2.75f)) {
value -= (1.5f / 2.75f);
return end * (7.5625f * (value) * value + .75f) + start;
} else if (value < (2.5 / 2.75)) {
value -= (2.25f / 2.75f);
return end * (7.5625f * (value) * value + .9375f) + start;
} else {
value -= (2.625f / 2.75f);
return end * (7.5625f * (value) * value + .984375f) + start;
}
}
public static float EaseInOutBounce (float start, float end, float value)
{
end -= start;
float d = 1f;
if (value < d / 2)
return EaseInBounce (0, end, value * 2) * 0.5f + start;
else
return EaseOutBounce (0, end, value * 2 - d) * 0.5f + end * 0.5f + start;
}
public static float EaseInBack (float start, float end, float value)
{
end -= start;
value /= 1;
float s = 1.70158f;
return end * (value) * value * ((s + 1) * value - s) + start;
}
public static float EaseOutBack (float start, float end, float value)
{
float s = 1.70158f;
end -= start;
value = (value / 1) - 1;
return end * ((value) * value * ((s + 1) * value + s) + 1) + start;
}
public static float EaseInOutBack (float start, float end, float value)
{
float s = 1.70158f;
end -= start;
value /= .5f;
if ((value) < 1) {
s *= (1.525f);
return end / 2 * (value * value * (((s) + 1) * value - s)) + start;
}
value -= 2;
s *= (1.525f);
return end / 2 * ((value) * value * (((s) + 1) * value + s) + 2) + start;
}
public static float Punch (float amplitude, float value)
{
float s = 9;
if (value == 0) {
return 0;
}
if (value == 1) {
return 0;
}
float period = 1 * 0.3f;
s = period / (2 * Mathf.PI) * Mathf.Asin (0);
return (amplitude * Mathf.Pow (2, -10 * value) * Mathf.Sin ((value * 1 - s) * (2 * Mathf.PI) / period));
}
public static float EaseInElastic (float start, float end, float value)
{
end -= start;
float d = 1f;
float p = d * .3f;
float s = 0;
float a = 0;
if (value == 0)
return start;
if ((value /= d) == 1)
return start + end;
if (a == 0f || a < Mathf.Abs (end)) {
a = end;
s = p / 4;
} else {
s = p / (2 * Mathf.PI) * Mathf.Asin (end / a);
}
return -(a * Mathf.Pow (2, 10 * (value -= 1)) * Mathf.Sin ((value * d - s) * (2 * Mathf.PI) / p)) + start;
}
public static float EaseOutElastic (float start, float end, float value)
{
end -= start;
float d = 1f;
float p = d * .3f;
float s = 0;
float a = 0;
if (value == 0)
return start;
if ((value /= d) == 1)
return start + end;
if (a == 0f || a < Mathf.Abs (end)) {
a = end;
s = p / 4;
} else {
s = p / (2 * Mathf.PI) * Mathf.Asin (end / a);
}
return (a * Mathf.Pow (2, -10 * value) * Mathf.Sin ((value * d - s) * (2 * Mathf.PI) / p) + end + start);
}
public static float EaseInOutElastic (float start, float end, float value)
{
end -= start;
float d = 1f;
float p = d * .3f;
float s = 0;
float a = 0;
if (value == 0)
return start;
if ((value /= d / 2) == 2)
return start + end;
if (a == 0f || a < Mathf.Abs (end)) {
a = end;
s = p / 4;
} else {
s = p / (2 * Mathf.PI) * Mathf.Asin (end / a);
}
if (value < 1)
return -0.5f * (a * Mathf.Pow (2, 10 * (value -= 1)) * Mathf.Sin ((value * d - s) * (2 * Mathf.PI) / p)) + start;
return a * Mathf.Pow (2, -10 * (value -= 1)) * Mathf.Sin ((value * d - s) * (2 * Mathf.PI) / p) * 0.5f + end + start;
}
}
7、TestTween.cs 客户端实现测试
using UnityEngine;
using System.Collections;
using System;
/// <summary>
/// 最原始的、最直接的、最不好扩展的实现动画方法
/// 【注意】实现动画时,使用协程来完成
/// </summary>
public class TestTween : MonoBehaviour {
// void Start () {
// StartCoroutine ("Tween");
// }
//
// IEnumerator Tween(){
// float start = -5;
// float end = 5;
// float duration = 3;
// float time = 0;
// while (time < duration) {
// yield return new WaitForEndOfFrame ();
// //Mathf.Clamp(value,min,max) 限制value在min和max之间
// //Mathf.Clamp01(value) 限制value在0和1之间
// time = Mathf.Clamp (time + Time.deltaTime,0,duration);
//// float value = (end - start) * (time / duration) + start;
// float value = EasingEquations.EaseInOutQuad(start, end, (time / duration));
// transform.localPosition = new Vector3 (value,0,0);
// }
// }
// EasingControl ec;
//
// void Start ()
// {
// ec = gameObject.AddComponent<EasingControl>();
// ec.startValue = -5;
// ec.endValue = 5;
// ec.duration = 3;
// ec.loopCount = -1; // inifinite looping
// ec.loopType = EasingControl.LoopType.PingPong;
// ec.equation = EasingEquations.EaseInOutQuad;
// ec.updateEvent += OnUpdateEvent;
// ec.Play();
// }
//
// void OnUpdateEvent (object sender, EventArgs e)
// {
// transform.localPosition = new Vector3( ec.currentValue, 0, 0 );
// }
void Start ()
{
transform.MoveTo( new Vector3(5, 0, 0), 3f, EasingEquations.EaseInOutQuad );
}
}