Unity动态动画

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 );
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值