0

我正在尝试移植和实现我发现的缓动功能

编辑

: 我贴错了缓动函数,对不起!这是正确的:

Math.easeOutQuart = function (t, b, c, d) {
    t /= d;
    t--;
    return -c * (t*t*t*t - 1) + b;
};

我使用的语言不是 Flash 或 Actionscript。这是我的代码:

ease:{outquart:{function(t as float,b as float,c as float,d as float) as float
        t=t/d
        t=t-1
        return -c * (t*t*t*t - 1) + b
    end function}}

我在循环中调用该函数:

EDIT2 - 调用函数。

m.move 设置为 1 或 -1 表示移动方向,或 -5 +5 表示移动 5 个长度。尽可能频繁地调用 setspritemoves,目前它与系统调用的速度一样快,但我可以在毫秒计时器上触发调用。

setspritemoves:function()
                if m.move=1 then
                m.duration=1
                    if m.ishd then
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]+m.move*324
                        next i
                    else
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]+m.move*224
                        next i
                    end if                          
                else if m.move=5 then
                    m.duration=5
                    if m.ishd then
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]+m.move*324
                        next i
                    else
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]+m.move*224
                        next i
                    end if      
                else if m.move=-1 then
                m.duration=1
                    if m.ishd then
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]-m.move*324
                        next i
                    else
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]-m.move*224
                        next i
                    end if      
                else if m.move=-5 then
                    m.duration=5
                    if m.ishd then
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]-m.move*324
                        next i
                    else
                        for i=0 to m.spriteposx.count()-1
                            m.moveto[i]=m.spriteposx[i]-m.move*224
                        next i
                    end if
                end if
                end function

m.moveto[i] 是目标 x 坐标,m.time 是我递增的整数,m.duration 是我假设我希望完成更改所需的时间量,m.spriteposx 是当前位置我正在移动的对象。[i] 是当前的精灵。

如果我想在 1/2 秒内移动 345 个像素,时间的增量值应该是多少?

在我所有的实验中,我要么超调了一个很大的因素,要么只移动了几个像素。

目前 m.time 每次迭代都会增加 1,而 m.duration 是 100。我尝试了各种值,但似乎没有一个能始终如一地工作。

4

3 回答 3

2

你为什么不复制1-1的逻辑?补间是一种简单的算法,它只是以四次方的方式将坐标从 映射bb+c,即b + c*t^4wheret获取区间中的值[0,1]。您可以通过替换看到,当t=0值是初始值时,b,并且t->1位置是必需的b+c

这就是 line 的原因,任意的持续时间也是t \= d如此,并且自动画开始以来经过的时间得到上述范围内的值。但是您已经完成并拍摄了底片等。为什么?dtt=t-1

例如,在 0.5 秒内移动 345px,您将有一个初始位置,bc=345假设 px 是度量单位。d=0.5并且您将动画分成您选择的长度的间隔(取决于将运行动画的机器的功率。移动设备不如台式机强大,因此您在这种情况下选择合理的帧速率)。假设我们选择 24 fps,所以我们将间隔分成0.5*24 = 12帧,并每隔 1/24秒调用一次函数,每次取值 1/24、2/24 等。如果更舒服t工作不是几秒钟,而是几帧,然后d=12取值t1,2,...,12。无论哪种方式,计算都是相同的。

这是一个很好的例子(单击框运行演示),随意摆弄这些值:

http://jsfiddle.net/nKhxw/

于 2011-10-11T12:45:40.370 回答
0

贝塞尔函数

借自http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/

/**
* KeySpline - use bezier curve for transition easing function
* is inspired from Firefox's nsSMILKeySpline.cpp
* Usage:
* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
* spline.get(x) => returns the easing value | x must be in [0, 1] range
*/
function KeySpline (mX1, mY1, mX2, mY2) {

  this.get = function(aX) {
    if (mX1 == mY1 && mX2 == mY2) return aX; // linear
    return CalcBezier(GetTForX(aX), mY1, mY2);
  }

  function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
  function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
  function C(aA1)      { return 3.0 * aA1; }

  // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
  function CalcBezier(aT, aA1, aA2) {
    return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
  }

  // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
  function GetSlope(aT, aA1, aA2) {
    return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
  }

  function GetTForX(aX) {
    // Newton raphson iteration
    var aGuessT = aX;
    for (var i = 0; i < 4; ++i) {
      var currentSlope = GetSlope(aGuessT, mX1, mX2);
      if (currentSlope == 0.0) return aGuessT;
      var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
      aGuessT -= currentX / currentSlope;
    }
    return aGuessT;
  }
}

常用曲线的别名:

