Tween算法的深入分析

Tween算法:http://www.robertpenner.com/easing/ 这里有文档。

我们来深入解析下Tween算法公式吧,庖丁解牛

开始之前,必须了解下一些知识:

函数关于点或者直线对称方法

来自百度百科。

http://zhidao.baidu.com/question/114652008.html

http://zhidao.baidu.com/question/35072436.html

怎么求函数关于某个点对称后的函数?

例如f(x)=x+(1/x)关于点(2,1)对称的函数为g(x),那么g(x)怎么求?

解:一般的步骤是先设g(x)上的任一点为(x,y),

它关于点(2,1)对称的点的坐标为(x0,y0),

利用中点坐标公式求出它们的关系如下:

(x+x0)/2=2(y+y0)/2=1,

所以x0=4-x,y0=2-y,

因为(x0,y0)在原函数f(x)的图象上,所以满足函数关系式y0=x0+1/x0

即2-y=4-x+1/(4-x),所以y=x-2+1/(x-4)

 

已知函数的解析式,怎么求它关于某条直线对称的函数的解析式?

如:Y=X^2+X+1关于X=Y的对称函数的解析式怎么求?

设A(x,y)在函数Y=X^2+X+1上

则A关于y=x的对称点B(x',y')在函数Y=X^2+X+1上的对称函数上

AB的中点C在y=x上

C的坐标为[(x+x')/2,(y+y')/2],C在y=x上

(y+y')/2=(x+x')/2    (1)

直线AB的斜率垂直与y=x,即kAB*k=-1   kAB=-1

kAB=(y-y')/(x-x')    (2)

由(1)(2)可以解得:

x'=y

y'=x

设A(x,y)在函数Y=X^2+X+1上

x'=y

y'=x

代入方程Y=X^2+X+1

所以 x'=y'^2+y'+1

这就是所求的解析式

 

Linear比较简单,pass。

Quadratic Easing:

公式:p(t) = t^2

作者每次都归一化t,这样t是从 0-1,此时p(t)的结果也是0-1,那么这个结果就是缩放系数,看下源代码:

Math.easeInQuad= function (t, b, c, d) {

returnc*(t/=d)*t + b;

};

t = t/d, 然后取平方.可以理解为:c*(t/d)*(t/d) + b,作者那么写可以提速。(speeding up the process.)

看看Quadratic的easeOut函数吧:

Math.easeOutQuad= function (t, b, c, d) {

return-c * (t/=d)*(t-2) + b;

};

显然,easeIn函数和easeOut函数是关于某个点对称的,作者对t进行归一化,那么这个点就是(0.5, 0.5)

设 (x0,y0)在easeIn函数上, (x,y)在easeOut函数上,那么有

 (x0+x)/2=0.5, (y0+y)/2=0.5, 这样得出 x=1 - x0, y = 1 - y0 ;记下来,后面会用到。

对于函数Quadratic

代入y=x^2 或者是p(t)=t^2

得出:   y0=x0*(2-x0) 或者是 p(t0)=t0*(2-t0);

所以作者真正的写法应该是这样:

{

t = t / d ;

return c * t*(2-t) + b ;

}

合起来就是作者上面的公式。

接下来看看这个:easeIn和easeOut的结合

Math.easeInOutQuad = function (t, b, c, d) {

if ((t/=d/2) < 1) return c/2*t*t + b;

return -c/2 * ((--t)*(t-2) - 1) + b;

};

首先在d/2范围内对t归一化。

作者在0-d/2的地方调用easeIn,t~(0-1)

这个比较好理解,在d/2-d的地方调用easeOut,t~(0-2),但是只有t>1的部分才是我们想要的。

因此计算出的t=t-1,这样又使t归一化到了 (0-1)了,这样,就可以应用之前easeOut公式了。公式展开是这样的:

{

t = t / (d/2); // t ~(0-2)

if (t < 1) //easeIn

return c/2 * t *t + b;

else // easeOut

 {

t=t-1;//归一化到0-1之间

return  c/2 * t*(2-t) + c/2 + b ;  //  c/2 是偏移,比较好理解吧

 }

}

 

其余的也一样分析啦。接下来我只介绍easeOut以及easeInOut的easeOut部分。

CubicEasing

A cubicequation is based on the power of three.

p(t) = t^3

easeOut

y=1-(1-x0)^3

easeInOu: (后半部分)

y=1-(1-(x0-1))^3 简化为1-(2-x0)^3 ,继续化简 1+(x0-2)^3 ,这样之后

 return c/2 * (1+pow(x0-2,3)) + c/2 + b;化简就得到:

Math.easeInOutCubic = function (t, b, c, d) {

if ((t/=d/2) < 1)

return c/2 * Math.pow (t, 3) + b;

return c/2 * (Math.pow (t-2, 3) + 2) + b;

};

 

QuarticEasing

A quarticequation is based on the power of four:

p(t) = t4

easeOut

y=1-(1-x0)^4

easeInOu: (后半部分)

