[Cocos2d-x 相关教程来源于红孩儿的游戏编程之路 CSDN 博客地址: http://blog.csdn.net/honghaier ]
红孩儿Cocos2d-X学习园地QQ2群:44208467 加群写:Cocos2d-x
红孩儿Cocos2d-X学习园地QQ群:249941957 [暂满]加群写:Cocos2d-x
本章为我的Cocos2d-x教程一书初稿。望各位看官多提建议!
另:本章所用Cocos2d-x版本为:
cocos2d-2.0-x-2.0.2 @ Aug 30 2012
http://cn.cocos2d-x.org/download
在TestCpp工程里,ActionsTest演示了大量的动画,这些动画看起来非常酷。可是,它是怎么实现的呢?本节,咱们就谈谈这些动画的原理。
在上一节中,我们学习了基类CCAction,我们知道它有必须有一个“目标结点”。它是动画的使用者,即演示动画的精灵。我们让一个精灵调用runAction函数,则这个精灵就是使用者。它会被记录在动画的“目标结点”中。CCAction通过step函数来取得时间的流逝并计算动画进度。但在CCAction中,step函数是一个虚函数,它并没有在CCAction中进行相应功能的实现。而是由CCAction 派生到CCActionInterval这个类时才进行了相应功能的实现。可以说CCActinInterval这个类才真正的实现了时间流逝的动画计算功能。这是怎么回事呢?那现在就从CCActinInterval这个类开始我们的源码之旅吧!
打开CCActionInterval.h:
#ifndef __ACTION_CCINTERVAL_ACTION_H__ #define __ACTION_CCINTERVAL_ACTION_H__ //加入相关头文件 #include "base_nodes/CCNode.h" #include "CCAction.h" #include "CCProtocols.h" #include "sprite_nodes/CCSpriteFrame.h" #include "sprite_nodes/CCAnimation.h" #include <vector> //使用Cocos2d命名空间 NS_CC_BEGIN //可以看到,CCActionInterval是由时间动画基类CCFiniteTimeAction派生的,它有基础的时间长度属性接口。 class CC_DLL CCActionInterval : public CCFiniteTimeAction { public: //取得动画播放了多久。 inline float getElapsed(void) { return m_elapsed; } //初始化,设置一个固定时长的动画。 bool initWithDuration(float d); //动画是否播放结束。 virtual bool isDone(void); //产生一个当前动画实例的拷贝。 virtual CCObject* copyWithZone(CCZone* pZone); //上一节我们讲过,step是用来通过当前帧与上一帧的时间流逝值来计算动画播放进度的。 virtual void step(float dt); //设置使用者结点,即记录表演动画的演员。 virtual void startWithTarget(CCNode *pTarget); //创建一个反向播放的动画。 virtual CCActionInterval* reverse(void); public: //静态函数:创建一个时间动画,其内部调用create来实现。 CC_DEPRECATED_ATTRIBUTE static CCActionInterval* actionWithDuration(float d); //静态函数:创建一个时间动画 static CCActionInterval* create(float d); public: // void setAmplitudeRate(float amp); float getAmplitudeRate(void); protected: //当前帧与上一帧的时间流逝值。单位是秒。 float m_elapsed; //这里定义一个布尔变量来判断是否是第一次计算时间,相当于一个时间计算方式的开关。 bool m_bFirstTick; }; 为了更直接的学习这些动画,我把CPP中的实现直接贴到相应的类定义后面。 //静态函数:创建一个时间动画,其内部调用create来实现。 CCActionInterval* CCActionInterval::actionWithDuration(float d) { return CCActionInterval::create(d); } //静态函数:创建一个时间动画 CCActionInterval* CCActionInterval::create(float d) { //先new出一个时间动画 CCActionInterval *pAction = new CCActionInterval(); //调用初始化函数。 pAction->initWithDuration(d); //设置其使用内存管理器进行释放。 pAction->autorelease(); //返回动画。 return pAction; } //初始化时间动画。 bool CCActionInterval::initWithDuration(float d) { //记录动画时长。 m_fDuration = d; //如果动画时长为0,这里取一个极小值,防止在计算中产生除零中断。 if (m_fDuration == 0) { m_fDuration = FLT_EPSILON; } //初始化代表时间累和的变量为0。 m_elapsed = 0; //初始化代表第一次进行时间间隔计算的布尔变量为true。 m_bFirstTick = true; return true; } //产生一个时间动画的拷贝。 CCObject* CCActionInterval::copyWithZone(CCZone *pZone) { //定义用于保存新拷贝指针的变量,参看CCZone的定义可以知道,它的功能仅仅是保存一个CCObject指针。 CCZone* pNewZone = NULL; //定义用于返回结果的CCActionInterval指针变量 CCActionInterval* pCopy = NULL; //如果pZone不为空且它保存了有效的CCObject,则返回给pCopy if(pZone && pZone->m_pCopyObject) { pCopy = (CCActionInterval*)(pZone->m_pCopyObject); } else { //如果pZone为空或没有拷贝,则创建一个CCActionInterval返回给pCopy,并由pCopy做为拷贝取得一个新的CCZone返回给pZone。这个pCopy的变量名称写的好,很清楚。比上一节的变量名称好。 pCopy = new CCActionInterval(); pZone = pNewZone = new CCZone(pCopy); } //调用基类的产生拷贝函数,可参见上一节内容。 CCFiniteTimeAction::copyWithZone(pZone); //释放pNewZone CC_SAFE_DELETE(pNewZone); //对产生的拷贝调用初始化函数 pCopy->initWithDuration(m_fDuration); //返回拷贝对象。 return pCopy; } //返回动画是否播放结束。 bool CCActionInterval::isDone(void) { //返回时间累和值是否大于等于动画总时长。 return m_elapsed >= m_fDuration; } //时间流逝的动画处理 void CCActionInterval::step(float dt) { //如果是播放开始第一次进行时间流逝处理,将时间累和值设为0。 if (m_bFirstTick) { m_bFirstTick = false; m_elapsed = 0; } else { //动画时间累和。 m_elapsed += dt; } //调用update函数更新动画。参数的结果是动画的时间插值结果,它代表了动画的进度,上一节讲过它取0~1之间的值。这里MIN和MAX用来将计算结果限定在0~1间。 this->update(MAX (0, // needed for rewind. elapsed could be negative MIN(1, m_elapsed / MAX(m_fDuration, FLT_EPSILON) // division by 0 ) ) ); } //设置振幅。子类重载进行功能实现。 void CCActionInterval::setAmplitudeRate(float amp) { CC_UNUSED_PARAM(amp); // Abstract class needs implementation CCAssert(0, ""); } //取得振幅。 float CCActionInterval::getAmplitudeRate(void) { // Abstract class needs implementation CCAssert(0, ""); return 0; } //动画初始化处理,设置将要表演动画的“演员”。 void CCActionInterval::startWithTarget(CCNode *pTarget) { //调用子类相应函数。 CCFiniteTimeAction::startWithTarget(pTarget); //设置累和值为零并设置是第一次进行动画时间流逝计算。 m_elapsed = 0.0f; m_bFirstTick = true; } //产生一个反向播放的动画。 CCActionInterval* CCActionInterval::reverse(void) { CCAssert(false, "CCIntervalAction: reverse not implemented."); return NULL; }
//动画序列:动画序列是将多个动画串联起来,使它们能够按照顺序一个一个的播放,这个类是一个很有用的类。 class CC_DLL CCSequence : public CCActionInterval { public: //析构 ~CCSequence(void); //初始化,参数为两个动画。初始化完成后会将两个动画保存在数组中。 bool initWithTwoActions(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo); //重载基类函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void stop(void); virtual void update(float t); virtual CCActionInterval* reverse(void); public: //静态函数:创建一个串联多个动画的动画序列。参数使用…来表示参数个数根据实际填写的个数为准。 CC_DEPRECATED_ATTRIBUTE static CCFiniteTimeAction* actions(CCFiniteTimeAction *pAction1, ...); //同上,只是参数为一个指针数组,数组里存放了要串联在一起的所有动画,即动画个数由数组大小决定。 CC_DEPRECATED_ATTRIBUTE static CCFiniteTimeAction* actionWithArray(CCArray *arrayOfActions); //静态函数:将两个时间动画串联成一个动画序列,其内部调用createWithTwoActions来实现。 CC_DEPRECATED_ATTRIBUTE static CCSequence* actionOneTwo(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo); //静态函数:将两个时间动画串联成一个动画序列。 static CCFiniteTimeAction* create(CCFiniteTimeAction *pAction1, ...); //同上。只是参数为一个指针数组,数组里存放了要串联在一起的所有动画,即动画个数由数组大小决定。 static CCFiniteTimeAction* create(CCArray *arrayOfActions); //静态函数:将两个时间动画串联成一个动画序列。 static CCSequence* createWithTwoActions(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo); protected: //存放串联在一起的两个动画的数组。 CCFiniteTimeAction *m_pActions[2]; //第一个串联动画时长占总时长的比率,代表了两个动画的分界进度。 float m_split; //保存上一帧正在播放的动画在串联动画数组中的索引,每帧更新为当前帧正在播放的的动画在串联动画数组中的索引。 int m_last; }; 具体实现: //静态函数:将两个时间动画串联成一个动画序列,其内部调用createWithTwoActions来实现。 CCSequence* CCSequence::actionOneTwo(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo) { return CCSequence::createWithTwoActions(pActionOne, pActionTwo); } //静态函数:将两个时间动画串联成一个动画序列。 CCSequence* CCSequence::createWithTwoActions(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo) { //使用new创建一个CCSequence实例对象。 CCSequence *pSequence = new CCSequence(); //对其调用初始化函数。 pSequence->initWithTwoActions(pActionOne, pActionTwo); //将其交由内存管理器进行释放。 pSequence->autorelease(); //返回新创建的动画序列。 return pSequence; } //静态函数:创建一个串联多个动画的动画序列。参数使用…来表示参数个数根据实际填写的个数为准。 CCFiniteTimeAction* CCSequence::actions(CCFiniteTimeAction *pAction1, ...) { //建立一个参数列表 va_list params; //将所有的CCFiniteTimeAction指针参数放入列表中、 va_start(params, pAction1); //定义临时CCFiniteTimeAction指针变量用于代表参数列表中当前项和上一项。 //当前项 CCFiniteTimeAction *pNow; //上一项,初始化为pAction1。 CCFiniteTimeAction *pPrev = pAction1; //利用while循环来取得参数列表中的所有参数。 while (pAction1) { //取得参数队列当前游标指向的参数。每调用一次,会将队列中头部的移除,下一个自动成为头部。 pNow = va_arg(params, CCFiniteTimeAction*); //如果有值 if (pNow) { //将上一项与当前项串联成一个序列动画存入上一项,这个处理就不断的把所有的序列动画串联在一起了。其关键点是理解序列本身也是动画。 pPrev = CCSequence::createWithTwoActions(pPrev, pNow); } else { //如果无值,中断退出循环。 break; } } //关闭参数表。 va_end(params); //将最终串联在一起的动画返回。 return pPrev; } //同上,只是函数名不同。 CCFiniteTimeAction* CCSequence::create(CCFiniteTimeAction *pAction1, ...) { va_list params; va_start(params, pAction1); CCFiniteTimeAction *pNow; CCFiniteTimeAction *pPrev = pAction1; while (pAction1) { pNow = va_arg(params, CCFiniteTimeAction*); if (pNow) { pPrev = createWithTwoActions(pPrev, pNow); } else { break; } } va_end(params); return pPrev; } //同上,只是参数是一个指针数组,数组中存放的是所有要串联在一起的动画,内部调用create实现。 CCFiniteTimeAction* CCSequence::actionWithArray(CCArray* arrayOfActions) { return CCSequence::create(arrayOfActions); } //同上,只是参数是一个指针数组,数组中存放的是所有要串联在一起的动画。 CCFiniteTimeAction* CCSequence::create(CCArray* arrayOfActions) { //先取得数组中第一项做为上一项。 CCFiniteTimeAction* prev = (CCFiniteTimeAction*)arrayOfActions->objectAtIndex(0); //然后从第二基开始遍历。分别取上一项与当前项来产生充列动画,并将产生的新的序列动画存入上一项中。 for (unsigned int i = 1; i < arrayOfActions->count(); ++i) { prev = createWithTwoActions(prev, (CCFiniteTimeAction*)arrayOfActions->objectAtIndex(i)); } //返回上一项。 return prev; } //这个函数才是真正的串联实现。 bool CCSequence::initWithTwoActions(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo) { //有效性判断 CCAssert(pActionOne != NULL, ""); CCAssert(pActionTwo != NULL, ""); //取得两个动画的动画时长累加后做为当前序列动画的总时长。 float d = pActionOne->getDuration() + pActionTwo->getDuration(); CCActionInterval::initWithDuration(d); //将代表上一个动画的指针存入串联数组项的第一项中。 m_pActions[0] = pActionOne; //因为整个过程占用此动画项,所以对其引用计数器加一。 pActionOne->retain(); //将代表当前动画的指针存入串联数组项的第二项中。 m_pActions[1] = pActionTwo; //因为整个过程占用此动画项,所以对其引用计数器加一。 pActionTwo->retain(); //返回true. return true; } //返回当前动画的拷贝,因讲的太多,故这里略过。 CCObject* CCSequence::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCSequence* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { pCopy = (CCSequence*)(pZone->m_pCopyObject); } else { pCopy = new CCSequence(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); //使用当前串联的两个动画的拷贝做为新生成的序列动画的串联动画。 pCopy->initWithTwoActions((CCFiniteTimeAction*)(m_pActions[0]->copy()->autorelease()), (CCFiniteTimeAction*)(m_pActions[1]->copy()->autorelease())); CC_SAFE_DELETE(pNewZone); return pCopy; } //析构,做释放处理,对两个占用的动画的引有计数做减一操作。 CCSequence::~CCSequence(void) { CC_SAFE_RELEASE(m_pActions[0]); CC_SAFE_RELEASE(m_pActions[1]); } //设置表演当前序列动画的演员。 void CCSequence::startWithTarget(CCNode *pTarget) { CCActionInterval::startWithTarget(pTarget); //计算两个串联动画的分界进度。 m_split = m_pActions[0]->getDuration() / m_fDuration; //将m_last先置为-1。 m_last = -1; } //停止当前序列动画。 void CCSequence::stop(void) { // 如果m_last值有效,则停止对应的串联动画。 if( m_last != - 1) { m_pActions[m_last]->stop(); } //调用基类的stop停止序列动画。 CCActionInterval::stop(); } //动画的播放计算处理 void CCSequence::update(float t) { //定义整型变量found来代表播放到第几个动画。 int found = 0; //定义浮点变量new_t来代表正在播放的串联动画的进度。 float new_t = 0.0f; //如果播放进度值小于分界进度值,即还在播放串联的第一个动画。 if( t < m_split ) { // 将变量found设置0。 found = 0; //这里是计算第一个串联动画的播放进度。 if( m_split != 0 ) new_t = t / m_split; else new_t = 1; } else { //否则,设置found变量为1,代表播放第二个串联动画。 found = 1; //这时是计算第二个串联动画的播放进度。 if ( m_split == 1 ) new_t = 1; else new_t = (t-m_split) / (1 - m_split ); } //如果在播放第二个串联动画。 if ( found==1 ) { //如果m_last为-1 ? 这个该怎么理解呢?为什么m_last会为-1,那不是说t >= m_split ?在什么情况下会发生这种情况呢?只有当m_split为0的情况!在startWithTarget函数中我们看下m_split的计算公式在什么情况下m_split为0呢?只有串联动画1的时长为0!那什么时候动画的时长为0呢?好吧,有许多动画时长为0,立即播放一次搞定!比如CCCallFuncN!的确,有不少这种东西被放在动画序列里做为播放完一个时间动画后调用某个函数处理的功能。 if( m_last == -1 ) { // 那就立即播放这个动画吧!播放完就停止。 m_pActions[0]->startWithTarget(m_pTarget); m_pActions[0]->update(1.0f); m_pActions[0]->stop(); } else if( m_last == 0 ) { //如果上一帧播放的是第一个动画。即首次播放第二个串联动画。 //设置第一个串联动画播放到尾部并停止。 m_pActions[0]->update(1.0f); m_pActions[0]->stop(); } } // 如果当前正在播放的动画已播放结束,直接返回。 if( found == m_last && m_pActions[found]->isDone() ) { return; } // 如果found与m_last不同,代表当前帧要播放的动画与上一帧播放的动画不同。即要播新动画。 if( found != m_last ) { m_pActions[found]->startWithTarget(m_pTarget); } //将新动画的进度传给新动画调用的update函数来实现播放。 m_pActions[found]->update(new_t); //将found值赋值给m_last。 m_last = found; } //创建一个序列动画的反向播放动画。 CCActionInterval* CCSequence::reverse(void) { //内部通过串联两个串联动画的反向动画来实现。注意的是,这时候串联的第一个动画应该为原串联动画的第二个动画的反向动画,第二个动画应该为原串联动画的第一个动画的反向动画。好好理解一下。 return CCSequence::createWithTwoActions(m_pActions[1]->reverse(), m_pActions[0]->reverse()); }
//重复动画。这个动画可以实现对另一个时间动画设置循环播放指定次数。 class CC_DLL CCRepeat : public CCActionInterval { public: ~CCRepeat(void); //初始化,传入一个要进行循环播放的时间动画,次数取1~pow(2,30)之间的整数。 bool initWithAction(CCFiniteTimeAction *pAction, unsigned int times); //重载基类函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void stop(void); virtual void update(float dt); virtual bool isDone(void); virtual CCActionInterval* reverse(void); //设置要进行循环的动画。 inline void setInnerAction(CCFiniteTimeAction *pAction) { //释放原来设置的动画,更新为参数指定的动画。 if (m_pInnerAction != pAction) { CC_SAFE_RETAIN(pAction); CC_SAFE_RELEASE(m_pInnerAction); m_pInnerAction = pAction; } } //取得要进行循环的动画。 inline CCFiniteTimeAction* getInnerAction() { return m_pInnerAction; } public: //静态函数:创建一个控制循环播放的动画。内部调用create来实现。参1为要进行循环播放的时间动画,参2为循环次数。 CC_DEPRECATED_ATTRIBUTE static CCRepeat* actionWithAction(CCFiniteTimeAction *pAction, unsigned int times); //静态函数:创建一个控制循环播放的动画。 static CCRepeat* create(CCFiniteTimeAction *pAction, unsigned int times); protected: //当前循环次数 unsigned int m_uTimes; //总的循环次数 unsigned int m_uTotal; // float m_fNextDt; //是否有控制循环播放的动画 bool m_bActionInstant; //所控制的要进行循环播放的动画 CCFiniteTimeAction *m_pInnerAction; }; 具体实现: //静态函数:创建一个控制循环播放的动画。内部调用create来实现。 CCRepeat* CCRepeat::actionWithAction(CCFiniteTimeAction *pAction, unsigned int times) { return CCRepeat::create(pAction, times); } //静态函数:创建一个控制循环播放的动画。 CCRepeat* CCRepeat::create(CCFiniteTimeAction *pAction, unsigned int times) { //先new出一个CCRepeat。 CCRepeat* pRepeat = new CCRepeat(); //初始化 pRepeat->initWithAction(pAction, times); //设置交由内存管理器进行释放 pRepeat->autorelease(); //返回创建的CCRepeat实例指针。 return pRepeat; } //初始化函数。 bool CCRepeat::initWithAction(CCFiniteTimeAction *pAction, unsigned int times) { //总时长等于一次动画的时长乘以循环次数。 float d = pAction->getDuration() * times; //设置动画的时长 if (CCActionInterval::initWithDuration(d)) { //保存动画循环次数。 m_uTimes = times; //保存控制循环播放的内部动画。 m_pInnerAction = pAction; //因为会占用此动画,所以对其引用计数器值加一。 pAction->retain(); //这里用dynamic_cast来判断pAction是否是CCActionInstant*的子类,其实是限制要求pAction要是一个有时长的时间动画而不是一个调用一次立即播放完成的动画。 m_bActionInstant = dynamic_cast<CCActionInstant*>(pAction) ? true : false; //如果属于调用一次立即播放完成的动画,就不能循环。 if (m_bActionInstant) { m_uTimes -=1; } //总时长变量初始化置0。 m_uTotal = 0; return true; } return false; } //略过,参见前面。 CCObject* CCRepeat::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCRepeat* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCRepeat*)(pZone->m_pCopyObject); } else { pCopy = new CCRepeat(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithAction((CCFiniteTimeAction*)(m_pInnerAction->copy()->autorelease()), m_uTimes); CC_SAFE_DELETE(pNewZone); return pCopy; } //析构 CCRepeat::~CCRepeat(void) { //不再占用内部控制循环的动画,在此对其引用计数器减1。 CC_SAFE_RELEASE(m_pInnerAction); } //设置演示当前控制动画的演员。 void CCRepeat::startWithTarget(CCNode *pTarget) { //总时长变量初始化置0。 m_uTotal = 0; //计算下一次循环切换时刻的动画进度。 m_fNextDt = m_pInnerAction->getDuration()/m_fDuration; //调用基类的初始化处理。 CCActionInterval::startWithTarget(pTarget); //对所控制的动画进行初始化。 m_pInnerAction->startWithTarget(pTarget); } //停止动画。 void CCRepeat::stop(void) { //停止所控制的动画 m_pInnerAction->stop(); //停止当前动画。 CCActionInterval::stop(); } //更新动画的播放,参数为时间进度。 void CCRepeat::update(float dt) { //如果已经到了该进行循环切换的时候! if (dt >= m_fNextDt) { //如果当前时间进度超过了循环切换的进度位置并且循环次数仍不够,则将循环的动画播放到结尾,并停止动画后重新初始化。 while (dt > m_fNextDt && m_uTotal < m_uTimes) { //将循环的动画播放到结尾。 m_pInnerAction->update(1.0f); //循环次数加1 m_uTotal++; //停止动画后重新初始化。 m_pInnerAction->stop(); m_pInnerAction->startWithTarget(m_pTarget); //计算下一次要切换时的进度位置。 m_fNextDt += m_pInnerAction->getDuration()/m_fDuration; } // 下面这一句是为了防止上面一句m_fNextDt因为浮点不精确可能出现的意外情况:即最后一次循环时可能未及时循环次数加1以致后面不能够停止。 if(dt >= 1.0f && m_uTotal < m_uTimes) { m_uTotal++; } // 限制要求pAction要是一个有时长的时间动画而不是一个调用一次立即播放完成的动画。 if (!m_bActionInstant) { //如果是最后一次循环结束,停止动画。 if (m_uTotal == m_uTimes) { m_pInnerAction->update(1); m_pInnerAction->stop(); } else { //否则更新动画。进度值等于当前时刻总进度dt减去上一次切换时刻的总进度( m_fNextDt - m_pInnerAction->getDuration()/m_fDuration),因为当前时刻不会正好等于切换时刻,总会有点余值,这个要计算到新循环中才精确。 m_pInnerAction->update(dt - (m_fNextDt - m_pInnerAction->getDuration()/m_fDuration)); } } } else { //未到循环切换时,计算进度,这里计算进度使用了浮点取模函数fmodf,咱们“笨人”一般应该是写成“(dt - m_fNextDt)/(m_pInnerAction->getDuration()/m_fDuration) ”,看看人家咋写的! m_pInnerAction->update(fmodf(dt * m_uTimes,1.0f)); } } //当前循环是否结束 bool CCRepeat::isDone(void) { //通过循环次数来判断。 return m_uTotal == m_uTimes; } //创建一个反向播放的循环动画。 CCActionInterval* CCRepeat::reverse(void) { return CCRepeat::create(m_pInnerAction->reverse(), m_uTimes); }
//无限循环动画。 class CC_DLL CCRepeatForever : public CCActionInterval { public: //构造与析构。 CCRepeatForever() : m_pInnerAction(NULL) {} virtual ~CCRepeatForever(); //初始化及一些基类重载函数。 bool initWithAction(CCActionInterval *pAction); virtual CCObject* copyWithZone(CCZone *pZone); virtual void startWithTarget(CCNode* pTarget); virtual void step(float dt); virtual bool isDone(void); virtual CCActionInterval* reverse(void); //设置要设置为无限循环播放的动画。 inline void setInnerAction(CCActionInterval *pAction) { //删除旧动画,更换新动画。 if (m_pInnerAction != pAction) { CC_SAFE_RELEASE(m_pInnerAction); m_pInnerAction = pAction; CC_SAFE_RETAIN(m_pInnerAction); } } //取得设置为无限循环播放的动画。 inline CCActionInterval* getInnerAction() { return m_pInnerAction; } public: //创建一个无限循环播放的动画,依然是调用create实现。 CC_DEPRECATED_ATTRIBUTE static CCRepeatForever* actionWithAction(CCActionInterval *pAction); //创建一个无限循环播放的动画。 static CCRepeatForever* create(CCActionInterval *pAction); protected: //设置为无限循环播放的动画。 CCActionInterval *m_pInnerAction; }; 具体实现: //析构 CCRepeatForever::~CCRepeatForever() { CC_SAFE_RELEASE(m_pInnerAction); } //创建一个无限循环播放的动画,依然是调用create实现。 CCRepeatForever *CCRepeatForever::actionWithAction(CCActionInterval *pAction) { return CCRepeatForever::create(pAction); } //创建一个无限循环播放的动画。 CCRepeatForever *CCRepeatForever::create(CCActionInterval *pAction) { //使用new创建一个无限循环动画。 CCRepeatForever *pRet = new CCRepeatForever(); //对其进行初始化 if (pRet && pRet->initWithAction(pAction)) { //成功则将其设置为交由内存管理器释放。 pRet->autorelease(); return pRet; } //如果出现任何失败,释放返回 CC_SAFE_DELETE(pRet); return NULL; } //初始化。 bool CCRepeatForever::initWithAction(CCActionInterval *pAction) { //参数有效性判断 CCAssert(pAction != NULL, ""); //占用pAction,故对其引用计数器加1 pAction->retain(); //记录所控制的动画。 m_pInnerAction = pAction; return true; } //产生一个拷贝,讲的头痛,略过。 CCObject* CCRepeatForever::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCRepeatForever* pRet = NULL; if(pZone && pZone->m_pCopyObject) { pRet = (CCRepeatForever*)(pZone->m_pCopyObject); } else { pRet = new CCRepeatForever(); pZone = pNewZone = new CCZone(pRet); } CCActionInterval::copyWithZone(pZone); pRet->initWithAction((CCActionInterval*)(m_pInnerAction->copy()->autorelease())); CC_SAFE_DELETE(pNewZone); return pRet; } //设置演示当前动画的演员。 void CCRepeatForever::startWithTarget(CCNode* pTarget) { CCActionInterval::startWithTarget(pTarget); m_pInnerAction->startWithTarget(pTarget); } //计算播放进度。 void CCRepeatForever::step(float dt) { //调用控制的动画的相应函数。 m_pInnerAction->step(dt); //如果此动画播放结束。重新初始化后给出新一轮循环的进度。 if (m_pInnerAction->isDone()) { //动画播放结束后,其当前时间长度大于动画时长,这里计算超了多少,做为下次循环的起始时间点,这样可以保证时间精确。 float diff = m_pInnerAction->getElapsed() - m_pInnerAction->getDuration(); m_pInnerAction->startWithTarget(m_pTarget); // 为什么要多调一次step(0.0f),因为在上一句初始化时其内部变量代表第一次播放的变量m_bFirstTick为true,第一次调用step时其参数会置0。只有第二次调用时设的值才管用。 m_pInnerAction->step(0.0f); m_pInnerAction->step(diff); } } //当前无限循环动画是否播放结束。那当然不可能结束,要不怎么叫无限循环动画呢? bool CCRepeatForever::isDone() { return false; } //返回一个反向播放的无限循环动画。 CCActionInterval *CCRepeatForever::reverse() { return (CCActionInterval*)(CCRepeatForever::create(m_pInnerAction->reverse())); }
//组合动画。与序列动画的不同为序列动画是一个一个顺序播放,组合动画是几个动画一起播放。 class CC_DLL CCSpawn : public CCActionInterval { public: //析构 ~CCSpawn(void); //初始化当前组合动画,将两个动画进行组合。 bool initWithTwoActions(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2); //重载基类相关函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void stop(void); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建组合动画,内部调用 CC_DEPRECATED_ATTRIBUTE static CCFiniteTimeAction* actions(CCFiniteTimeAction *pAction1, ...); //创建组合动画。 CC_DEPRECATED_ATTRIBUTE static CCFiniteTimeAction* actionWithArray(CCArray *arrayOfActions); //将两个动画进行组合。 CC_DEPRECATED_ATTRIBUTE static CCSpawn* actionOneTwo(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2); //将多个动画进行组合。 static CCFiniteTimeAction* create(CCFiniteTimeAction *pAction1, ...); //创建组合动画。参数为动画数组。 static CCFiniteTimeAction* create(CCArray *arrayOfActions); //创建组合动画。参数为两个动画。 static CCSpawn* createWithTwoActions(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2); protected: //要组合的第一个动画。 CCFiniteTimeAction *m_pOne; //要组合的第二个动画。 CCFiniteTimeAction *m_pTwo; }; 具体实现: //创建组合动画,内部调用 CCFiniteTimeAction* CCSpawn::actions(CCFiniteTimeAction *pAction1, ...) { //定义参数列表 va_list params; //将以pAction1为参数头的所有参数放到列表中。 va_start(params, pAction1); //定义临时变量来循环取出相应的参数。 CCFiniteTimeAction *pNow; CCFiniteTimeAction *pPrev = pAction1; //如果有参数,利用while来循环取出所有参数。 while (pAction1) { //取出新参数 pNow = va_arg(params, CCFiniteTimeAction*); if (pNow) { //利用pPrev和pNow来创建组合动画,最后生成的组合动画返回给pPrev继续组合。 pPrev = CCSpawn::createWithTwoActions(pPrev, pNow); } else { break; } } //取参操作结束。 va_end(params); return pPrev; } //同上,只是名称不同。 CCFiniteTimeAction* CCSpawn::create(CCFiniteTimeAction *pAction1, ...) { va_list params; va_start(params, pAction1); CCFiniteTimeAction *pNow; CCFiniteTimeAction *pPrev = pAction1; while (pAction1) { pNow = va_arg(params, CCFiniteTimeAction*); if (pNow) { pPrev = createWithTwoActions(pPrev, pNow); } else { break; } } va_end(params); return pPrev; } //同上,只是参数形式变为动画数组。 CCFiniteTimeAction* CCSpawn::actionWithArray(CCArray *arrayOfActions) { return CCSpawn::create(arrayOfActions); } //同上。名称不同。 CCFiniteTimeAction* CCSpawn::create(CCArray *arrayOfActions) { //先取数组第一个放入临时CCFiniteTimeAction* 变量。 CCFiniteTimeAction* prev = (CCFiniteTimeAction*)arrayOfActions->objectAtIndex(0); //从第二个起遍历数组进行组合,生成的动画存入临时CCFiniteTimeAction* 变量供下一次循环操作。 for (unsigned int i = 1; i < arrayOfActions->count(); ++i) { prev = createWithTwoActions(prev, (CCFiniteTimeAction*)arrayOfActions->objectAtIndex(i)); } return prev; } //组合两个动画,内部调用createWithTwoActions。 CCSpawn* CCSpawn::actionOneTwo(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2) { return CCSpawn::createWithTwoActions(pAction1, pAction2); } //组合两个动画。 CCSpawn* CCSpawn::createWithTwoActions(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2) { //使用new创建一个CCSpawn。 CCSpawn *pSpawn = new CCSpawn(); //初始化 pSpawn->initWithTwoActions(pAction1, pAction2); //交由内存管理器进行释放。 pSpawn->autorelease(); //返回新生成的CCSpawn实例对象指针。 return pSpawn; } //初始化。 bool CCSpawn:: initWithTwoActions(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2) { //有效性判断 CCAssert(pAction1 != NULL, ""); CCAssert(pAction2 != NULL, ""); //临时变量bRet,先置false bool bRet = false; //将两个动画的时长取出存入临时变量d1,d2。 float d1 = pAction1->getDuration(); float d2 = pAction2->getDuration(); //取出两个时长的最大值做为当前动画的时长。 if (CCActionInterval::initWithDuration(MAX(d1, d2))) { //将两个动画存入成员动画指针变量。 m_pOne = pAction1; m_pTwo = pAction2; //如果第一个动画时长大于第二个动画时长。 if (d1 > d2) { //第二个动画结束后保持不动。 m_pTwo = CCSequence::createWithTwoActions(pAction2, CCDelayTime::create(d1 - d2)); } else if (d1 < d2) { //反之,第一个动画结束后保持不动。 m_pOne = CCSequence::createWithTwoActions(pAction1, CCDelayTime::create(d2 - d1)); } //占用两个动画,所以引用计数器都加一。 m_pOne->retain(); m_pTwo->retain(); //返回初始化成功。 bRet = true; } return bRet; } //除了略过还是略过,头疼ing... CCObject* CCSpawn::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCSpawn* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCSpawn*)(pZone->m_pCopyObject); } else { pCopy = new CCSpawn(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithTwoActions((CCFiniteTimeAction*)(m_pOne->copy()->autorelease()), (CCFiniteTimeAction*)(m_pTwo->copy()->autorelease())); CC_SAFE_DELETE(pNewZone); return pCopy; } //析构 CCSpawn::~CCSpawn(void) { CC_SAFE_RELEASE(m_pOne); CC_SAFE_RELEASE(m_pTwo); } //设置演员。 void CCSpawn::startWithTarget(CCNode *pTarget) { CCActionInterval::startWithTarget(pTarget); m_pOne->startWithTarget(pTarget); m_pTwo->startWithTarget(pTarget); } //停止动画 void CCSpawn::stop(void) { m_pOne->stop(); m_pTwo->stop(); CCActionInterval::stop(); } //更新当前动画的播放进度。 void CCSpawn::update(float time) { //看,真的是分别对两个动画做了update调用。 if (m_pOne) { m_pOne->update(time); } if (m_pTwo) { m_pTwo->update(time); } } //创建反向播放的动画。 CCActionInterval* CCSpawn::reverse(void) { return CCSpawn::createWithTwoActions(m_pOne->reverse(), m_pTwo->reverse()); }
//旋转动画:旋转到某个角度。 class CC_DLL CCRotateTo : public CCActionInterval { public: //初始化 bool initWithDuration(float duration, float fDeltaAngle); //重载基类函数 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); public: //创建一个旋转动画,内部调用create函数。参数一为动画时长,参数二为旋转到的目标角度。 CC_DEPRECATED_ATTRIBUTE static CCRotateTo* actionWithDuration(float duration, float fDeltaAngle); //创建一个旋转动画。 static CCRotateTo* create(float duration, float fDeltaAngle); protected: //目标角度 float m_fDstAngle; //起始角度 float m_fStartAngle; //起始角度与目标角度之差。 float m_fDiffAngle; }; 具体实现: //创建一个旋转动画,内部调用create函数。 CCRotateTo* CCRotateTo::actionWithDuration(float duration, float fDeltaAngle) { return CCRotateTo::create(duration, fDeltaAngle); } //创建一个旋转动画。 CCRotateTo* CCRotateTo::create(float duration, float fDeltaAngle) { //使用new创建一个CCRotateTo对象。 CCRotateTo* pRotateTo = new CCRotateTo(); //对其初始化。 pRotateTo->initWithDuration(duration, fDeltaAngle); //交由内顾虑管理器进行释放。 pRotateTo->autorelease(); //返回实例指针 return pRotateTo; } //初始化。 bool CCRotateTo::initWithDuration(float duration, float fDeltaAngle) { //先调用基类初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //保存目标角度。 m_fDstAngle = fDeltaAngle; return true; } return false; } //略 CCObject* CCRotateTo::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCRotateTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCRotateTo*)(pZone->m_pCopyObject); } else { pCopy = new CCRotateTo(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_fDstAngle); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员 void CCRotateTo::startWithTarget(CCNode *pTarget) { //调用基类的设置函数。 CCActionInterval::startWithTarget(pTarget); //取得演员的当前旋转角度做为起始角度。 m_fStartAngle = pTarget->getRotation(); //如果演员当前有旋转角度,则把角度值限制在相应范围内。 if (m_fStartAngle > 0) { //如果正值限定在0~360之间。 m_fStartAngle = fmodf(m_fStartAngle, 360.0f); } else { //如果负值限定在-360~0之间。 m_fStartAngle = fmodf(m_fStartAngle, -360.0f); } //计算出目标角度与起始角度之差做为要旋转的角度。 m_fDiffAngle = m_fDstAngle - m_fStartAngle; //如果大于180度。则减去360度,为啥呢?因为“地球是圆的!”,正向转,反向转,你都能到美国,那当然要捡最近的路径转动。这个处理就是要达到转动最少的角度达到同样的目的,不过话说回来,貌似旋转动画应该设定旋转方向会更好。 if (m_fDiffAngle > 180) { m_fDiffAngle -= 360; } //如果小于-180度。则加上360度。 if (m_fDiffAngle < -180) { m_fDiffAngle += 360; } } //更新动画播放。 void CCRotateTo::update(float time) { //设置演员的旋转状态。 if (m_pTarget) { //对要进行旋转的角度m_fDiffAngle进行时间进度插值做为当前时刻旋转的角度。 m_pTarget->setRotation(m_fStartAngle + m_fDiffAngle * time); }}
//另一个旋转动画:从当前旋转角度再继续旋转多少。它与上个动画的不同是一个是追求结果,一个是追求过程。 class CC_DLL CCRotateBy : public CCActionInterval { public: //初始化。 bool initWithDuration(float duration, float fDeltaAngle); //重载基类函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建旋转动画,内部调用create。 CC_DEPRECATED_ATTRIBUTE static CCRotateBy* actionWithDuration(float duration, float fDeltaAngle); //创建旋转动画 static CCRotateBy* create(float duration, float fDeltaAngle); protected: //要旋转的角度。 float m_fAngle; //起始角度。 float m_fStartAngle; }; 具体实现: //创建旋转动画,内部调用create。 CCRotateBy* CCRotateBy::actionWithDuration(float duration, float fDeltaAngle) { return CCRotateBy::create(duration, fDeltaAngle); } //创建旋转动画。 CCRotateBy* CCRotateBy::create(float duration, float fDeltaAngle) { //使用new创建一个CCRotateBy。 CCRotateBy *pRotateBy = new CCRotateBy(); //对其初始化。 pRotateBy->initWithDuration(duration, fDeltaAngle); //交由内存管理器进行释放。 pRotateBy->autorelease(); //返回实例指针。 return pRotateBy; } //初始化。 bool CCRotateBy::initWithDuration(float duration, float fDeltaAngle) { //先调用基类的初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //将要旋转的角度保存到成员变量m_fAngle。 m_fAngle = fDeltaAngle; return true; } return false; } //略。 CCObject* CCRotateBy::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCRotateBy* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCRotateBy*)(pZone->m_pCopyObject); } else { pCopy = new CCRotateBy(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_fAngle); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前旋转动画的演员。 void CCRotateBy::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCActionInterval::startWithTarget(pTarget); //先记录一下演员的当前旋转状态。 m_fStartAngle = pTarget->getRotation(); } //更新动画播放 void CCRotateBy::update(float time) { //原理同上一个动画,对要进行旋转的角度m_fAngle进行时间进度插值做为当前时刻演员的旋转角度。 if (m_pTarget) { m_pTarget->setRotation(m_fStartAngle + m_fAngle * time); } } //创建一个反向播放的旋转动画。 CCActionInterval* CCRotateBy::reverse(void) { //其实就是向反方向旋转相同角度大小的旋转动画。 return CCRotateBy::create(m_fDuration, -m_fAngle); }
//位移动画:移动到某个位置。 class CC_DLL CCMoveTo : public CCActionInterval { public: //初始化。 bool initWithDuration(float duration, const CCPoint& position); //重载基类的相关函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); public: //创建一个移动动画,内部调用create实现。参数一为动画时长,参数二为要移动到的目标点。 CC_DEPRECATED_ATTRIBUTE static CCMoveTo* actionWithDuration(float duration, const CCPoint& position); //创建一个移动动画。 static CCMoveTo* create(float duration, const CCPoint& position); protected: //目标点位置 CCPoint m_endPosition; //当前起始位置 CCPoint m_startPosition; //移动的偏移。 CCPoint m_delta; }; 具体实现: //创建一个移动动画,内部调用create实现。 CCMoveTo* CCMoveTo::actionWithDuration(float duration, const CCPoint& position) { return CCMoveTo::create(duration, position); } //创建一个移动动画。 CCMoveTo* CCMoveTo::create(float duration, const CCPoint& position) { CCMoveTo *pMoveTo = new CCMoveTo(); pMoveTo->initWithDuration(duration, position); pMoveTo->autorelease(); return pMoveTo; } //初始化函数。 bool CCMoveTo::initWithDuration(float duration, const CCPoint& position) { //先调用基类的初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //保存目标位置。 m_endPosition = position; return true; } return false; } //略,你懂的,你珍惜我的脑细胞,对么? CCObject* CCMoveTo::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCMoveTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCMoveTo*)(pZone->m_pCopyObject); } else { pCopy = new CCMoveTo(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_endPosition); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示位移动画的演员。 void CCMoveTo::startWithTarget(CCNode *pTarget) { //调用其类的相应函数。 CCActionInterval::startWithTarget(pTarget); //记录演员的当前起始位置。 m_startPosition = pTarget->getPosition(); //保存起始位置和目标位置之差。 m_delta = ccpSub(m_endPosition, m_startPosition); } //更新动画的播放。 void CCMoveTo::update(float time) { //对位置偏移进行进度插值,再加上起始位置,即是当前时刻位置。 if (m_pTarget) { m_pTarget->setPosition(ccp(m_startPosition.x + m_delta.x * time, m_startPosition.y + m_delta.y * time)); } }
//位移动画:是上一个位移动画的子类。同上一个位移动画的不同是这个动画的目的是从当前位置移动多少偏移,是追求过程。 class CC_DLL CCMoveBy : public CCMoveTo { public: //初始化。 bool initWithDuration(float duration, const CCPoint& position); //重载基类的函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual CCActionInterval* reverse(void); public: //创建一个位移动画,内部调用create实现,参数一为动画时长,参数二为要移动的偏移。 CC_DEPRECATED_ATTRIBUTE static CCMoveBy* actionWithDuration(float duration, const CCPoint& position); //创建一个位移动画。 static CCMoveBy* create(float duration, const CCPoint& position); }; 具体实现: //创建一个位移动画,内部调用create实现。 CCMoveBy* CCMoveBy::actionWithDuration(float duration, const CCPoint& position) { return CCMoveBy::create(duration, position); } //创建一个位移动画,讲的太多。也略。 CCMoveBy* CCMoveBy::create(float duration, const CCPoint& position) { CCMoveBy *pMoveBy = new CCMoveBy(); pMoveBy->initWithDuration(duration, position); pMoveBy->autorelease(); return pMoveBy; } //初始化。 bool CCMoveBy::initWithDuration(float duration, const CCPoint& position) { //先调用基类初始化。 if (CCActionInterval::initWithDuration(duration)) { //保存要旋转的角度。 m_delta = position; return true; } //如果初始化失败返回false return false; } //产生拷贝,略。 CCObject* CCMoveBy::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCMoveBy* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCMoveBy*)(pZone->m_pCopyObject); } else { pCopy = new CCMoveBy(); pZone = pNewZone = new CCZone(pCopy); } CCMoveTo::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_delta); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员。 void CCMoveBy::startWithTarget(CCNode *pTarget) { //因为CCMoveBy是由CCMoveTo派生,m_delta是CCMoveTo的成员变量。而下一句调用CCMoveTo的初始化会改变m_delta的值。所以这里做个临时变量保存一下再调用CCMoveTo的实始化函数。 CCPoint dTmp = m_delta; CCMoveTo::startWithTarget(pTarget); m_delta = dTmp; } //产生一个反向播放的偏移动画。 CCActionInterval* CCMoveBy::reverse(void) { return CCMoveBy::create(m_fDuration, ccp(-m_delta.x, -m_delta.y)); }
//扭曲动作:这个动画是我在本节中遇到的最难解释的动画。我想了好久该怎么说,却仍然有些晦涩。扭曲动画可以理解为对精灵的两对对角分别进行X,Y方向的拉伸扭曲到目标角度的动画。 class CC_DLL CCSkewTo : public CCActionInterval { public: //构造 CCSkewTo(); //初始化及重载基类函数。 virtual bool initWithDuration(float t, float sx, float sy); virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); public: //创建一个扭曲动画,内部调用create实现。参一为动画时长,参二为右上角在X轴方向上的目标扭曲角度,参三为Y轴方向上的目标扭曲角度. CC_DEPRECATED_ATTRIBUTE static CCSkewTo* actionWithDuration(float t, float sx, float sy); //创建一个扭曲动画。 static CCSkewTo* create(float t, float sx, float sy); protected: float m_fSkewX;//子类CCSkewBy所用的变量,用于保存数据。 float m_fSkewY; //子类CCSkewBy所用的变量,用于保存数据。 float m_fStartSkewX;//X方向起始扭曲角度 float m_fStartSkewY;//Y方向起始扭曲角度 float m_fEndSkewX;//X方向目标扭曲角度 float m_fEndSkewY;//Y方向目标扭曲角度 float m_fDeltaX;//X方向上要扭曲多少角度 float m_fDeltaY;//Y方向上要扭曲多少角度 }; 具体实现://创建一个扭曲动画,内部调用create实现。 CCSkewTo* CCSkewTo::actionWithDuration(float t, float sx, float sy) { return CCSkewTo::create(t, sx, sy); } //创建一个扭曲动画。 CCSkewTo* CCSkewTo::create(float t, float sx, float sy) { //使用new创建一个扭曲动画对象实例。 CCSkewTo *pSkewTo = new CCSkewTo(); if (pSkewTo) { //如果成功,对其初始化。 if (pSkewTo->initWithDuration(t, sx, sy)) { //初始化成功,交由内存管理器进行释放。 pSkewTo->autorelease(); } else { //否则删除。 CC_SAFE_DELETE(pSkewTo); } } //返回创建的动画实例对象指针。 return pSkewTo; } //初始化。参一为动画时长,参二为右上角在X轴方向上的目标扭曲角度,参三为Y轴方向上的目标扭曲角度. bool CCSkewTo::initWithDuration(float t, float sx, float sy) { bool bRet = false; //初始化基类 if (CCActionInterval::initWithDuration(t)) { //记录扭曲的目标角度。 m_fEndSkewX = sx; m_fEndSkewY = sy; bRet = true; } return bRet; } //产生一个拷贝。 CCObject* CCSkewTo::copyWithZone(CCZone* pZone) { CCZone* pNewZone = NULL; CCSkewTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { pCopy = (CCSkewTo*)(pZone->m_pCopyObject); } else { pCopy = new CCSkewTo(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_fEndSkewX, m_fEndSkewY); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员。 void CCSkewTo::startWithTarget(CCNode *pTarget) { //初始化。 CCActionInterval::startWithTarget(pTarget); //起始的X扭曲角度。 m_fStartSkewX = pTarget->getSkewX(); // if (m_fStartSkewX > 0) { //如果m_fStartSkewX为正方向值,把它限制在0~180度之内。 m_fStartSkewX = fmodf(m_fStartSkewX, 180.f); } else { //如果m_fStartSkewX为负方向值,把它限制在0~180度之内。 m_fStartSkewX = fmodf(m_fStartSkewX, -180.f); } //计算将要扭曲的X轴角度。 m_fDeltaX = m_fEndSkewX - m_fStartSkewX; //如旋转一样,计算最小扭曲值。 if (m_fDeltaX > 180) { m_fDeltaX -= 360; } if (m_fDeltaX < -180) { m_fDeltaX += 360; } //起始的Y扭曲角度。 m_fStartSkewY = pTarget->getSkewY(); if (m_fStartSkewY > 0) { //如果m_fStartSkewY为正方向值,把它限制在0~180度之内。 m_fStartSkewY = fmodf(m_fStartSkewY, 360.f); } else { //如果m_fStartSkewY为负方向值,把它限制在0~180度之内。 m_fStartSkewY = fmodf(m_fStartSkewY, -360.f); } //计算将要扭曲的Y轴角度。 m_fDeltaY = m_fEndSkewY - m_fStartSkewY; //如旋转一样,计算最小扭曲值。 if (m_fDeltaY > 180) { m_fDeltaY -= 360; } if (m_fDeltaY < -180) { m_fDeltaY += 360; } } //更新动画播放。 void CCSkewTo::update(float t) { //类似旋转的计算,通过时间进度对扭曲角度进行插值,计算出最终的扭曲状态。 m_pTarget->setSkewX(m_fStartSkewX + m_fDeltaX * t); m_pTarget->setSkewY(m_fStartSkewY + m_fDeltaY * t); } //构造函数。 CCSkewTo::CCSkewTo() : m_fSkewX(0.0) , m_fSkewY(0.0) , m_fStartSkewX(0.0) , m_fStartSkewY(0.0) , m_fEndSkewX(0.0) , m_fEndSkewY(0.0) , m_fDeltaX(0.0) , m_fDeltaY(0.0) { }
//扭曲动画:从当前状态起在X,Y方向上设置扭曲多少角度,注意,它是CCSkewTo的子类。 class CC_DLL CCSkewBy : public CCSkewTo { public: //初始化。 virtual bool initWithDuration(float t, float sx, float sy); //重载设置演示当前扭曲动画的演员。 virtual void startWithTarget(CCNode *pTarget); //创建一个反向播放的当前扭曲动画。 virtual CCActionInterval* reverse(void); public: //创建一个扭曲动画,内部调用create实现。参一为动画时长,参二为右上角在X轴方向上的扭曲角度,参三为Y轴方向。 CC_DEPRECATED_ATTRIBUTE static CCSkewBy* actionWithDuration(float t, float deltaSkewX, float deltaSkewY); //创建一个扭曲动画。 static CCSkewBy* create(float t, float deltaSkewX, float deltaSkewY); }; 具体实现://创建一个扭曲动画,内部调用create实现。参一为动画时长,参二为右上角在X轴方向上的扭曲角度,参三为Y轴方向上的扭曲角度。 CCSkewBy* CCSkewBy::actionWithDuration(float t, float sx, float sy) { return CCSkewBy::create(t, sx, sy); } //创建一个扭曲动画。 CCSkewBy* CCSkewBy::create(float t, float sx, float sy) { //使用new创建一个CCSkewBy实例对象。 CCSkewBy *pSkewBy = new CCSkewBy(); if (pSkewBy) { //对其初始化。 if (pSkewBy->initWithDuration(t, sx, sy)) { //如果初始化成功,将其交由内存管理器进行释放。 pSkewBy->autorelease(); } else { //如果初始化失败,直接释放。 CC_SAFE_DELETE(pSkewBy); } } //返回创建的扭曲动画。 return pSkewBy; } //初始化函数。 bool CCSkewBy::initWithDuration(float t, float deltaSkewX, float deltaSkewY) { //定义布尔变量做为初始化成功与否的结果。 bool bRet = false; //调用基类的初始化函数,但初始化之后,目标角度和要扭曲的角度都不对的,需要重置。 if (CCSkewTo::initWithDuration(t, deltaSkewX, deltaSkewY)) { //将要扭曲的角度保存到变量中用于在设置演员时计算目标角度和要扭曲的角度,话说这两个变量真是应该放到CCSkewBy中而不是CCSkewTo中。 m_fSkewX = deltaSkewX; m_fSkewY = deltaSkewY; //设置布尔变量代表初始化成功。 bRet = true; } return bRet; } //设置演示当前动画的演员。 void CCSkewBy::startWithTarget(CCNode *pTarget) { //调用基类的设置演员函数。 CCSkewTo::startWithTarget(pTarget); //重置目标角度和要扭曲的角度 m_fDeltaX = m_fSkewX; m_fDeltaY = m_fSkewY; m_fEndSkewX = m_fStartSkewX + m_fDeltaX; m_fEndSkewY = m_fStartSkewY + m_fDeltaY; } //创建一个反向播放的扭曲动画。 CCActionInterval* CCSkewBy::reverse() { return create(m_fDuration, -m_fSkewX, -m_fSkewY); }
//跳跃移动动画:从当前位置经过几次跳跃并移动多远。 class CC_DLL CCJumpBy : public CCActionInterval { public: //初始化跳跃动画,参数一为时长,参数二为跳跃移动到的目标位置,参数三为每次跳跃的高度,参数四为跳跃次数。 bool initWithDuration(float duration, const CCPoint& position, float height, unsigned int jumps); //重载基类相关函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建一个跳跃移动动画。内部调用create函数实现。参数一为时长,参数二为跳跃移动多少偏移,参数三为每次跳跃的高度,参数四为跳跃次数。 CC_DEPRECATED_ATTRIBUTE static CCJumpBy* actionWithDuration(float duration, const CCPoint& position, float height, unsigned int jumps); //创建一个跳跃移动动画。 static CCJumpBy* create(float duration, const CCPoint& position, float height, unsigned int jumps); protected: //起始位置 CCPoint m_startPosition; //从当前位置所要移动的偏移。 CCPoint m_delta; //跳跃的高度。 float m_height; //跳跃的次数。 unsigned int m_nJumps; }; 具体实现://创建一个跳跃移动动画。内部调用create函数实现。 CCJumpBy* CCJumpBy::actionWithDuration(float duration, const CCPoint& position, float height, unsigned int jumps) { return CCJumpBy::create(duration, position, height, jumps); } //创建一个跳跃移动动画。 CCJumpBy* CCJumpBy::create(float duration, const CCPoint& position, float height, unsigned int jumps) { //new创建出跳跃动画,调用初始化并交由内存管理器。呵呵,估计是作者也觉得烦了。连pJumpBy是否为空也不判断了,还是应该加上的。 CCJumpBy *pJumpBy = new CCJumpBy(); pJumpBy->initWithDuration(duration, position, height, jumps); pJumpBy->autorelease(); //返回创建的跳跃动画。 return pJumpBy; } //初始化函数。 bool CCJumpBy::initWithDuration(float duration, const CCPoint& position, float height, unsigned int jumps) { //调用基类初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //如果成功将参数保存到相应成员变量中。 m_delta = position; m_height = height; m_nJumps = jumps; //直接返回成功。 return true; } //否则返回失败。呵呵,作者也不用布尔变量了,还是这样简洁。 return false; } //创建一个当前动画的拷贝,略过。 CCObject* CCJumpBy::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCJumpBy* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCJumpBy*)(pZone->m_pCopyObject); } else { pCopy = new CCJumpBy(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_delta, m_height, m_nJumps); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员 void CCJumpBy::startWithTarget(CCNode *pTarget) { //调用基类函数。 CCActionInterval::startWithTarget(pTarget); //将当前演员的位置保存到起始位置变量。 m_startPosition = pTarget->getPosition(); } //更新当前动画的播放。 void CCJumpBy::update(float time) { // 演员有效性判断。 if (m_pTarget) { //计算当前的跳跃次数进度并取浮点模值,即在一次跳跃中的进度。 float frac = fmodf(time * m_nJumps, 1.0f); //跳跃的实现关健:通过高度公式和进度计算出一个跳跃高度。 float y = m_height * 4 * frac * (1 - frac); //这个高度加上位移的位置高度做为当前的位置高度。 y += m_delta.y * time; //计算当前的X方向位置。 float x = m_delta.x * time; //设置演员的当前位置。 m_pTarget->setPosition(ccp(m_startPosition.x + x, m_startPosition.y + y)); } } //创建一个反向播放的跳跃动画。 CCActionInterval* CCJumpBy::reverse(void) { return CCJumpBy::create(m_fDuration, ccp(-m_delta.x, -m_delta.y), m_height, m_nJumps); }
//跳跃移动动画:从一个位置经过几次跳跃移动到目标位置,注意它是CCJumpBy的子类,哈,这次By在前,To在后。 class CC_DLL CCJumpTo : public CCJumpBy { public: //重载设置演员和拷贝函数。 virtual void startWithTarget(CCNode *pTarget); virtual CCObject* copyWithZone(CCZone* pZone); public: //创建跳跃动画,内部调用create实现。参数一为时长,参数二为跳跃移动到的目标位置,参数三为每次跳跃的高度,参数四为跳跃次数。 CC_DEPRECATED_ATTRIBUTE static CCJumpTo* actionWithDuration(float duration, const CCPoint& position, float height, int jumps); //创建跳跃动画。 static CCJumpTo* create(float duration, const CCPoint& position, float height, int jumps); }; 具体实现://创建跳跃动画,内部调用create实现。 CCJumpTo* CCJumpTo::actionWithDuration(float duration, const CCPoint& position, float height, int jumps) { return CCJumpTo::create(duration, position, height, jumps); } //创建跳跃动画。 CCJumpTo* CCJumpTo::create(float duration, const CCPoint& position, float height, int jumps) { //new创建出跳跃动画,调用初始化并交由内存管理器。 CCJumpTo *pJumpTo = new CCJumpTo(); pJumpTo->initWithDuration(duration, position, height, jumps); pJumpTo->autorelease(); //返回创建的跳跃动画。 return pJumpTo; } //创建拷贝。 CCObject* CCJumpTo::copyWithZone(CCZone* pZone) { CCZone* pNewZone = NULL; CCJumpTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCJumpTo*)(pZone->m_pCopyObject); } else { pCopy = new CCJumpTo(); pZone = pNewZone = new CCZone(pCopy); } CCJumpBy::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_delta, m_height, m_nJumps); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员。 void CCJumpTo::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCJumpBy::startWithTarget(pTarget); //重新计算要移动的偏移。 m_delta = ccp(m_delta.x - m_startPosition.x, m_delta.y - m_startPosition.y); }
//贝赛尔曲线结构。什么是“贝赛尔曲线”?有事找度娘。 typedef struct _ccBezierConfig { //结束点。 CCPoint endPosition; //第一控制点。 CCPoint controlPoint_1; //第二控制点。 CCPoint controlPoint_2; } ccBezierConfig; //贝赛尔曲线移动动画。这里是按照贝赛尔曲线移动多少偏移。 class CC_DLL CCBezierBy : public CCActionInterval { public: //初始化动画,参数一为时长,参数二为设置的曲线信息。 bool initWithDuration(float t, const ccBezierConfig& c); //重载相应函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建一个贝塞尔曲线,内部调用create实现。参数一为动画时长,参数二为曲线结构。 CC_DEPRECATED_ATTRIBUTE static CCBezierBy* actionWithDuration(float t, const ccBezierConfig& c); //创建一个贝塞尔曲线。 static CCBezierBy* create(float t, const ccBezierConfig& c); protected: //贝塞尔结构。 ccBezierConfig m_sConfig; //起始点。 CCPoint m_startPosition; }; 具体实现: //创建一个贝塞尔曲线移动动画,内部调用create实现。 CCBezierBy* CCBezierBy::actionWithDuration(float t, const ccBezierConfig& c) { return CCBezierBy::create(t, c); } //创建一个贝塞尔曲线移动动画。 CCBezierBy* CCBezierBy::create(float t, const ccBezierConfig& c) { //使用new创建一个贝塞尔曲线动画实例对象,对其初始化并交由内存管理器释放,又忘做有效性判断了,唉。 CCBezierBy *pBezierBy = new CCBezierBy(); pBezierBy->initWithDuration(t, c); pBezierBy->autorelease(); //返回创建的动画实例对象。 return pBezierBy; } //初始化贝塞尔曲线移动动画。 bool CCBezierBy::initWithDuration(float t, const ccBezierConfig& c) { //调用基类初始化函数。 if (CCActionInterval::initWithDuration(t)) {//保存贝塞尔曲线信息,并返回true。 m_sConfig = c; return true; } //如果初始化失败返回false。 return false; } //设置演示当前动画的演员。 void CCBezierBy::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCActionInterval::startWithTarget(pTarget); //取得演员的起始位置保存到成员变量。 m_startPosition = pTarget->getPosition(); } //产生拷贝。 CCObject* CCBezierBy::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCBezierBy* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCBezierBy*)(pZone->m_pCopyObject); } else { pCopy = new CCBezierBy(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_sConfig); CC_SAFE_DELETE(pNewZone); return pCopy; } //更新动画的播放。 void CCBezierBy::update(float time) { //演员的有效性判断。 if (m_pTarget) { //x方向上的四个点位置。起始点,第一控制点,第二控制点,结束点。 float xa = 0; float xb = m_sConfig.controlPoint_1.x; float xc = m_sConfig.controlPoint_2.x; float xd = m_sConfig.endPosition.x; //y方向上的四个点位置。 float ya = 0; float yb = m_sConfig.controlPoint_1.y; float yc = m_sConfig.controlPoint_2.y; float yd = m_sConfig.endPosition.y; //通过四个点的位置和进度插值来调用贝塞尔曲线公式函数bezierat计算出当前的位置。 float x = bezierat(xa, xb, xc, xd, time); float y = bezierat(ya, yb, yc, yd, time); //因为是By动画,所以要加上起始位置后设置为演员当前位置。 m_pTarget->setPosition(ccpAdd(m_startPosition, ccp(x, y))); } } //创建一个反向播放的贝塞尔曲线移动动画。 CCActionInterval* CCBezierBy::reverse(void) { //定义一个新的贝塞尔曲线信息结构。 ccBezierConfig r; //ccpNeg是取负数,这里代表结尾的偏移位置改为反方向的相应偏移位置。 r.endPosition = ccpNeg(m_sConfig.endPosition); r.controlPoint_1 = ccpAdd(m_sConfig.controlPoint_2, ccpNeg(m_sConfig.endPosition)); r.controlPoint_2 = ccpAdd(m_sConfig.controlPoint_1, ccpNeg(m_sConfig.endPosition)); CCBezierBy *pAction = CCBezierBy::create(m_fDuration, r); return pAction; }
//贝赛尔曲线移动动画。这里是按照贝赛尔曲线移动到目标点。它是CCBezierBy的子类。 class CC_DLL CCBezierTo : public CCBezierBy { public: //重载基类函数。 virtual void startWithTarget(CCNode *pTarget); virtual CCObject* copyWithZone(CCZone* pZone); public: //创建一个贝塞尔曲线移动动画,内部调用create实现。参数一为动画时长,参数二为曲线结构。 CC_DEPRECATED_ATTRIBUTE static CCBezierTo* actionWithDuration(float t, const ccBezierConfig& c); //创建一个贝塞尔曲线移动动画。 static CCBezierTo* create(float t, const ccBezierConfig& c); }; 具体实现: //创建一个贝塞尔曲线移动动画,内部调用create实现。 CCBezierTo* CCBezierTo::actionWithDuration(float t, const ccBezierConfig& c) { return CCBezierTo::create(t, c); } //创建一个贝塞尔曲线移动动画。 CCBezierTo* CCBezierTo::create(float t, const ccBezierConfig& c) { //使用new创建一个贝塞尔曲线动画实例对象,对其初始化并交由内存管理器释放,有效性判断呢,唉。 CCBezierTo *pBezierTo = new CCBezierTo(); pBezierTo->initWithDuration(t, c); pBezierTo->autorelease(); //返回创建的动画。 return pBezierTo; } //创建拷贝。 CCObject* CCBezierTo::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCBezierBy* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCBezierTo*)(pZone->m_pCopyObject); } else { pCopy = new CCBezierTo(); pZone = pNewZone = new CCZone(pCopy); } CCBezierBy::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_sConfig); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演员当前动画的演员。 void CCBezierTo::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCBezierBy::startWithTarget(pTarget); //因为是移动到目标位置,所以这里要对曲线的结构进行一个重置,都加上起始的位置。曲线移动就由By变To了~。 m_sConfig.controlPoint_1 = ccpSub(m_sConfig.controlPoint_1, m_startPosition); m_sConfig.controlPoint_2 = ccpSub(m_sConfig.controlPoint_2, m_startPosition); m_sConfig.endPosition = ccpSub(m_sConfig.endPosition, m_startPosition); }
//缩放动画:缩放到指定大小 class CC_DLL CCScaleTo : public CCActionInterval { public: //初始化等比缩放动画,参一为时长,参二为等比缩放目标值. bool initWithDuration(float duration, float s); //初始化非等比缩放动画,参一为时长,参二为X方向缩放目标值,参三为Y方向缩放目标值. bool initWithDuration(float duration, float sx, float sy); //拷贝. virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); public: //创建一个等比缩放动画.内部调用create实现. CC_DEPRECATED_ATTRIBUTE static CCScaleTo* actionWithDuration(float duration, float s); //创建一个非等比缩放动画.内部调用create实现. CC_DEPRECATED_ATTRIBUTE static CCScaleTo* actionWithDuration(float duration, float sx, float sy); //创建一个等比缩放动画. static CCScaleTo* create(float duration, float s); //创建一个非等比缩放动画. static CCScaleTo* create(float duration, float sx, float sy); protected: //又是给子类CCScaleBy用的.Why放在这里? float m_fScaleX; float m_fScaleY; //起始缩放值 float m_fStartScaleX; float m_fStartScaleY; //目标缩放值 float m_fEndScaleX; float m_fEndScaleY; //动画过程要缩放的大小. float m_fDeltaX; float m_fDeltaY; }; 具体实现: //创建一个等比缩放动画. CCScaleTo* CCScaleTo::actionWithDuration(float duration, float s) { return CCScaleTo::create(duration, s); } //创建一个等比缩放动画. CCScaleTo* CCScaleTo::create(float duration, float s) { //使用new创建一个等比缩放动画,之后初始化并交由内存管理器进行释放处理. CCScaleTo *pScaleTo = new CCScaleTo(); pScaleTo->initWithDuration(duration, s); pScaleTo->autorelease(); //返回创建的等比缩放动画. return pScaleTo; } //初始化等比缩放动画. bool CCScaleTo::initWithDuration(float duration, float s) { //调用基类的初始化函数. if (CCActionInterval::initWithDuration(duration)) { //保存目标缩放大小. m_fEndScaleX = s; m_fEndScaleY = s; return true; } return false; } //创建一个非等比缩放动画.内部调用create实现. CCScaleTo* CCScaleTo::actionWithDuration(float duration, float sx, float sy) { return CCScaleTo::create(duration, sx, sy); } //创建一个非等比缩放动画. CCScaleTo* CCScaleTo::create(float duration, float sx, float sy) { //使用new创建一个非等比缩放动画,之后初始化并交由内存管理器进行释放处理. CCScaleTo *pScaleTo = new CCScaleTo(); pScaleTo->initWithDuration(duration, sx, sy); pScaleTo->autorelease(); //返回创建的非等比缩放动画. return pScaleTo; } //初始化非等比缩放动画. bool CCScaleTo::initWithDuration(float duration, float sx, float sy) { //调用基类的初始化函数. if (CCActionInterval::initWithDuration(duration)) { //保存目标缩放大小. m_fEndScaleX = sx; m_fEndScaleY = sy; return true; } return false; } //创建拷贝. CCObject* CCScaleTo::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCScaleTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCScaleTo*)(pZone->m_pCopyObject); } else { pCopy = new CCScaleTo(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_fEndScaleX, m_fEndScaleY); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员. void CCScaleTo::startWithTarget(CCNode *pTarget) { //调用基类函数. CCActionInterval::startWithTarget(pTarget); //保存起始缩放值. m_fStartScaleX = pTarget->getScaleX(); m_fStartScaleY = pTarget->getScaleY(); //保存动画过程中要缩放大小. m_fDeltaX = m_fEndScaleX - m_fStartScaleX; m_fDeltaY = m_fEndScaleY - m_fStartScaleY; } //更新动画 void CCScaleTo::update(float time) { //如果演员有效,通过时间进度插值来计算当前的缩放大小,并设置为演员的缩放值. if (m_pTarget) { m_pTarget->setScaleX(m_fStartScaleX + m_fDeltaX * time); m_pTarget->setScaleY(m_fStartScaleY + m_fDeltaY * time); } }
//缩放动画:控制演员由当前缩放值缩放多少.是CCScaleTo的子类. class CC_DLL CCScaleBy : public CCScaleTo { public: //重载相关函数. virtual void startWithTarget(CCNode *pTarget); virtual CCActionInterval* reverse(void); virtual CCObject* copyWithZone(CCZone* pZone); public: //创建等比缩放动画.内部调用create函数. CC_DEPRECATED_ATTRIBUTE static CCScaleBy* actionWithDuration(float duration, float s); //创建非等比缩放动画.内部调用create函数. CC_DEPRECATED_ATTRIBUTE static CCScaleBy* actionWithDuration(float duration, float sx, float sy); //创建等比缩放动画. static CCScaleBy* create(float duration, float s); //创建非等比缩放动画. static CCScaleBy* create(float duration, float sx, float sy); }; 具体实现: //创建等比缩放动画.内部调用create函数. CCScaleBy* CCScaleBy::actionWithDuration(float duration, float s) { return create(duration, s); } //创建非等比缩放动画.内部调用create函数. CCScaleBy* CCScaleBy::actionWithDuration(float duration, float sx, float sy) { return create(duration, sx, sy); } //创建等比缩放动画. CCScaleBy* CCScaleBy::create(float duration, float s) { //使用new创建一个等比缩放动画,之后初始化并交由内存管理器进行释放处理. CCScaleBy *pScaleBy = new CCScaleBy(); pScaleBy->initWithDuration(duration, s); pScaleBy->autorelease(); //返回创建的动画实例对象指针. return pScaleBy; } //创建非等比缩放动画. CCScaleBy* CCScaleBy::create(float duration, float sx, float sy) { //使用new创建一个非等比缩放动画,之后初始化并交由内存管理器进行释放处理. CCScaleBy *pScaleBy = new CCScaleBy(); pScaleBy->initWithDuration(duration, sx, sy); pScaleBy->autorelease(); //返回创建的动画实例对象指针. return pScaleBy; } //创建拷贝. CCObject* CCScaleBy::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCScaleTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCScaleBy*)(pZone->m_pCopyObject); } else { pCopy = new CCScaleBy(); pZone = pNewZone = new CCZone(pCopy); } CCScaleTo::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_fEndScaleX, m_fEndScaleY); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员. void CCScaleBy::startWithTarget(CCNode *pTarget) { //调用基类的相应函数. CCScaleTo::startWithTarget(pTarget); //重新计算要缩放的大小. m_fDeltaX = m_fStartScaleX * m_fEndScaleX - m_fStartScaleX; m_fDeltaY = m_fStartScaleY * m_fEndScaleY - m_fStartScaleY; } //创建一个反向播放的CCScaleBy动画.注意,CCScaleTo动画没有这个函数哦,当然也不是不能,可能作者懒,没空加吧!有兴趣的可以自已改一下CCScaleTo,加上反向播放动画.~ CCActionInterval* CCScaleBy::reverse(void) { //取倒数做为反向缩放动画的参数. return CCScaleBy::create(m_fDuration, 1 / m_fEndScaleX, 1 / m_fEndScaleY); }
//闪现动画:"一闪一闪亮晶晶,满天都是小星星." class CC_DLL CCBlink : public CCActionInterval { public: //初始化闪现动画. bool initWithDuration(float duration, unsigned int uBlinks); //重载相应函数. virtual CCObject* copyWithZone(CCZone* pZone); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建一个闪现动画.内部调用create实现.参一为动画时长,参二为闪现次数. CC_DEPRECATED_ATTRIBUTE static CCBlink* actionWithDuration(float duration, unsigned int uBlinks); //创建一个闪现动画. static CCBlink* create(float duration, unsigned int uBlinks); protected: unsigned int m_nTimes; }; 具体实现: //创建一个闪现动画 CCBlink* CCBlink::actionWithDuration(float duration, unsigned int uBlinks) { return CCBlink::create(duration, uBlinks); } //创建一个闪现动画. CCBlink* CCBlink::create(float duration, unsigned int uBlinks) { //使用new创建一个闪现动画,之后初始化并交由内存管理器进行释放处理. CCBlink *pBlink = new CCBlink(); pBlink->initWithDuration(duration, uBlinks); pBlink->autorelease(); //返回创建的动画 return pBlink; } //初始化闪现动画. bool CCBlink::initWithDuration(float duration, unsigned int uBlinks) { //调用基类的初始化函数. if (CCActionInterval::initWithDuration(duration)) { //保存闪现次数. m_nTimes = uBlinks; return true; } return false; } //创建拷贝. CCObject* CCBlink::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCBlink* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCBlink*)(pZone->m_pCopyObject); } else { pCopy = new CCBlink(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, (unsigned int)m_nTimes); CC_SAFE_DELETE(pNewZone); return pCopy; } //更新闪现动画. void CCBlink::update(float time) { //如果有演员且动画未结束. if (m_pTarget && ! isDone()) { //计算每一次闪现的时间进度存入变量slice. float slice = 1.0f / m_nTimes; //当前的时间进度与slice取模计算本次闪现的时间进度. float m = fmodf(time, slice); //如果时间进度走过了本次闪现的一半进度,切换显示或不显示. m_pTarget->setVisible(m > slice / 2 ? true : false); } } //创建一个反向播放的闪现动画.这个没什么正反的,都一样~ CCActionInterval* CCBlink::reverse(void) { return CCBlink::create(m_fDuration, m_nTimes); }
//淡入动画:渐渐显现的动画. class CC_DLL CCFadeIn : public CCActionInterval { public: //重载相应函数. virtual void update(float time); virtual CCActionInterval* reverse(void); virtual CCObject* copyWithZone(CCZone* pZone); public: //创建一个淡入动画,内部调用create实现.参数为淡入时间. CC_DEPRECATED_ATTRIBUTE static CCFadeIn* actionWithDuration(float d); //创建一个淡入动画 static CCFadeIn* create(float d); }; 具体实现: //创建一个淡入动画,内部调用create实现. CCFadeIn* CCFadeIn::actionWithDuration(float d) { return CCFadeIn::create(d); } //创建一个渐渐显现的淡入动画. CCFadeIn* CCFadeIn::create(float d) { //利用new创建一个淡入动画.初始化后交由内存管理器进行释放处理. CCFadeIn* pAction = new CCFadeIn(); pAction->initWithDuration(d); pAction->autorelease(); //返回创建的淡入动画. return pAction; } //创建一个拷贝. CCObject* CCFadeIn::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCFadeIn* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCFadeIn*)(pZone->m_pCopyObject); } else { pCopy = new CCFadeIn(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); CC_SAFE_DELETE(pNewZone); return pCopy; } //更新淡入动画. void CCFadeIn::update(float time) { //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(m_pTarget); if (pRGBAProtocol) { //如果转换成功,按时间进度设置透明度.透明度取值0~255,所以要乘以255. pRGBAProtocol->setOpacity((GLubyte)(255 * time)); } /*m_pTarget->setOpacity((GLubyte)(255 * time));*/ } //创建一个反向播放的淡入动画.其实是创建一个相同时间的渐渐消失的淡出动画. CCActionInterval* CCFadeIn::reverse(void) { return CCFadeOut::create(m_fDuration); }
//淡出动画:渐渐消失的动画. class CC_DLL CCFadeOut : public CCActionInterval { public: //重载相应函数. virtual void update(float time); virtual CCActionInterval* reverse(void); virtual CCObject* copyWithZone(CCZone* pZone); public: //创建一个淡出动画,内部调用create实现.参数为淡入时间. CC_DEPRECATED_ATTRIBUTE static CCFadeOut* actionWithDuration(float d); //创建一个淡出动画. static CCFadeOut* create(float d); }; 具体实现: //创建一个淡出动画,内部调用create实现.参数为淡入时间. CCFadeOut* CCFadeOut::actionWithDuration(float d) { return CCFadeOut::create(d); } //创建一个淡出动画. CCFadeOut* CCFadeOut::create(float d) { //利用new创建一个淡出动画.初始化后交由内存管理器进行释放处理. CCFadeOut* pAction = new CCFadeOut(); pAction->initWithDuration(d); pAction->autorelease(); //返回创建的动画实例对象指针. return pAction; } //创建拷贝. CCObject* CCFadeOut::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCFadeOut* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCFadeOut*)(pZone->m_pCopyObject); } else { pCopy = new CCFadeOut(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); CC_SAFE_DELETE(pNewZone); return pCopy; } //更新淡出动画. void CCFadeOut::update(float time) { //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(m_pTarget); if (pRGBAProtocol) { //如果转换成功,按时间进度设置透明度.透明度取值0~255,所以要乘以255. pRGBAProtocol->setOpacity(GLubyte(255 * (1 - time))); } /*m_pTarget->setOpacity(GLubyte(255 * (1 - time)));*/ } //创建一个反向播放的淡出动画.其实是创建一个相同时间的渐渐显示的淡入动画. CCActionInterval* CCFadeOut::reverse(void) { return CCFadeIn::create(m_fDuration); } //透明度渐变动画:从当前透明度渐渐变化到指定的透明度. class CC_DLL CCFadeTo : public CCActionInterval { public: //初始化,参数一为时间长度,参数二为目标透明度。 bool initWithDuration(float duration, GLubyte opacity); //重载基类相应函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); public: //创建一个透明度渐变动画,内部调用create实现,参数一为时间长度,参数二为目标透明度。 CC_DEPRECATED_ATTRIBUTE static CCFadeTo* actionWithDuration(float duration, GLubyte opacity); //创建一个透明度渐变动画。 static CCFadeTo* create(float duration, GLubyte opacity); protected: //目标透明度 GLubyte m_toOpacity; //当前透明度。 GLubyte m_fromOpacity; }; 具体实现: //创建一个透明度渐变动画,内部调用create实现,参数一为时间长度,参数二为目标透明度。 CCFadeTo* CCFadeTo::actionWithDuration(float duration, GLubyte opacity) { return CCFadeTo::create(duration, opacity); } //创建一个透明度渐变动画。 CCFadeTo* CCFadeTo::create(float duration, GLubyte opacity) { //利用new创建一个透明度渐变动画.初始化后交由内存管理器进行释放处理. CCFadeTo *pFadeTo = new CCFadeTo(); pFadeTo->initWithDuration(duration, opacity); pFadeTo->autorelease(); //返回创建的动画实例对象指针。 return pFadeTo; } //初始化。 bool CCFadeTo::initWithDuration(float duration, GLubyte opacity) { //调用基类的初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //保存目标透明度值并返回成功。 m_toOpacity = opacity; return true; } //否则返回失败。 return false; } //创建拷贝。 CCObject* CCFadeTo::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCFadeTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCFadeTo*)(pZone->m_pCopyObject); } else { pCopy = new CCFadeTo(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_toOpacity); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示当前动画的演员。 void CCFadeTo::startWithTarget(CCNode *pTarget) { //调用基类相应函数。 CCActionInterval::startWithTarget(pTarget); //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(pTarget); if (pRGBAProtocol) { //取得当前演员的透明度做为起始透明度。 m_fromOpacity = pRGBAProtocol->getOpacity(); } /*m_fromOpacity = pTarget->getOpacity();*/ } //更新动画。 void CCFadeTo::update(float time) { //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(m_pTarget); if (pRGBAProtocol) { //通过时间插值计算当前演员的透明度值。 pRGBAProtocol->setOpacity((GLubyte)(m_fromOpacity + (m_toOpacity - m_fromOpacity) * time)); } /*m_pTarget->setOpacity((GLubyte)(m_fromOpacity + (m_toOpacity - m_fromOpacity) * time));*/ }
//变色动画:从当前演员的色彩值变化到目标色彩。 class CC_DLL CCTintTo : public CCActionInterval { public: //初始化:参一为动画时长,参二,三,四分别代表目标色彩的红色,绿色,蓝色的分量。 bool initWithDuration(float duration, GLubyte red, GLubyte green, GLubyte blue); //重载基类函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); public: //创建一个变色动画,内部调用create实现。参一为动画时长,参二,三,四分别代表目标色彩的红色,绿色,蓝色的分量。 CC_DEPRECATED_ATTRIBUTE static CCTintTo* actionWithDuration(float duration, GLubyte red, GLubyte green, GLubyte blue); //创建一个变色动画。 static CCTintTo* create(float duration, GLubyte red, GLubyte green, GLubyte blue); protected: //目标的三原色。 ccColor3B m_to; //起始的三原色。 ccColor3B m_from; }; 具体实现: //创建一个变色动画,内部调用create实现。参一为动画时长,参二,三,四分别代表目标色彩的红色,绿色,蓝色的分量。 CCTintTo* CCTintTo::actionWithDuration(float duration, GLubyte red, GLubyte green, GLubyte blue) { return CCTintTo::create(duration, red, green, blue); } //创建一个变色动画。 CCTintTo* CCTintTo::create(float duration, GLubyte red, GLubyte green, GLubyte blue) { //利用new创建一个变色动画.初始化后交由内存管理器进行释放处理. CCTintTo *pTintTo = new CCTintTo(); pTintTo->initWithDuration(duration, red, green, blue); pTintTo->autorelease(); //返回创建的动画实例对象指针。 return pTintTo; } //初始化。 bool CCTintTo::initWithDuration(float duration, GLubyte red, GLubyte green, GLubyte blue) { //先调用基类的初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //保存目标色彩值。 m_to = ccc3(red, green, blue); //返回成功。 return true; } //如果初始化失败返回false。 return false; } //创建拷贝。 CCObject* CCTintTo::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCTintTo* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCTintTo*)(pZone->m_pCopyObject); } else { pCopy = new CCTintTo(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, m_to.r, m_to.g, m_to.b); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演示变色动画的演员。 void CCTintTo::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCActionInterval::startWithTarget(pTarget); //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(m_pTarget); if (pRGBAProtocol) { //取得演员的色彩值做为起始色彩值。 m_from = pRGBAProtocol->getColor(); } /*m_from = pTarget->getColor();*/ } //更新动画的播放。 void CCTintTo::update(float time) { //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(m_pTarget); if (pRGBAProtocol) { //利用时间对色彩变化进行插值,计算出演员的当前色彩值。 pRGBAProtocol->setColor(ccc3(GLubyte(m_from.r + (m_to.r - m_from.r) * time), (GLbyte)(m_from.g + (m_to.g - m_from.g) * time), (GLbyte)(m_from.b + (m_to.b - m_from.b) * time))); } }
//变色动画:从当前演员的色彩值变化多少。 class CC_DLL CCTintBy : public CCActionInterval { public: //初始化:参一为动画时长,参二,三,四分别代表变化色彩的红色,绿色,蓝色的分量。 bool initWithDuration(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue); //重载基类的函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建一个变色动画,内部调用create实现。参一为动画时长,参二,三,四分别代表要变化的色彩的红色,绿色,蓝色的分量。 CC_DEPRECATED_ATTRIBUTE static CCTintBy* actionWithDuration(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue); //创建一个变色动画。 static CCTintBy* create(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue); protected: //色彩变化值的三分量。我真想跪了,前面不是用ccColor3B 挺好么? GLshort m_deltaR; GLshort m_deltaG; GLshort m_deltaB; //起始色彩值的三分量。 GLshort m_fromR; GLshort m_fromG; GLshort m_fromB; }; 具体实现: //创建一个变色动画,内部调用create实现。参一为动画时长,参二,三,四分别代表要变化的色彩的红色,绿色,蓝色的分量。 CCTintBy* CCTintBy::actionWithDuration(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue) { return CCTintBy::create(duration, deltaRed, deltaGreen, deltaBlue); } //创建一个变色动画。 CCTintBy* CCTintBy::create(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue) { //利用new创建一个变色动画.初始化后交由内存管理器进行释放处理. CCTintBy *pTintBy = new CCTintBy(); pTintBy->initWithDuration(duration, deltaRed, deltaGreen, deltaBlue); pTintBy->autorelease(); //返回创建的变色动画。 return pTintBy; } //初始化函数。 bool CCTintBy::initWithDuration(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue) { //调用基类的初始化函数。 if (CCActionInterval::initWithDuration(duration)) { //将要变化的色彩的三分量保存。 m_deltaR = deltaRed; m_deltaG = deltaGreen; m_deltaB = deltaBlue; //返回成功。 return true; } //如果初始化失败返回false。 return false; } //创建当前动画的拷贝。 CCObject* CCTintBy::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCTintBy* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCTintBy*)(pZone->m_pCopyObject); } else { pCopy = new CCTintBy(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithDuration(m_fDuration, (GLubyte)m_deltaR, (GLubyte)m_deltaG, (GLubyte)m_deltaB); CC_SAFE_DELETE(pNewZone); return pCopy; } //设置演员当前动画的演员。 void CCTintBy::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCActionInterval::startWithTarget(pTarget); //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(pTarget); if (pRGBAProtocol) { //将演员的色彩值取出保存为起始色彩值。 ccColor3B color = pRGBAProtocol->getColor(); m_fromR = color.r; m_fromG = color.g; m_fromB = color.b; } } //更新当前动画播放。 void CCTintBy::update(float time) { //将演员由精灵类降为色彩控制基类CCRGBAProtocol . CCRGBAProtocol *pRGBAProtocol = dynamic_cast<CCRGBAProtocol*>(m_pTarget); if (pRGBAProtocol) { //利用时间对色彩变化进行插值,计算出演员的当前色彩值。 pRGBAProtocol->setColor(ccc3((GLubyte)(m_fromR + m_deltaR * time), (GLubyte)(m_fromG + m_deltaG * time), (GLubyte)(m_fromB + m_deltaB * time))); } } //创建一个反向播放的变色动画。 CCActionInterval* CCTintBy::reverse(void) { return CCTintBy::create(m_fDuration, -m_deltaR, -m_deltaG, -m_deltaB); }
//暂停动画:这个动画就是代表在时长内保持没有任何变化效果。 class CC_DLL CCDelayTime : public CCActionInterval { public: //重载基类相应函数。 virtual void update(float time); virtual CCActionInterval* reverse(void); virtual CCObject* copyWithZone(CCZone* pZone); public: //创建一个暂停动画。参数为动画的时间长度。内部调用create实现。 CC_DEPRECATED_ATTRIBUTE static CCDelayTime* actionWithDuration(float d); //创建一个暂停动画。 static CCDelayTime* create(float d); }; 具体实现: //创建一个暂停动画。参数为动画的时间长度。 CCDelayTime* CCDelayTime::actionWithDuration(float d) { return CCDelayTime::create(d); } //创建一个暂停动画。 CCDelayTime* CCDelayTime::create(float d) { CCDelayTime* pAction = new CCDelayTime(); pAction->initWithDuration(d); pAction->autorelease(); return pAction; } //创建一个暂停动画的拷贝。 CCObject* CCDelayTime::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCDelayTime* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCDelayTime*)(pZone->m_pCopyObject); } else { pCopy = new CCDelayTime(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); CC_SAFE_DELETE(pNewZone); return pCopy; } //更新当前暂停动画。 void CCDelayTime::update(float time) { //就是啥也不做。 CC_UNUSED_PARAM(time); return; } //创建一个反向播放的动画,其实就是自身,有毛意义反向~? CCActionInterval* CCDelayTime::reverse(void) { return CCDelayTime::create(m_fDuration); }
//倒带动画:控制一个动画进行反向播放 class CC_DLL CCReverseTime : public CCActionInterval { public: //析构与构造 ~CCReverseTime(void); CCReverseTime(); //初始化动画,参数为控制的时间动画。 bool initWithAction(CCFiniteTimeAction *pAction); //重载基类相应函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void stop(void); virtual void update(float time); virtual CCActionInterval* reverse(void); public: //创建一个倒带动画,内部调用create实现。参数为控制的时间动画。 CC_DEPRECATED_ATTRIBUTE static CCReverseTime* actionWithAction(CCFiniteTimeAction *pAction); //创建一个倒带动画。 static CCReverseTime* create(CCFiniteTimeAction *pAction); protected: CCFiniteTimeAction *m_pOther; }; 具体实现: ////创建一个动画,内部调用create实现。 CCReverseTime* CCReverseTime::actionWithAction(CCFiniteTimeAction *pAction) { return CCReverseTime::create(pAction); } //创建一个动画。 CCReverseTime* CCReverseTime::create(CCFiniteTimeAction *pAction) { //亲, 创建,初始化,交由内存管理器进行释放处理,包邮返回一条龙哦~ CCReverseTime *pReverseTime = new CCReverseTime(); pReverseTime->initWithAction(pAction); pReverseTime->autorelease(); return pReverseTime; } //初始化 bool CCReverseTime::initWithAction(CCFiniteTimeAction *pAction) { //有效性判断 CCAssert(pAction != NULL, ""); CCAssert(pAction != m_pOther, ""); //先调用基类初始化处理。 if (CCActionInterval::initWithDuration(pAction->getDuration())) { // Don't leak if action is reused CC_SAFE_RELEASE(m_pOther); //保存要控制的动画。 m_pOther = pAction; //占用它,就让它的引用计数器加一! pAction->retain(); //返回成功。 return true; } //如果初始化失败,返回false。 return false; } //创建拷贝。 CCObject* CCReverseTime::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCReverseTime* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCReverseTime*)(pZone->m_pCopyObject); } else { pCopy = new CCReverseTime(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithAction((CCFiniteTimeAction*)(m_pOther->copy()->autorelease())); CC_SAFE_DELETE(pNewZone); return pCopy; } //构造。 CCReverseTime::CCReverseTime() : m_pOther(NULL) { } //析构。 CCReverseTime::~CCReverseTime(void) { //占用它,就要释放它!当然,到不到释放时候由内存管理器通过引用计数来判断和处理。 CC_SAFE_RELEASE(m_pOther); } //设置演示当前动画的演员。 void CCReverseTime::startWithTarget(CCNode *pTarget) { //调用基类的相应函数。 CCActionInterval::startWithTarget(pTarget); //设置演员演示当前控制的动画。 m_pOther->startWithTarget(pTarget); } //停止动画。 void CCReverseTime::stop(void) { //控制动画停止。 m_pOther->stop(); //当前动画停止。 CCActionInterval::stop(); } //更新动画的播放。 void CCReverseTime::update(float time) { //如果控制的动画有效,则计算倒带进度播放动画。 if (m_pOther) { m_pOther->update(1 - time); } } //反向动画的反向动画。真蛋疼啊~ CCActionInterval* CCReverseTime::reverse(void) { return (CCActionInterval*)(m_pOther->copy()->autorelease()); }
class CCTexture2D; //序列帧动画 class CC_DLL CCAnimate : public CCActionInterval { public: //构造与析构。 CCAnimate(); ~CCAnimate(); //初始化动画。 bool initWithAnimation(CCAnimation *pAnimation); //重载基类的相应函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void stop(void); virtual void update(float t); virtual CCActionInterval* reverse(void); public: //创建一个序列帧动画,内部调用create实现。参数为动画信息结构指针。 CC_DEPRECATED_ATTRIBUTE static CCAnimate* actionWithAnimation(CCAnimation *pAnimation); //创建一个序列帧动画。 static CCAnimate* create(CCAnimation *pAnimation); //定义一个动画信息结构指针变量以及存取此变量的函数。 CC_SYNTHESIZE_RETAIN(CCAnimation*, m_pAnimation, Animation) protected: //保存每一帧要切换时的进度的容器指针,由动画信息结构指针取得。 std::vector<float>* m_pSplitTimes; //当前要播放的下一帧序号。 int m_nNextFrame; //各帧中保存的精灵信息。 CCSpriteFrame* m_pOrigFrame; //循环次数。 unsigned int m_uExecutedLoops; }; 具体实现: //创建一个序列帧动画,内部调用create实现。参数为动画信息结构。 CCAnimate* CCAnimate::actionWithAnimation(CCAnimation *pAnimation) { return CCAnimate::create(pAnimation); } //创建一个序列帧动画。 CCAnimate* CCAnimate::create(CCAnimation *pAnimation) { //创建,初始化,交由内存管理器,包邮~ CCAnimate *pAnimate = new CCAnimate(); pAnimate->initWithAnimation(pAnimation); pAnimate->autorelease(); //返回创建的实例对象。 return pAnimate; } //初始化序列动画。 bool CCAnimate::initWithAnimation(CCAnimation *pAnimation) { //有效性判断。 CCAssert( pAnimation!=NULL, "Animate: argument Animation must be non-NULL"); //取得序列的时长。 float singleDuration = pAnimation->getDuration(); //乘以循环次数做为当前动画总时长来进行初始化。 if ( CCActionInterval::initWithDuration(singleDuration * pAnimation->getLoops() ) ) { //初始化变量。 m_nNextFrame = 0; //将参数pAnimation保存到动画信息结构指针变量m_pAnimation. setAnimation(pAnimation); m_pOrigFrame = NULL; m_uExecutedLoops = 0; //设置容器大小。这里我认为应该写成resize而不是reserver!!! m_pSplitTimes->reserve(pAnimation->getFrames()->count()); //初始化变量。 float accumUnitsOfTime = 0; //序列播放一轮的时间/ float newUnitOfTimeValue = singleDuration / pAnimation->getTotalDelayUnits(); //取得序列信息中的帧信息数组。 CCArray* pFrames = pAnimation->getFrames(); // CCARRAY_VERIFY_TYPE(pFrames, CCAnimationFrame*); //定义临时变量pObj来遍历取得帧信息中的单帧信息。 CCObject* pObj = NULL; CCARRAY_FOREACH(pFrames, pObj) { //取得单帧信息。 CCAnimationFrame* frame = (CCAnimationFrame*)pObj; //计算播放当前单帧时的进度。 float value = (accumUnitsOfTime * newUnitOfTimeValue) / singleDuration; accumUnitsOfTime += frame->getDelayUnits(); //将当前单帧的进度存入容器。 m_pSplitTimes->push_back(value); } //返回成功。 return true; } //如果初始化失败,返回false。 return false; } //创建拷贝。 CCObject* CCAnimate::copyWithZone(CCZone *pZone) { CCZone* pNewZone = NULL; CCAnimate* pCopy = NULL; if(pZone && pZone->m_pCopyObject) { //in case of being called at sub class pCopy = (CCAnimate*)(pZone->m_pCopyObject); } else { pCopy = new CCAnimate(); pZone = pNewZone = new CCZone(pCopy); } CCActionInterval::copyWithZone(pZone); pCopy->initWithAnimation((CCAnimation*)m_pAnimation->copy()->autorelease()); CC_SAFE_DELETE(pNewZone); return pCopy; } //构造,注意在这里申请了一个vector<float>容器,并将成员指针变量m_pSplitTimes指向它的。 CCAnimate::CCAnimate() : m_pAnimation(NULL) , m_pSplitTimes(new std::vector<float>) , m_nNextFrame(0) , m_pOrigFrame(NULL) , m_uExecutedLoops(0) { } //析构。 CCAnimate::~CCAnimate() { CC_SAFE_RELEASE(m_pAnimation); CC_SAFE_RELEASE(m_pOrigFrame); CC_SAFE_DELETE(m_pSplitTimes); } //设置演示当前序列动画的演员。 void CCAnimate::startWithTarget(CCNode *pTarget) { //先调用基类的相应函数。 CCActionInterval::startWithTarget(pTarget); //序列帧动画必须是个精灵。 CCSprite *pSprite = (CCSprite*)(pTarget); //释放上一个 CC_SAFE_RELEASE(m_pOrigFrame); //如果有帧数据。 if (m_pAnimation->getRestoreOriginalFrame()) { //取得精灵的帧信息。 m_pOrigFrame = pSprite->displayFrame(); //对帧信息占用,引用数加一。 m_pOrigFrame->retain(); } m_nNextFrame = 0; m_uExecutedLoops = 0; } //停止当前动画。 void CCAnimate::stop(void) { //如果动画有帧数据且有演员。 if (m_pAnimation->getRestoreOriginalFrame() && m_pTarget) { //设置演员显示当前帧。 ((CCSprite*)(m_pTarget))->setDisplayFrame(m_pOrigFrame); } //停止当前动画。 CCActionInterval::stop(); } //更新动画。 void CCAnimate::update(float t) { // 如果整个动画未播放,先计算循环是否够次数。 if( t < 1.0f ) { //计算出当前进度播放的循环数。 t *= m_pAnimation->getLoops(); // 通过先取整再判断是否大于当前的已经循环次数来判断是否是新的循环,如果是将下一帧置零,已经循环的次数加1 。 unsigned int loopNumber = (unsigned int)t; if( loopNumber > m_uExecutedLoops ) { m_nNextFrame = 0; m_uExecutedLoops++; } // 对t进行浮点取模值,将其限制在0~1之间,这样等于又转换成为了当前动画播放的进度值。 t = fmodf(t, 1.0f); } //取得动画的帧信息容器和帧数。 CCArray* frames = m_pAnimation->getFrames(); unsigned int numberOfFrames = frames->count(); //精灵图片信息。 CCSpriteFrame *frameToDisplay = NULL; //找出要播放的帧图片设置为精灵要显示的图片,这里用了一个for循环。从下一帧开始到结束帧进行遍历,判断是否到了这一帧。 for( unsigned int i=m_nNextFrame; i < numberOfFrames; i++ ) { //取出循环中的当前帧的播出时间进度。 float splitTime = m_pSplitTimes->at(i); //如果这一帧的进度小于当前动画的播放进度,即代表进入了这一帧。 if( splitTime <= t ) { //取得对应的动画帧信息。 CCAnimationFrame* frame = (CCAnimationFrame*)frames->objectAtIndex(i); //取得当前帧的精灵图片信息。 frameToDisplay = frame->getSpriteFrame(); //设置为精灵的当前显示图片。 ((CCSprite*)m_pTarget)->setDisplayFrame(frameToDisplay); //通过动画帧信息取得其字典信息。 CCDictionary* dict = frame->getUserInfo(); if( dict ) { //忽略了。 //TODO: [[NSNotificationCenter defaultCenter] postNotificationName:CCAnimationFrameDisplayedNotification object:target_ userInfo:dict]; } //帧数加一。 m_nNextFrame = i+1; break; } } } //创建一个反向播放的序列帧动画。 CCActionInterval* CCAnimate::reverse(void) { CCArray* pOldArray = m_pAnimation->getFrames(); CCArray* pNewArray = CCArray::createWithCapacity(pOldArray->count()); CCARRAY_VERIFY_TYPE(pOldArray, CCAnimationFrame*); if (pOldArray->count() > 0) { CCObject* pObj = NULL; CCARRAY_FOREACH_REVERSE(pOldArray, pObj) { CCAnimationFrame* pElement = (CCAnimationFrame*)pObj; if (! pElement) { break; } pNewArray->addObject((CCAnimationFrame*)(pElement->copy()->autorelease())); } } CCAnimation *newAnim = CCAnimation::create(pNewArray, m_pAnimation->getDelayPerUnit(), m_pAnimation->getLoops()); newAnim->setRestoreOriginalFrame(m_pAnimation->getRestoreOriginalFrame()); return create(newAnim); }
//控制动画:就是让目标演员演示一个目标动画。 class CC_DLL CCTargetedAction : public CCActionInterval { public: //构造与析构。 CCTargetedAction(); virtual ~CCTargetedAction(); //创建一个控制动画,内部调用create实现。参一为演示目标动画的演员,参二为目标动画。 CC_DEPRECATED_ATTRIBUTE static CCTargetedAction* actionWithTarget(CCNode* pTarget, CCFiniteTimeAction* pAction); //创建一个控制动画。 static CCTargetedAction* create(CCNode* pTarget, CCFiniteTimeAction* pAction); //初始化。 bool initWithTarget(CCNode* pTarget, CCFiniteTimeAction* pAction); //重载相应函数。 virtual CCObject* copyWithZone(CCZone* pZone); virtual void startWithTarget(CCNode *pTarget); virtual void stop(void); virtual void update(float time); //定义变量m_pForcedTarget存放初始化参数目标演员。 CC_SYNTHESIZE_RETAIN(CCNode*, m_pForcedTarget, ForcedTarget); private: //定义变量m_pAction存放初始化参数目标动画。 CCFiniteTimeAction* m_pAction; }; 具体实现: //构造函数。 CCTargetedAction::CCTargetedAction() : m_pForcedTarget(NULL) , m_pAction(NULL) { } //析构函数。 CCTargetedAction::~CCTargetedAction() { CC_SAFE_RELEASE(m_pForcedTarget); CC_SAFE_RELEASE(m_pAction); } //创建一个控制动画,内部调用create实现。参一为演示目标动画的演员,参二为目标动画。 CCTargetedAction* CCTargetedAction::actionWithTarget(CCNode* pTarget, CCFiniteTimeAction* pAction) { return CCTargetedAction::create(pTarget, pAction); } //创建一个控制动画。 CCTargetedAction* CCTargetedAction::create(CCNode* pTarget, CCFiniteTimeAction* pAction) { //又是一条龙。 CCTargetedAction* p = new CCTargetedAction(); p->initWithTarget(pTarget, pAction); p->autorelease(); return p; } //初始化 bool CCTargetedAction::initWithTarget(CCNode* pTarget, CCFiniteTimeAction* pAction) { //调用基类的初始化函数。 if(CCActionInterval::initWithDuration(pAction->getDuration())) { //干掉旧演员,推出新演员。 CC_SAFE_RETAIN(pTarget); m_pForcedTarget = pTarget; //干掉旧动画,演示新动画。 CC_SAFE_RETAIN(pAction); m_pAction = pAction; //初始化成功,返回true. return true; } //初始化失败返回false. return false; } //创建拷贝。 CCObject* CCTargetedAction::copyWithZone(CCZone* pZone) { CCZone* pNewZone = NULL; CCTargetedAction* pRet = NULL; if(pZone && pZone->m_pCopyObject) //in case of being called at sub class { pRet = (CCTargetedAction*)(pZone->m_pCopyObject); } else { pRet = new CCTargetedAction(); pZone = pNewZone = new CCZone(pRet); } CCActionInterval::copyWithZone(pZone); // win32 : use the m_pOther's copy object. pRet->initWithTarget(m_pTarget, (CCFiniteTimeAction*)m_pAction->copy()->autorelease()); CC_SAFE_DELETE(pNewZone); return pRet; } //设置演示当前动画的演员,话是这么说,但实际这个函数的功能只是在这个时候可以对目标动画进行相应的设置。 void CCTargetedAction::startWithTarget(CCNode *pTarget) { //调用基类相应函数。 CCActionInterval::startWithTarget(m_pForcedTarget); //这里使用目标演员来设置为演示目标动画的演。 m_pAction->startWithTarget(m_pForcedTarget); } //停止目标动画。 void CCTargetedAction::stop(void) { m_pAction->stop(); } //更新目标动画。 void CCTargetedAction::update(float time) { m_pAction->update(time); } NS_CC_END #endif //__ACTION_CCINTERVAL_ACTION_H__
这一斧子下去,真心痛啊!不过不要紧,还有一斧子,最后一斧子哦~.
最后,敬告转载文章不写出处的网站,请看在小生这么拼命写博为你们赚钱的份上,好歹写一下文章出处~