关于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 else
11 {
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 } else
12 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 else
10 {
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来创建动作队列。
关于Cococs中的CCActionEase(下)的更多相关文章
- 关于Cococs中的CCActionEase(中)
相比之前的速度正弦变化动作(这个东西叫什么更好一些?渐变动画?)与速度指数级变化动作,CCEaseIn/CCEaseOut/CCEaseInOut更具灵活性.你可以设置运动的速率,甚至是在运动的过程中 ...
- 关于Cococs中的CCActionEase
尊重作者劳动,转载时请标明文章出处.作者:Bugs Bunny地址:http://www.cnblogs.com/cocos2d-x/archive/2012/03/13/2393898.html 本 ...
- Linux中/proc目录下文件详解
转载于:http://blog.chinaunix.net/uid-10449864-id-2956854.html Linux中/proc目录下文件详解(一)/proc文件系统下的多种文件提供的系统 ...
- SQL搜索下划线,like中不能匹配下划线的问题
最近在检测天气预报15天查询网 站(http://tqybw.net)时的URL时,发现页面中有很些404页,分析发现,是请求地址的能参数中多了下划线“_”,而rewrite规 则中并没有配这样的规则 ...
- python中那些双下划线开头得函数和变量--转载
Python中下划线---完全解读 Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用'from module import *'导入 __xxx__ 系统定义名字 __x ...
- struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input
原文地址:struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input jsp页面 1 function dosearch() {2 if ($(&q ...
- Cocos开发中Visual Studio下HttpClient开发环境设置
Cocos2d-x 3.x将与网络通信相关的类集成到libNetwork类库工程中,这其中包括了HttpClient类.我们需要在Visual Studio解决方案中添加libNetwork类库工程. ...
- Cocos开发中Visual Studio下libcurl库开发环境设置
我们介绍一下win32中Visual Studio下libcurl库开发环境设置.Cocos2d-x引擎其实已经带有为Win32下访问libcurl库,Cocos2d-x 3.x中libcurl库文件 ...
- Android 获取SDCard中某个目录下图片
本文介绍Android开发中如何获取SDCard中某目录下的所有图片并显示出来,下面的我们提供的这个函数是通用的,只要提供路径就可以查询出该目录下所有图片的路径信息,并保存到一个List<Str ...
随机推荐
- COJ 1003 WZJ的数据结构(三)ST表
WZJ的数据结构(三) 难度级别:B: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的 ...
- POJ 1502 MPI Maelstrom( Spfa, Floyd, Dijkstra)
题目大意: 给你 1到n , n个计算机进行数据传输, 问从1为起点传输到所有点的最短时间是多少, 其实就是算 1 到所有点的时间中最长的那个点. 然后是数据 给你一个n 代表有n个点, 然后给你一 ...
- struts2校验器规范错误解决
今天struts2的校验器的配置文件文件头出现了错误,配置如下: <!DOCTYPE validators PUBLIC "-//OpenSymphony Group// ...
- Oracle V$SESSION
SADDR session address SID session identifier 常用于链接其他列 SERIAL# SID有可能会重复,当两个session的SID重复时,SERIAL#用来区 ...
- Android BaseAdapter ListView (明星简介列表)
1.搭建布局 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" andro ...
- 【解决】hive动态添加partitions不能超过100的问题
Author: kwu [解决]hive动态添加partitions不能超过100的问题,全量动态生成partitions超过100会出现例如以下异常: The maximum number of d ...
- WIN32读写INI文件方法
在程序中经常要用到设置或者其他少量数据的存盘,以便程序在下一次执行的时候可以使用,比如说保存本次程序执行时窗口的位置.大小.一些用户设置的 数据等等,在 Dos 下编程的时候,我们一般自己产生一个 ...
- 【转】关于Ubuntu的sources.list 的总结
一.作用 文件/etc/apt/sources.list是一个普通可编辑的文本文件,保存了ubuntu软件更新的源服务器的地址.和sources.list功能一样的是/etc/apt/sources. ...
- nginx 1.安装
nginx 1.安装 nginx的众多优点这里就不多说了,直接开始吧. 基本依赖 yum install -y gcc gcc-c++ pcre pcre-devel zlib zlib-devel ...
- SQL Server 数据库邮件 配置
在 Sqlserver 上尝试配置 数据库邮件,用 smtp.qq.com 来发送邮件 如下配置后,发送测试邮件遇到错误 “由于邮件服务器故障,无法将邮件发送给收件人. (使用帐户 1 (2015-1 ...