{
    "ease":        [0.25, 0.1, 0.25, 1.0], 
    "linear":      [0.00, 0.0, 1.00, 1.0],
    "ease-in":     [0.42, 0.0, 1.00, 1.0],
    "ease-out":    [0.00, 0.0, 0.58, 1.0],
    "ease-in-out": [0.42, 0.0, 0.58, 1.0]
}

应该很容易制作自己的曲线...

于 2012-07-12T10:43:12.117 回答
0

谢谢你,乔尼!

下面是如何实现 Bezier 缓动函数:C or Objective-C for iOS

// APPLE ORIGINAL TIMINGS:
//    linear        (0.00, 0.00), (0.00, 0.00), (1.00, 1.00), (1.00, 1.00)
//    easeIn        (0.00, 0.00), (0.42, 0.00), (1.00, 1.00), (1.00, 1.00)
//    easeOut       (0.00, 0.00), (0.00, 0.00), (0.58, 1.00), (1.00, 1.00)
//    easeInEaseOut (0.00, 0.00), (0.42, 0.00), (0.58, 1.00), (1.00, 1.00)
//    default       (0.00, 0.00), (0.25, 0.10), (0.25, 1.00), (1.00, 1.00)

+(double)defaultEase_Linear:(double)t
{
    return t;
}

// Замедление в начале
+(double)defaultEase_In:(double)t
{
    return [AnimationMath easeBezier_t:t

                              point0_x:0
                              point0_y:0

                              point1_x:0.42
                              point1_y:0

                              point2_x:1
                              point2_y:1

                              point3_x:1
                              point3_y:1];
}

// Замедление в конце
+(double)defaultEase_Out:(double)t
{
    return [AnimationMath easeBezier_t:t

                              point0_x:0
                              point0_y:0

                              point1_x:0
                              point1_y:0

                              point2_x:0.58
                              point2_y:1

                              point3_x:1
                              point3_y:1];
}

+(double)defaultEase_InOut:(double)t
{
    return [AnimationMath easeBezier_t:t

                              point0_x:0
                              point0_y:0

                              point1_x:0.42
                              point1_y:0

                              point2_x:0.58
                              point2_y:1

                              point3_x:1
                              point3_y:1];
}

+(double)defaultEase_default:(double)t
{
    return [AnimationMath easeBezier_t:t

                              point0_x:0
                              point0_y:0

                              point1_x:0.25
                              point1_y:0.1

                              point2_x:0.25
                              point2_y:1.0

                              point3_x:1
                              point3_y:1];
}


// For *better understanding* there is p1 and p2, because it is a Bezier curve from 0,0 to 1,0. So, you can remove p1 and p2 from this method, it is just for better understanding what's going on here

double ease_bezier_A(double aA1, double aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
double ease_bezier_B(double aA1, double aA2) { return 3.0 * aA2 - 6.0 * aA1; }
double ease_bezier_C(double aA1)      { return 3.0 * aA1; }

// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
double ease_bezier_calc(double aT, double aA1, double aA2) {
    return ((ease_bezier_A(aA1, aA2)*aT + ease_bezier_B(aA1, aA2))*aT + ease_bezier_C(aA1))*aT;
}

// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
double ease_bezier_get_slope(double aT, double aA1, double aA2) {
    return 3.0 * ease_bezier_A(aA1, aA2)*aT*aT + 2.0 * ease_bezier_B(aA1, aA2) * aT + ease_bezier_C(aA1);
}

double ease_bezier_get_t_for_x(double aX, double mX1, double mX2) {
    // Newton raphson iteration
    double aGuessT = aX;
    for (int i = 0; i < 4; ++i) {
        double currentSlope = ease_bezier_get_slope(aGuessT, mX1, mX2);
        if (currentSlope == 0.0) return aGuessT;
        double currentX = ease_bezier_calc(aGuessT, mX1, mX2) - aX;
        aGuessT -= currentX / currentSlope;
    }
    return aGuessT;
}



// Objective-C
// For ***better understanding*** there is p1 and p2, because it is a Bezier curve from 0,0 to 1,0. So, you can remove p1 and p2 from this method, it is just for better understanding what's going on here
// p1_x always = 0
// p1_y always = 0
// p2_x always = 1.0
// p2_y always = 1.0
+(double)easeBezier_t:(double)t
             point0_x:(double)point0_x point0_y:(double)point0_y
             point1_x:(double)point1_x point1_y:(double)point1_y
             point2_x:(double)point2_x point2_y:(double)point2_y
             point3_x:(double)point3_x point3_y:(double)point3_y
{
    if (point0_x != 0 || point0_y != 0 || point3_x != 1 || point3_y != 1) {
        [NSException raise:@"Error! Your bezier is wrong!!!" format:@""];
    }

    double v = ease_bezier_calc(ease_bezier_get_t_for_x(t, point1_x, point2_x), point1_y, point2_y);

    return v;
}
于 2016-12-14T13:09:42.437 回答