unity

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

2019-05-10  本文已影响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效果 - 简书

上一篇下一篇

猜你喜欢

热点阅读