如何在循环中的两个值X,Y之间来回跳转?

时间:2015-11-25 12:10:56

标签: javascript lerp

使用setInterval或RequestAnimationFrame,我想从X和Y之间获取进展值。 假设X为0且Y为1,我希望在启动时为0,在一半中为0.5,在完成时为1。 我希望在给定的时间范围内发生这种情况,让我们说5秒钟。意味着半值0.5会发生 setInterval / RequestAnimationFrame达到2.5秒。 最后,我喜欢pingPong,所以当它达到5秒时,值正在减少而不是增加,例如 如0.9,0.8,0.7等,然后从0,0.1,0.2 ......再次开始

任何提示或建议?

谢谢!

2 个答案:

答案 0 :(得分:5)

线性插值的基本公式类似于

InterpolatedValue = X*t + Y*(1-t)

其中XY是要插入的值,t是确定插值程度的01之间的参数; 0产生X1产生Y。此外,您希望进行一些周期长度为5的周期性移动,交替插值方向;这可以通过以下方式实现。如果t是一个随时间增长的非负数,请计算

t' = t - t / 10

删除之前发生的所有期间

t'' = t'     : t' in [0,5)
      5 - t' : t' in [5,10)

然后设置

t''' = t' / 5

将参数标准化为[0,1]并从头开始使用基本插值公式。

请注意,收集线性插值和各种其他方法here

答案 1 :(得分:1)

根据您的描述,在任何给定的框架中有6个状态:

  1. 当前lerp的开始时间
  2. Lerp timespan
  3. 当前方向
  4. 当前时间
  5. 起始值
  6. 结束价值
  7. 通过这些,您可以计算所需的进度值,例如:

    function progressValue(startTime, lerpSpanSeconds, dir, 
                           currentTime X, Y, dir, currentTime) {
        // lerp
        return 0.42;
    }
    

    对于requestAnimationFrame,you need a simple callback to pass in。也就是说,该函数必须知道它需要的一切,除了它运行时可以获得的东西。在这里,当它运行时,它只需要获取当前时间并从那里完成剩下的工作。

    function animableThing() {
        var startTime = 7;
        var lerpSpanSeconds = 3;
        var dir = +1;
        var X = 0;
        var Y = 1;
        var currentTime = GetCurrentUnicornTime();
        var thingToAnimate = document.getElementById('myAnimableElement');
    
        var progress = progressValue(startTime, lerpSpanSeconds, dir, 
              currentTime, X, Y, dir, currentTime);
        // reverse when we hit the end
        if(progress > Y) {
            dir *= -1;
            startTime = currentTime;
            progress = Y;
        }
    
        DrawAnimationThing(thingToAnimate, progress);
    
        // continue the animation
        window.requestAnimationFrame(animableThing);
    }
    

    但是有一个问题;如果您希望能够使用脚本中的值或屏幕输入设置动画,或者有关屏幕上元素的最新信息,那么您需要能够创建animableThing当您有新值时,回调新鲜。看哪,母亲:

    function MotherOfAnimableThings(startTime, lerpSpanSeconds, dir, X, Y, 
       thingToAnimate)
    {
        // Passed in variables have scope outside the animableThing, these
        // will be private to the animableThing function.
        // Consider defaulting or validation here
    
        // Construct a new function freshly each time the Mother is called,
        // and return it to the caller. Note that we assign a variable here
        // so that we can re-call RequestAnimationFrame to continue the loop
        var callback = (function() {
            var currentTime = GetCurrentUnicornTime();
            var progress = progressValue(startTime, lerpSpanSeconds, dir, 
                  currentTime, X, Y, dir, currentTime);
            // reverse when we hit the end
            if(progress > Y) {
                dir *= -1;
                startTime = currentTime;
                progress = Y;
            }
    
            DrawAnimationThing(thingToAnimate, progress);
    
            window.requestAnimationFrame(callback);
        });
        return callback;
    }
    

    我们可以更进一步,通过让调用者传入progressValue函数来调用,或者实际上是一个回调函数,使其适用于其他类型的东西,这样你就可以使用任何元素,绘制函数和设置函数并使一个动画的东西,但这是一个合理的起点。

    通过上述内容,我们只需要调用Mother来创建animableThing函数并使用它调用RequestAnimationFrame。从那时起,它在内部调用RequestAnimationFrame来继续循环。

    现在,完成后,你会想让它停止,所以在它可以检查的回调中添加一个变量,这样就可以了

    var animableThing = MotherOfAnimableThings(...);
    window.requestAnimationFrame(animableThing);
    // ... later
    animableThing.stop = true; // it should stop on the next frame