AEJoy —— 表达式之弹性(韧性)模拟详解【JS】

320 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

效果图

弹性(elastic)

1101.gif

表达式代码与注释

var p = 0.6; ///< 弹性期限
var a = 140; ///< 弹性振幅

/// @note 弹性函数
function outElastic(t, b, c, d, a, p) {
    if (t == 0)
        return b;
    if ((t /= d) == 1)
        return b + c;
        
    if (!p)
        p = d * .3;

    if (!a || a < Math.abs(c)) {
        a = c;
        var s = p / 4;
    } else
        var s = p / (2 * Math.PI) * Math.asin(c / a);

    return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
}

/// @note 实际调用弹性函数的缓动函数
function easeAndWizz() {
    var n = 0;
    
    /// @note 确保关键帧帧数是大于 0 的
    if (numKeys > 0) {
        n = nearestKey(time).index; ///< 获取最近的关键帧索引
        if (key(n).time > time) { ///< 如果最近的关键帧所处时间在当前时间之后(即时间还没到)
            n--; ///< 则取前一个关键帧的索引
        }
    }

    try {
        /// @note 前后两个关键帧
        var key1 = key(n);
        var key2 = key(n + 1);
    } catch (e) {
        return null;
    }

    /// @note 确定关键帧需要的数据维度
    var dim = 1; ///< 该属性至少是一维的
    try {
        key(1)[1]; ///< 数据有第二维度
        dim = 2;
        key(1)[2]; ///< 数据有第三维度
        dim = 3;
    } catch (e) { }

    t = time - key1.time; ///< 当前时间和前一个关键帧的时间差
    d = key2.time - key1.time; ///< 前后俩关键帧的时间差

    /// @note 计算关键帧上的属性,用于后期的弹性计算
    /// 一维
    sX = key1[0];
    eX = key2[0] - key1[0];
    /// @note 二维
    if (dim >= 2) {
        sY = key1[1];
        eY = key2[1] - key1[1];
        /// @note 三维
        if (dim >= 3) {
            sZ = key1[2];
            eZ = key2[2] - key1[2];
        }
    }

    if ((time < key1.time) || (time > key2.time)) {
        return value;
    } else {
        /// @note 进行弹性计算
        val1 = outElastic(t, sX, eX, d, a, p);
        
        /// @note 同样分为三个维度进行计算
        switch (dim) {
            case 1:
                return val1;
                break;
            case 2:
                val2 = outElastic(t, sY, eY, d, a, p);
                return [val1, val2];
                break;
            case 3:
                val2 = outElastic(t, sY, eY, d, a, p);
                val3 = outElastic(t, sZ, eZ, d, a, p);
                return [val1, val2, val3];
                break;
            default:
                return null;
        }
    }
}

(easeAndWizz() || value);