关于Cococs中的CCActionEase(下)

我们前面介绍的动作主要是用来改变内部动作的执行速度,接下来要介绍的这几个动作主要是用来增加表现效果的,可以看作是简单的特效。

10)CCEaseBackIn

1 void CCEaseBackIn::update(ccTime time)2 {3     ccTime overshoot = 1.70158f;4     m_pOther->update(time * time * ((overshoot + 1) * time - overshoot));5 }

前面我们已经做过很多次了,大家也一定都是轻车熟路,推导出一下公式:
s(t)=(overshoot+1)*t^3-overshoot*t^2 t∈[0,1]
v(t)=s‘(t)=3*(overshoot+1)*t^2-2*overshoot*t t∈[0,1]
a(t)=v‘(t)=6*(overshoot+1)*t-2*overshoot t∈[0,1]

在GeoGebra中绘制出函数图像:

请看图中的蓝色曲线。在动作开始执行后,精灵首先朝着y轴负方向运动,大约运动到y=-0.1的时候,开始按照正常的运动方向朝着点G(1,1)移动。

听起来有点儿复杂,那我给大家讲个故事。从前武状元考试,有个代号1.70158的人也来参加了,他把箭搭在弓上,然后用力向后拉,可惜力气太小了,只能把弓拉开10%,手一滑,箭就飞出去了,没想到正中靶心点G(1,1),阴差阳错的就当了武状元。

这故事讲完了,那您也一定听出来了,这CCEaseBackIn其实就是一个搭弓射箭的过程。

那这个代号1.70158的武状元是不是把弓拉开了10%呢?有兴趣的朋友可以跟着我一起算一算。

图中的红色曲线代表速度,只要它在x轴下方,那就说明这个武状元正在拉弓。如果红色曲线到了x轴上方,那就表示他把箭放出去了。所以红色曲线与x轴的交点B就是他松开手的那一刻。过点B做x轴的垂线,交蓝色曲线与C点,这个C点的纵坐标就是武状元拉弓的程度。

按照这个过程我们计算得出点B的横坐标为:
B.X=2*overshoot/(3*(overshoot+1))=0.419897
C.X=0.419897
将此值带入s(t)函数内,得出:
C.Y=s(C.X)=-0.1

因为这个动作的主要目的是实现特效,所以它的速度是多少就不是很重要了,有需要的朋友请自行计算红色曲线在[0,1]范围内的极值。

11)CCEaseBackOut

1 void CCEaseBackOut::update(ccTime time)2 {3     ccTime overshoot = 1.70158f;4     time = time - 1;5     m_pOther->update(time * time * ((overshoot + 1) * time + overshoot) + 1);6 }

将动作CCEaseBackIn倒着播放就是CCEaseBackOut了,请看图:

12)CCEaseBackInOut

Bug #961: fix mad behaviour in second stage of CCEaseBackInOut

cocos2d-1.0.1-x-0.12.0之前的版本中,CCEaseBackInOut动作的行为有点儿问题,如果你还在使用老的版本,先去升级一下吧。

 1 void CCEaseBackInOut::update(ccTime time) 2 { 3     ccTime overshoot = 1.70158f * 1.525f; 4  5     time = time * 2; 6     if (time < 1) 7     { 8         m_pOther->update((time * time * ((overshoot + 1) * time - overshoot)) / 2); 9     }10     else11     {12         time = time - 2;13         m_pOther->update((time * time * ((overshoot + 1) * time + overshoot)) / 2 + 1);14     }15 }

看到这段代码的你,可能会无比的迷惑。这迷惑不是莫名而来的,自打你见到overshoot第一眼的时候,这种子就已经种在你的心里了。

Why does 1.70158 equal a 10% "bounce"?
What does 1.70158 mean?
这里的1.525又是什么鬼东西?!

看来,如果我不把这些讲清楚,今天是收不了工了。

那我就简单地讲一讲。至于对与不对,各位您可擦亮了眼睛。

还记得上面我们计算C.Y的过程吗?如果我们不把overshoot的值代进去,再推导一次。

C.X=2*overshoot/(3*(overshoot+1))
C.Y=s(C.X)
C.Y=(2*overshoot/(3*(overshoot+1)))^2*((overshoot+1)*(2*overshoot/(3*(overshoot+1)))-overshoot)
C.Y=(2*overshoot/(3*(overshoot+1)))^2*(2*overshoot/3-overshoot)
C.Y=(2*overshoot/(3*(overshoot+1)))^2*(-overshoot/3)
C.Y=-(4*overshoot^3)/(27*(overshoot+1)^2)