y=1-(1-(x0-1))^4化简为  1-(2-x0)^4

 

QuinticEasing

Quinticeasing continues the upward trend, raises time to the fifth power:

p(t) = t5

easeOut

y=1-(1-x0)^5

easeInOu: (后半部分)

y=1-(1-(x0-1))^5化简为  1-(2-x0)^5

 

Sinusoidal Easing

Asinusoidal equation is based on a sine or cosine function. Either one

producesa sine wave—a periodic oscillation of a specific shape.This is the

equationon which I based the easing curve:

p(t) = sin(t × p/2)

Math.easeInSine =function (t, b, c, d) {

return c * (1 -Math.cos(t/d * (Math.PI/2))) + b;

};

Math.easeOutSine =function (t, b, c, d) {

return c *Math.sin(t/d * (Math.PI/2)) + b;

};

Math.easeInOutSine =function (t, b, c, d) {

return c/2 * (1 -Math.cos(Math.PI*t/d)) + b;

};

easeOut的图像是:y=sin(x),easeIn是y=sin(x)关于点 (pi/4,0.5)对称的图像;

(x+x0)/2 = pi/4, (y+y0)/2=0.5, 得到 x0=pi/2 – x  , y0 = 1-y;

代入 y0=sin(x0) ,那么 1-y = sin(pi/2-x) = cos(x) ,得到 y = 1-cos(x)

其中x = t/d * pi/2;

easeInOut: 前半部分,当t=(t/(d/2)) < 1时,c/2 * (1- cos(t/d*pi/2)) + b;

后半部分:当t=(t/(d/2))>1时, c/2 *   sin((t/d-1)pi/2)  + c/2(偏移) + b;

化简得: c/2 *  sin(t/d*pi/2– pi/2)  + c/2 + b;

化简得: c/2 * (1 – cos(t/d*pi/2)) + b ;

//由公式:sin(x-pi/2)=-sin(pi/2-x)=-cos(x)

Exponential Easing

Ibased my exponential functions on the number 2 raised to a multiple of 10:

p(t) = 2^(10*(t-1))

当t=0时,p(t) 约为0.0009765625,接近于0,作者说这个函数是他找了很久才找到的。

当t=1时,pt(t)=1

Math.easeInExpo =function (t, b, c, d) {

return c *Math.pow(2, 10 * (t/d - 1)) + b;

};

Math.easeOutExpo =function (t, b, c, d) {

return c *(-Math.pow(2, -10 * t/d) + 1) + b;

};

Math.easeInOutExpo =function (t, b, c, d) {

if ((t/=d/2) < 1)

return c/2 *Math.pow(2, 10 * (t - 1)) + b;

return c/2 *(-Math.pow(2, -10 * --t) + 2) + b;

};

 

说一下EaseOut:

EaseOut和easeIn关于 (0.5,0.5)对称

于是:x0=1-x,y0=1-y

代入得 1-y = 2^(10*((1-x)-1)) = 2^(10*(-x)) = 2 ^ (-10*x)

于是 y= 1- 2^(-10*x),y就是比例系数

easeInOut就比较好理解了

 

Circular Easing

Circulareasing is based on the equation for half of a circle, which uses a

squareroot (shown next). X^2+(Y-1)^2=1  圆心 (0,1) ,半径1

p(t) = 1- sqrt(1-t^2)

根据这个公式不难得出:

Math.easeInCirc =function (t, b, c, d) {

return c * (1 -Math.sqrt(1 - (t/=d)*t)) + b;

};

Math.easeOutCirc =function (t, b, c, d) {

return c * Math.sqrt(1- (t=t/d-1)*t) + b;

};

Math.easeInOutCirc =function (t, b, c, d) {

if ((t/=d/2) < 1)

return c/2 * (1 -Math.sqrt(1 - t*t)) + b;

return c/2 *(Math.sqrt(1 - (t-=2)*t) + 1) + b;

};

说一下easeOut:

关于 (0.5,0.5)对称,那么有:x0 = 1 - x, y0 = 1 – y

代入公式得 1-y = 1- sqrt(1-(1-x)^2)

 化简得 y=sqrt(1-(1-x)^2),这就是比例系数

 或者  y=sqrt(1-(x-1)^2)

easeInOut的后半部分:

        c/2 *(sqrt(1-((t-1)-1)^2) + c/2 + b;

化简得: c/2 * (sqrt(1-(t-2)^2) + 1) + b;

 

很可惜,作者没有讲后面三个的函数的原型,不过无妨,我会后续补充的。

 

这两天碰到一个问题,我写了CCTween类,继承了CCObject,也想来个autorelease,结果可想而知,由于我使用CCTween类时并没有保留,所以过一段时间CCTween类对象被销毁,我在visit方法中访问CCTween类的对象,一直以为是多线程互斥访问的问题,后来才发现原来是CCTween类的对象没有保留,这说明autorelease完的对象不能随便用,要用的话,必须retain一下。所以索性不继承CCObject:

 

你可能感兴趣的:(多线程,c,算法,function,百度,文档)