美文网首页unity
[Unity 3d] 如何在自己写的动效中加入Ease

[Unity 3d] 如何在自己写的动效中加入Ease

作者: 雨落随风 | 来源:发表于2019-05-10 03:49 被阅读5次

    笔者觉得一个好缓动效果的使用,往往会让人觉得这个游戏对象瞬间活泼起来就像有了生命一般,Easing 就是这般神奇。在本文,笔者带大家写一个具有缓动效果的 PingPong 动效。

    EasingCore

    巧妇难为无米之炊,我们要先整理一些 Ease 算法先,没想人家早早的就整理了一份放到 GitHub 上咯~(其实 Itween里面也有一套 Ease 算法哈)
    EasingCore-GitHub

    怎么用 EasingCore:

    怎么用EasingCore,超简单:

    float value = EasingFunction.Get(easetype).Invoke(progress);
    

    这样获得的值就是被算法修正的值啦。

    PingPong

    用上了这个EasingCore 的 PingPong动效模块,:

    using EasingCore;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using zFrame.Extend;
    using Ease = EasingCore.Ease;
    
    public class PingPong : MonoBehaviour
    {
        #region SelfField
        float progress = 0;
        bool addition = true;
        private CoroutineHandler coroutine;
        #endregion
        #region Configration Parameter
        private event Action<float> action;
        private Ease ease = Ease.Linear;
        private float delay = 0;
        #endregion
        #region 单例
        static PingPong driver;
        static PingPong Driver
        {
            get
            {
                if (null == driver)
                {
                    GameObject go = new GameObject("[PingPongDriver]");
                    driver = go.AddComponent<PingPong>();
                    GameObject.DontDestroyOnLoad(go);
                    go.hideFlags = HideFlags.HideAndDontSave;
                }
                return driver;
            }
        }
        private void Awake()
        {
            driver = this;
        }
        #endregion
        #region PingPongBehaviours
        public static PingPong OnUpdate(Action<float> action)
        {
            if (null == Driver.action) 
            {
                Driver.action = action; 
            }
            else
            {
                List<Delegate> list = new List<Delegate>(Driver.action.GetInvocationList());
                if (!list.Contains(action))
                {
                    Driver.action += action;
                }
            }
            return Driver;
        }
        public PingPong SetEase(Ease ease)
        {
            this.ease = ease;
            return Driver;
        }
        public PingPong SetDelay(float delay)
        {
            this.delay = delay;
            return Driver;
        }
        public void Play()
        {
            if (null == coroutine)
            {
                coroutine = Handler().Start();
            }
        }
        private void Finish()
        {
            coroutine.Stop();
            coroutine = null;
            action = null;
        }
        public static void Stop()
        {
            Driver.Finish();
        }
        #endregion
        IEnumerator Handler()
        {
            yield return new WaitForSeconds(delay);
            while (true)
            {
                progress += (addition ? 1 : -1) * Time.deltaTime ;
                progress = Mathf.Clamp01(progress);
                addition = progress == 1 ? false : progress == 0 ? true : addition;
                float value = EasingFunction.Get(ease).Invoke(progress);
                action?.Invoke(value);
                yield return 0;
            }
        }
    }
    

    这个实现比较无聊,仅仅是做的好玩,所以居然使用了单例,哈哈。
    然后,使用了链式编程风格以配置参数:

    怎么使用:

    演示代码,应该没有什么复杂需要特别注解的地方了

    using UnityEngine;
    
    public class TestBreath : MonoBehaviour
    {
        public EasingCore.Ease ease = EasingCore.Ease.InExpo;
        public Transform endPoint;
        public float delay = 2;
        public float factor = 0.5f;
        Vector3 v3; //缓存起点
        Vector3 ve; //终点
    
        void Start()
        {
            v3 = transform.position;
            Play();
        }
        [EditorButton]
        public void Restart()
        {
            PingPong.Stop();
            transform.position = v3;
            Play();
        }
        private void Play()
        {
            ve = endPoint.position;
            Vector3 dr = ve - v3; //获得起点指向终点的向量
            float dis = Vector3.Distance(v3, ve); //获得向量距离,
    
            PingPong.OnUpdate(v =>
            {
                Vector3? pos = v3 + dr.normalized * dis * v; // 使用可空值接这个数据
                transform.position = pos.HasValue ? pos.Value : transform.position;
            }).SetEase(ease) //设置 Ease 模式
              .SetDelay(delay) //设置延时多久后播放动画
              .SetFactor(factor) //等效于设置动画时长
              .Play();
        }
    }
    
    

    动画演示:

    Pingpong + EasingCore

    总共有30个缓动,动画中几个动效为随机测试。

    扩展阅读:

    Unity EditorButton - GitHub
    [Unity3D] 协程管理CoroutineManager - 简书
    [Unity 3d] 如何优雅的写一个PingPong效果 - 简书

    相关文章

      网友评论

        本文标题:[Unity 3d] 如何在自己写的动效中加入Ease

        本文链接:https://www.haomeiwen.com/subject/pmgnoqtx.html