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: