实现缓动函数

发布于 2024-12-08 23:42:31 字数 2885 浏览 8 评论 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 是整数 I 增量,m.duration 是我假设的完成更改所需的时间,m.spriteposx 是当前位置我正在移动的物体。 [i] 是当前精灵。

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

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

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

I'm trying to port and implement an easing function I found

EDIT

: I pasted in the wrong easing function, Sorry! Here is the correct one:

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

The language i'm using is not Flash or Actionscript. Here is my code:

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}}

I'm calling the function in a loop with:

EDIT2 - the calling function.

m.move is set to 1 or -1 for direction to move, or -5 +5 to move by 5 lengths.
setspritemoves is called as often as possible, currently it is as fast as the system can call, but I could trigger the call on a millisecond timer.

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] is the destination x coordinate, m.time is an integer I increment, m.duration is what I assume to be the amount of time I want the change to take to complete, m.spriteposx is the current position of the object I'm moving. [i] is the current sprite.

What should the increment value be for time what should the duration be, if I want to move 345 pixels in 1/2 second?

In all my experiments, I either overshoot by a huge factor, or only move a few pixels.

currently m.time is incremented by 1 every iteration, and m.duration is 100. I"ve tried all kinds of values and none seems to work consistently.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雪花飘飘的天空 2024-12-15 23:42:31

为什么你没有复制 1-1 的逻辑?补间是一个简单的算法,它只是以四次方式将坐标从 b 映射到 b+c,即 b + c*t^4< /code> 其中 t 获取区间 [0,1] 中的值。通过替换可以看出,当 t=0 时,该值为初始值 b,当 t->1 时,位置为所需的b+c

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

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

这是一个很好的示例(单击该框来运行演示),请随意修改这些值:

http://jsfiddle。净/nKhxw/

Why haven't you copied the logic across 1-1? The tween is a simple algorithm, it simply maps co-ordinates from b to b+c in a quartic fashion, i.e. b + c*t^4 where t gets values in the interval [0,1]. You can see by substitution that when t=0 the value is the initial value, b, and as t->1 the position is the required b+c.

That's the reason for the line t \= d, so d is an arbitrary duration and t, the time passed since the beginning of the animation gets a value in the aforementioned range. But you've done t=t-1 and taken negatives, etc. Why?

For example, moving 345px in 0.5s, you would have an initial position, b and c=345 assuming px is the units of measure. d=0.5 and you split the animation into intervals of a length of your choosing (depending on the power of the machine that will run the animation. Mobile devices aren't as powerful as desktops, so you choose a reasonable framerate under the circumstances). Let's say we choose 24 fps, so we split the interval into 0.5*24 = 12 frames, and call the function once every 1/24th of a second, each time with t taking values of 1/24, 2/24, etc. If it's more comfortable to work not in seconds but in frames, then d=12 and t takes values 1,2,...,12. The calculations are the same either way.

Here's a nice example (click the box to run the demo), feel free to fiddle with the values:

http://jsfiddle.net/nKhxw/

柠檬 2024-12-15 23:42:31

贝塞尔函数

借自 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 functions

Borrowed from 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;
  }
}

Aliases for common curves:

{
    "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]
}

Should be easy to make your own curves...

︶ ̄淡然 2024-12-15 23:42:31

谢谢你,乔尼!

以下是如何实现 Bezier 缓动函数: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;
}

Thank you, Jonny!

Here is how to implement Bezier easing functions: 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文