Unity动画曲线AnimationCurve的学习

在开发游戏的过程中,unity中的粒子系统,文字,UI界面的显示功能及一些其他的动态效果都可以使用AnimationCurve做一些自定义的曲线实现一些想要的效果。

1、AnimationCurve的创建

先创建脚本,public一个AnimationCurve对象如下图:

unity 动画rig unity 动画曲线_Unity


就会在Unity的Inspector面板上显示动画曲线自定义面板,如下图:

unity 动画rig unity 动画曲线_关键帧_02


unity 动画rig unity 动画曲线_unity 动画rig_03


点击进去会发现一些自带的曲线函数,可以根据需求直接拿来用。也会发现上面的曲线所在的坐标系,就像我们数学学习的坐标系一样,每一个横坐标的值都会对应一个纵坐标的值(就像Dictionary的键值对),这里我们就能自己定义横坐标与纵坐标的含义来做一个动画。(例如横坐标当做时间,纵坐标当做轴值,当动画运行时这个轴值就会随着时间而增大,根据上图就是一个曲线增长,到达1秒时轴值也对应增长到1)

官方的AnimationCurve的API如下图

unity 动画rig unity 动画曲线_Unity_04

2、脚本中创建曲线

a)创建帧序列
Keyframe[] ks = new Keyframe[2];
b)曲线中加入帧序列
AnimationCurve Curve= new AnimationCurve(ks);

帧序列的相关设置
WrapMode.Loop是指整个循环左右循环。
WrapMode.Clamp指除了你设置的以外别的位置为直线。
WrapMode.PingPong指对称循环。
ks[index].inTangent是设置指入的切线的斜率,而ks[index].outTangent是设置出的切线斜率。

下面举一个别人写类似掉血飘字的实例

using UnityEngine;
using System.Collections;

public class BloodAnimation : MonoBehaviour {

    private RectTransform rectTransform;

    [SerializeField]
    public AnimationCurve animationCurve;  // 动画曲线
    private int length;                    // 动画曲线关键帧个数
    private Keyframe[] keyframs;           // 动画曲线关键帧

    // 文字初始坐标
    private Vector3 bloodTextPos = Vector3.zero;

    // Use this for initialization
    void Start()
    {
        rectTransform = GetComponent<RectTransform>();
        bloodTextPos = rectTransform.localPosition;

        keyframs = animationCurve.keys;    // 获取动画曲线关键帧

        length = animationCurve.length;    // 获取动画曲线关键帧个数

        Debug.Log(length + "       " + keyframs.Length);

        // 遍历关键帧数组,打印每个关键帧的 time 和 value
        for (int i = 0; i < keyframs.Length; i++)
        {
            Debug.Log(keyframs[i].time + "       " + keyframs[i].value);
        }
    }

    private float time = 0;
    // Update is called once per frame
    void Update()
    {

        if (Input.GetKeyDown(KeyCode.A))
        {
            animationCurve = CreateAnimationCurve();
        }

        GetAnimationCurveValue();
    }

    private void GetAnimationCurveValue()
    {
        if (keyframs.Length <= 0)
        {
            Debug.LogWarning("Keyframs Length is 0");
            return;
        }

        if (time < keyframs[length - 1].time)
        {
            time += Time.deltaTime;

            // 根据时间获取动画曲线相应点的 value 
            float value = animationCurve.Evaluate(time);
            Debug.Log("time  : " + time + "       value  : " + value);

            Vector3 pos = rectTransform.localPosition;
            pos.y = bloodTextPos.y + value;
            // 设置文字坐标的 Y 值
            rectTransform.localPosition = pos;
        }
        else
        {
            time = 0;
        }
    }

    // 代码创建动画曲线
    private AnimationCurve CreateAnimationCurve()
    {
        // 定义关键帧数组
        Keyframe[] ks = new Keyframe[30];

        int i = 0;
        while (i < ks.Length)
        {
            // 给每个关键帧赋值  time, value
            ks[i] = new Keyframe(i, Mathf.Sin(i));
            i++;
        }

        // 设置前一个点进入该关键帧的切线(也就是设置斜率)
        ks[1].inTangent = 45;

        // 设置从 10 关键帧出去时的切线 (也是设置斜率)
        ks[10].outTangent = 90;

        // 通过关键帧数组实例化动画曲线
        AnimationCurve animaCur = new AnimationCurve(ks);

        //设置动画曲线最后一帧的 循环类型
        animaCur.postWrapMode = WrapMode.Loop;

        //设置动画曲线第一帧的 循环类型
        animaCur.preWrapMode = WrapMode.Once;

        Keyframe k = new Keyframe(31, 2);
        // 添加一个动画帧
        animaCur.AddKey(k);

        // 移除第 10 个关键帧
        animaCur.RemoveKey(10);

        // 设置第 20 个关键帧 的平滑度
        animaCur.SmoothTangents(20, 3);

        // 根据时间获取动画曲线 time 时间点的 value
        float time = 15.5f;
        animaCur.Evaluate(time);

        return animaCur;
    }
}

在Unity场景中添加Canvas并创建一个文本框Text,并把上面脚本添加到该文本对象上,并选择或者创建一个曲线,如下:

unity 动画rig unity 动画曲线_AnimationCurve_05


然后点击运行,你会发现文本对象会按照曲线坐标发生循环移动。当你按下A键时,会调用脚本中的CreateAnimationCurve()函数赋给现在曲线对象,你会发现文本运动发生改变,曲线也会变成脚本中自定义的曲线,如下图:

unity 动画rig unity 动画曲线_关键帧_06


AnimationCurve在游戏开发中应用很广,在做一些动态效果时也非常方便,上面只是一些基础案例,大家可以了解一下计算机图形学中的一些经典曲线,通过AnimationCurve创建出来应用在自己的案例里来做一些特殊的动态效果,或者增加更好的用户体验。