因为我们要找出10%对应的overshoot是多少,并且C.Y是在x轴下方,所以我们令C.Y=-0.1。

C.Y=-0.1
-(4*overshoot^3)/(27*(overshoot+1)^2)=-1/10
40*overshoot^3=27*(overshoot+1)^2
40*overshoot^3-27*overshoot^2-54*overshoot-27=0

下面就是纯数学问题了,求解一元三次方程

经过一系列运算,得出这个一元三次方程有一个实根和两个共轭复根。这个实根就是我们想要的值——1.70154。对,你没看错,我算出来的就是1.70154。我也不知道为什么不是1.70158,难道是神奇的误差?

我们再来看看这个1.525是怎么来的。

而CCEaseBackInOut其实就是把CCEaseBackIn和CCEaseBackOut的图像缩小成一半,然后分别放入[0,0.5]和[0.5,1]区间内。因为是缩小一半,所以我们需要重新计算overshoot的值,要让原来弹出10%变成20%,这样缩小后才能保持弹出的幅度是一样的。

令C.Y=-0.2,得出一元三次方程:
20*overshoot^3-27*overshoot^2-54*overshoot-27=0

求解overshoot的值为2.59239,它正好是原来的1.70154的1.52355倍。

哎呀,糗大了,好不容易算出来两个数,跟代码里大家用的还不一样。

这到底是怎么回事?是误差的问题?还是我的算法不对?等待高人指点。

13)CCEaseBounceOut

这次我们要稍微调整一下顺序,先来介绍CCEaseBounceOut动作,因为CCEaseBounceIn是按照它的定义做的镜像,所以CCEaseBounceOut才是实现的本体。

1 void CCEaseBounceOut::update(ccTime time)2 {3     ccTime newT = bounceTime(time);4     m_pOther->update(newT);5 }

这次的变换函数独立出来了,我们跟进去看看。

 1 ccTime CCEaseBounce::bounceTime(ccTime time) 2 { 3     if (time < 1 / 2.75) 4     { 5         return 7.5625f * time * time; 6     } else  7     if (time < 2 / 2.75) 8     { 9         time -= 1.5f / 2.75f;10         return 7.5625f * time * time + 0.75f;11     } else12     if(time < 2.5 / 2.75)13     {14         time -= 2.25f / 2.75f;15         return 7.5625f * time * time + 0.9375f;16     }17 18     time -= 2.625f / 2.75f;19     return 7.5625f * time * time + 0.984375f;20 }

这回竟然换了4次计算公式,我们先把它画出来。

可能你还没有看出这是什么,为了让大家都能看明白,我们把它按照y=0.5做一次轴对称镜像。

现在都看出来了吗?

对了,CCEaseBounceOut动作就是模拟的小球掉落的弹跳运动。

这里小球一共弹起了3次。在第3次落地后,小球终于没有足够的力气再跳起来了。

14)CCEaseBounceIn

前面我们说过CCEaseBounceIn动作其实就是按照CCEaseBounceOut的定义镜像而来的。

1 void CCEaseBounceIn::update(ccTime time)2 {3     ccTime newT = 1 - bounceTime(1 - time);4     m_pOther->update(newT);5 }

镜像的方式是按照点(0.5,0.5)做的中心对称。

倒着播放小球掉落的画面是个什么样子?或者想象一下将静止在地面上的篮球拍打起来的过程。

15)CCEaseBounceInOut

 1 void CCEaseBounceInOut::update(ccTime time) 2 { 3     ccTime newT = 0; 4     if (time < 0.5f) 5     { 6         time = time * 2; 7         newT = (1 - bounceTime(1 - time)) * 0.5f; 8     } 9     else10     {11         newT = bounceTime(time * 2 - 1) * 0.5f + 0.5f;12     }13 14     m_pOther->update(newT);15 }

CCEaseXxxxInOut动作的实现永远都是最没意思的,无非就是把CCEaseXxxxIn和CCEaseXxxxOut缩小一半,然后再拼在一起。

小结

今天一共介绍了两类动作,第一类是在模拟弹射运动,第二类是在模拟小球掉落之类的弹跳运动。它们主要不是为了修改内部动作的速度,而是为其增加特殊的显示效果。

由于篇幅的限制,Ease Elastic类动作将放到下次介绍。

如果你去查看参考手册,在这三类动作的描述中,会看到这样的警告:

This action doesn‘t use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action.

