实现缓动功能



我正在尝试移植和实现一个舒缓功能,我发现

编辑

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

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是一个整数i增量,m.duration是我假设的完成更改所需的时间,m.spriteposx是我正在移动的对象的当前位置。[i]是当前精灵。

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

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

当前m.time每次迭代递增1,m.duration为100。我试过各种各样的值,但似乎没有一个能始终如一地工作。

你为什么不复制1-1的逻辑?渐变是一个简单的算法,它简单地以四分之一的方式将坐标从b映射到b+c,即b + c*t^4,其中t在区间[0,1]中获得值。您可以通过替换看到,当t=0时,该值为初始值,b, t->1时,该位置为所需的b+c

这就是t = d行的原因,所以d是一个任意的持续时间,而t,从动画开始以来经过的时间,得到了上述范围内的值。但你做过t=t-1和底片,等等。为什么?

例如,在0.5s内移动345px,您将有一个初始位置,bc=345,假设px是度量单位。d=0.5,然后将动画分割为您选择的长度间隔(取决于将运行动画的机器的功率)。移动设备不像桌面设备那么强大,所以你要在这种情况下选择一个合理的帧率)。假设我们选择24帧/秒,那么我们将间隔分割为0.5*24 = 12帧,并每1/24秒调用该函数一次,每次t取1/24、2/24等值。如果不以秒为单位而是以帧为单位工作更舒服,那么d=12t的值为1,2,…,12。两种方法的计算都是一样的。

下面是一个很好的例子(点击方框运行演示),可以随意修改值:

http://jsfiddle.net/nKhxw/

贝塞尔函数

借用自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]
}

谢谢你,强尼!

下面是如何实现Bezier easing函数:C或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;
}

最新更新