所以不要把CCSequence之类的动作传递给它们作参数,但是你可以把它们传递给CCSequence来创建动作队列。

时间: 2024-11-09 06:26:09

关于Cococs中的CCActionEase(下)的相关文章

关于Cococs中的CCActionEase(中)

相比之前的速度正弦变化动作(这个东西叫什么更好一些?渐变动画?)与速度指数级变化动作,CCEaseIn/CCEaseOut/CCEaseInOut更具灵活性.你可以设置运动的速率,甚至是在运动的过程中改变速率.它们拥有共同的基类——CCEaseRateAction.不要直接使用CCEaseRateAction,因为它没有实现任何变化效果. 7)CCEaseIn 按照惯例贴出update函数的源代码,以免版本更新导致文不对题. 1 void CCEaseIn::update(ccTime time

关于Cococs中的CCActionEase

尊重作者劳动,转载时请标明文章出处.作者:Bugs Bunny地址:http://www.cnblogs.com/cocos2d-x/archive/2012/03/13/2393898.html 本文函数图像使用GeoGebra绘制,感谢它才华横溢的作者. 为了方便用户灵活地控制精灵运动,cocos2d-x提供了CCActionEase类系的动作.它们拥有相似的名字——CCEaseXxxxIn.CCEaseXxxxOut.CCEaseXxxxInOut,同时也拥有相似的行为——速度由慢至快.速

struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input

原文地址:struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input jsp页面 1     function dosearch() {2         if ($("#textValue").val() == "") {3                 $("#errortip").html("<font color='#FF0000'>请输入查询内容</font>")

Objective-C中,ARC下的 strong和weak指针原理解释

Objective-C中,ARC下的 strong和weak指针原理解释 提示:本文中所说的"实例变量"即是"成员变量","局部变量"即是"本地变量" 一.简介 ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain.release.autorelease语句.你不再需要担心内存管理,因为编译器为你处理了一切 注意:ARC 是编译器特性,而不是 iOS 运行时特性(除

删除沙盒中文件夹下所有文件

有时候需要在iOS系统里面,删除指定文件夹的内容,文件夹里面可能是文件,也可能包含有文件夹. 删除指定类型的文件.方法如下: NSString *extension = @"m4r"; NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,

vmware中NAT模式下,虚拟机与主机能ping通 为什么虚拟机不能上网

vmware中NAT模式下,虚拟机与主机能ping通 为什么虚拟机不能上网? 方案一: 1.把虚拟机的网络连接设置为桥接或NAT都可以的2.把虚拟机和主机设置为同一网段主机网络邻居属性3.双击打开本地连接,显示本地连接状态4.选择详细信息5.查看ip地址和掩码6.在本地连接状态中选择属性7.双击打开ip协议8.勾选使用下面的ip地址,输入刚才查看的ip地址和掩码,保险起见,默认网关一定要输入(本人实验过N次) 9.关闭虚拟机"防火墙" 方案二: 桥接方式都连不上网,那有两个可能.要么是

浅析WPF中MVVM模式下命令与委托的关系

??各位朋友大家好,我是Payne,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com.最近因为项目上的原因开始接触WPF,或许这样一个在现在来讲显得过时的东西,我猜大家不会有兴趣去了解,可是你不会明白对某些保守的项目来讲,安全性比先进性更为重要,所以当你发现银行这类机构还在使用各种"复古"的软件系统的时候,你应该相信这类东西的确有它们存在的意义.与此同时,你会更加深刻地明白一个道理:技术是否先进性和其流行程度本身并无直接联系.由此我们可以推论出:一项不流行

Cgroup和Namespace在测试中的使用(下)

Cgroup和Namespace在测试中的使用(下) Namespace介绍 使用Namespace又叫做命名空间,可以让每个进程组具有独立的PID.IPC和网络空间等,也就是说这些系统资源不再是全局性的,而是属于特定的Namespace,每个Namespace里面的资源对其他Namespace都是透明的,从而达到资源的隔离效果. 目前namespace的种类如下 分类 系统调用参数 Mount namespaces CLONE_NEWNS UTS namespaces CLONE_NEWUTS

Windows Phone获得IsolatedStorage中指定目录下的所有文件

在Windows Phone 中对隔离存储空间中的文件操作需要通过System.Io.IsolatedStorage下的类进行操作 获得指定文件夹下的所有文件: 参数:是指定文件夹的路径加上通配符,格式:\folder1\* List<string> GetFileNames(string _strFolder) { List<string> returnlst = new List<string>(); using (IsolatedStorageFile stora