cocos2dx里面有很多场景切换动画,使用起来也很简单,最简单的代码如下:
CCScene* newScene = new TransitionsTestScene(); newScene = CCTransitionProgressRadialCW::create(timeNeed, newScene); CCDirector::sharedDirector()->replaceScene(newScene);
CONTENTS
场景切换动画代码:
首先看下场景切换动画的继承关系:
CCTransition.h: class CC_DLL CCTransitionScene : public CCScene {。。。。。} class CC_DLL CCTransitionSceneOriented : public CCTransitionScene {。。。。。} class CC_DLL CCTransitionRotoZoom : public CCTransitionScene {。。。。。} class CC_DLL CCTransitionJumpZoom : public CCTransitionScene {。。。。。} 。。。。
可以看出,cocos2dx内部的场景切换动画继承自CCTransitionScene这个类,而CCTransitionScene这个类继承自CCScene,因此也是个场景类。
参考之前的【 笔记 】可以知道,CCTransitionScene在场景切换动画中担当了桥梁和动画播放的功能。
下面仔细分析下CCTransitionScene类的部分代码:
。。。。。 。。。。。 //==>>create函数,内部调用了initWithDuration, //==>>传入参数scene是新的场景的实例。 CCTransitionScene * CCTransitionScene::create(float t, CCScene *scene) { CCTransitionScene * pScene = new CCTransitionScene(); if(pScene && pScene->initWithDuration(t,scene)) 。。。。。 } bool CCTransitionScene::initWithDuration(float t, CCScene *scene) { CCAssert( scene != NULL, "Argument scene must be non-nil"); if (CCScene::init()) { m_fDuration = t; // retain m_pInScene = scene; m_pInScene->retain(); m_pOutScene = CCDirector::sharedDirector()->getRunningScene(); if (m_pOutScene == NULL) { m_pOutScene = CCScene::create(); m_pOutScene->init(); } m_pOutScene->retain(); //==>>通过上述代码我们可以知道: //==>>m_pInScene:是新的场景的实例 //==>>m_pOutScene:是当前的场景的实例 CCAssert( m_pInScene != m_pOutScene, "Incoming scene must be different from the outgoing scene" ); //==>>注意这里调用了函数sceneOrder,该函数是虚函数,可以被子类重写。 //==>>该函数的作用是设置当场景切换时新/旧场景哪个在上面。 sceneOrder(); 。。。。。 } //==>>默认的设置为场景切换时,旧的场景绘制在上面,新的场景绘制在下面。 void CCTransitionScene::sceneOrder() { m_bIsInSceneOnTop = true; } void CCTransitionScene::draw() { CCScene::draw(); //==>>根据m_bIsInSceneOnTop的值来绘制新/旧场景。 if( m_bIsInSceneOnTop ) { m_pOutScene->visit(); m_pInScene->visit(); } else { m_pInScene->visit(); m_pOutScene->visit(); } } //==>>场景切换动画完成之后,需要调用finish方法。 //==>>该方法主要供继承类使用 void CCTransitionScene::finish() { // clean up m_pInScene->setVisible(true); m_pInScene->setPosition(ccp(0,0)); m_pInScene->setScale(1.0f); m_pInScene->setRotation(0.0f); m_pInScene->getCamera()->restore(); m_pOutScene->setVisible(false); m_pOutScene->setPosition(ccp(0,0)); m_pOutScene->setScale(1.0f); m_pOutScene->setRotation(0.0f); m_pOutScene->getCamera()->restore(); //[self schedule:@selector(setNewScene:) interval:0]; this->schedule(schedule_selector(CCTransitionScene::setNewScene), 0); } //==>>由finish方法调用,主要用来完成最后的清理工作。 void CCTransitionScene::setNewScene(float dt) { CC_UNUSED_PARAM(dt); this->unschedule(schedule_selector(CCTransitionScene::setNewScene)); // Before replacing, save the "send cleanup to scene" CCDirector *director = CCDirector::sharedDirector(); m_bIsSendCleanupToScene = director->isSendCleanupToScene(); director->replaceScene(m_pInScene); // issue #267 m_pOutScene->setVisible(true); } //==>>该方法主要供继承类使用 void CCTransitionScene::hideOutShowIn() { m_pInScene->setVisible(true); m_pOutScene->setVisible(false); } //==>>重写了onEnter函数,主要是为了保证onEnterXXX,onExitXXX调用流程的正确 // custom onEnter void CCTransitionScene::onEnter() { CCScene::onEnter(); // disable events while transitions CCDirector::sharedDirector()->getTouchDispatcher()->setDispatchEvents(false); // outScene should not receive the onEnter callback // only the onExitTransitionDidStart m_pOutScene->onExitTransitionDidStart(); m_pInScene->onEnter(); } // custom onExit void CCTransitionScene::onExit() { CCScene::onExit(); // enable events while transitions CCDirector::sharedDirector()->getTouchDispatcher()->setDispatchEvents(true); m_pOutScene->onExit(); // m_pInScene should not receive the onEnter callback // only the onEnterTransitionDidFinish m_pInScene->onEnterTransitionDidFinish(); } // custom cleanup void CCTransitionScene::cleanup() { CCScene::cleanup(); if( m_bIsSendCleanupToScene ) m_pOutScene->cleanup(); }
由于CCTransitionScene是个基类,真正的场景动画实现都是继承类实现的,这里分析几个场景切换动画的实现:
CCTransitionJumpZoom:
CCTransitionJumpZoom算是一个比较简单的动画实现,直接搞了一大堆动画:
CCTransitionJumpZoom* CCTransitionJumpZoom::create(float t, CCScene* scene) { 。。。。。 } //==>>重写了onEnter函数,在里面初始化动画效果。 void CCTransitionJumpZoom::onEnter() { //==>>先调用了父类的函数,保证流程正确。 CCTransitionScene::onEnter(); //==>>构造一大堆动画 CCSize s = CCDirector::sharedDirector()->getWinSize(); m_pInScene->setScale(0.5f); m_pInScene->setPosition(ccp(s.width, 0)); m_pInScene->setAnchorPoint(ccp(0.5f, 0.5f)); m_pOutScene->setAnchorPoint(ccp(0.5f, 0.5f)); CCActionInterval *jump = CCJumpBy::create(m_fDuration/4, ccp(-s.width,0), s.width/4, 2); CCActionInterval *scaleIn = CCScaleTo::create(m_fDuration/4, 1.0f); CCActionInterval *scaleOut = CCScaleTo::create(m_fDuration/4, 0.5f); CCActionInterval *jumpZoomOut = (CCActionInterval*)(CCSequence::create(scaleOut, jump, NULL)); CCActionInterval *jumpZoomIn = (CCActionInterval*)(CCSequence::create(jump, scaleIn, NULL)); CCActionInterval *delay = CCDelayTime::create(m_fDuration/2); //==>>让两个场景分别执行不同的动画,达成弹跳的效果 m_pOutScene->runAction(jumpZoomOut); m_pInScene->runAction ( CCSequence::create ( delay, jumpZoomIn, //==>>这里可以看到,动画中的最后执行了父类的finish方法。 CCCallFunc::create(this, callfunc_selector(CCTransitionScene::finish)), NULL ) ); }
CCTransitionProgress:
CCTransitionProgress是一系列动画的父类,但是它也是CCTransitionScene的子类,它主要是实现一系列的进度条形式的动画。这里笔记下代码,看下它的实现方式:
class CC_DLL CCTransitionProgress : public CCTransitionScene 。。。。。 // CCTransitionProgress void CCTransitionProgress::onEnter() { CCTransitionScene::onEnter(); //==>>初始化了几个变量,子类可以重写该方法 setupTransition(); // create a transparent color layer // in which we are going to add our rendertextures CCSize size = CCDirector::sharedDirector()->getWinSize(); // create the second render texture for outScene CCRenderTexture *texture = CCRenderTexture::create((int)size.width, (int)size.height); texture->getSprite()->setAnchorPoint(ccp(0.5f,0.5f)); texture->setPosition(ccp(size.width/2, size.height/2)); texture->setAnchorPoint(ccp(0.5f,0.5f)); // render outScene to its texturebuffer texture->clear(0, 0, 0, 1); texture->begin(); m_pSceneToBeModified->visit(); texture->end(); //==>>上面的代码是进度条动画的核心。通过上面的代码,我们可以知道进度条动画的实现的方式为: //==>>首先新建一个CCRenderTexture的实例,将其大小覆盖全屏,然后将m_pSceneToBeModified在CCRenderTexture上重新绘制一遍, //==>>这样就得到了m_pSceneToBeModified的静态图片,通过将CCProgressTimer动画和静态图片相结合的方式,我们就可以看到一个 //==>>进度条的场景切换动画了,实际上场景的静态截图随着进度条不断变化实现的。 // Since we've passed the outScene to the texture we don't need it. if (m_pSceneToBeModified == m_pOutScene) { hideOutShowIn(); } //==>>子类会重写该方法,以便根据不同的进度条样式生成不同的进度条动画 // We need the texture in RenderTexture. CCProgressTimer *pNode = progressTimerNodeWithRenderTexture(texture); // create the blend action CCActionInterval* layerAction = (CCActionInterval*)CCSequence::create( //==>>播放进度条动画 CCProgressFromTo::create(m_fDuration, m_fFrom, m_fTo), //==>>播放到最后调用父类的finish方法,完成场景切换 CCCallFunc::create(this, callfunc_selector(CCTransitionProgress::finish)), NULL); // run the blend action pNode->runAction(layerAction); // add the layer (which contains our two rendertextures) to the scene addChild(pNode, 2, kCCSceneRadial); } 。。。。。
在学习场景切换动画代码中,作者感觉这部分代码的实现比较怪异,每个新的场景动画都要复写父类的onEnter方法,而且要在复写的函数中调用父类的onEnter方法。作者的建议是CCTransitionScene类可以声明一个虚函数func专门供子类复写以实现不同的动画效果,CCTransitionScene可以在onEnter函数的最后调用func,这样子类就不需要复写onEnter方法,只需要复写func方法就可以了。一点点个人看法 呵呵~~
自定义的场景切换动画:
在特定的场景下我们可能想实现一些自定义的场景切换动画,来达到比较好的效果,这里作者笔记下一种实现方式:
首先看下cocos2dx的内部的场景切换动画,看下有没有相似的。比如作者这里想找一个类似于进度条的动画,但是进图条的样式作者想自定义,那么我们就可以先看下cocos2dx自带的进度条切换动画是如何实现的,然后我们就可以自己写一个类,继承CCTransitionScene来实现。代码如下:
头文件:
/************************************************************************/ /* by cstriker1407 */ /* http://116.62.110.235/blog */ /************************************************************************/ #ifndef _CUSTOMTRANSPROGRESSINOUT_H_ #define _CUSTOMTRANSPROGRESSINOUT_H_ #include "cocos2d.h" NS_CC_BEGIN class CustomTransProgressInOut : public CCTransitionScene { public: //==>>t:切换用时间 //==>>scene:新的场景 //==>>pStencilFileName:自定义的图片 //==>>direction:true->从里向外放大, false->从外向里缩小 static CustomTransProgressInOut* create(float t, CCScene* scene, const char *pStencilFileName, bool direction); virtual void sceneOrder(); virtual void onEnter(); virtual void onExit(); protected: CCSprite *m_pStencil; bool m_bDirection; }; NS_CC_END #endif /* _CUSTOMTRANSPROGRESSINOUT_H_ */
cpp文件:
#include "CustomTransProgressInOut.h" NS_CC_BEGIN CustomTransProgressInOut* CustomTransProgressInOut::create( float t, CCScene* scene, const char *pStencilFileName, bool direction) { CustomTransProgressInOut* pScene = new CustomTransProgressInOut(); if(pScene && pScene->initWithDuration(t, scene)) { pScene->m_pStencil = CCSprite::create(pStencilFileName); pScene->m_bDirection = direction; //==>>由于direction的改变会使场景的绘制顺序发生改变,这里手动调用sceneOrder,保证正确性 pScene->sceneOrder(); pScene->autorelease(); return pScene; } CC_SAFE_DELETE(pScene); return NULL; } void CustomTransProgressInOut::sceneOrder() { //==>>从里向外,当前场景在上,从外向里,新的场景在上 m_bIsInSceneOnTop = !m_bDirection; } void CustomTransProgressInOut::onEnter() { CCTransitionScene::onEnter(); CCSize size = CCDirector::sharedDirector()->getWinSize(); //==>>和进度条类似,首先新建一个CCRenderTexture,以便生成静态贴图。 CCRenderTexture *texture = CCRenderTexture::create((int)size.width, (int)size.height); texture->getSprite()->setAnchorPoint(ccp(0.5f,0.5f)); texture->setPosition(ccp(size.width/2, size.height/2)); texture->setAnchorPoint(ccp(0.5f,0.5f)); texture->clear(0, 0, 0, 1); texture->begin(); //==>>根据不同的方向生成不同的贴图。 if (m_bDirection) { m_pInScene->visit(); }else { m_pOutScene->visit(); } texture->end(); CCClippingNode *clippingNode = CCClippingNode::create(); clippingNode->setStencil(m_pStencil); CCSprite *background = CCSprite::createWithTexture(texture->getSprite()->getTexture()); background->setFlipY(true); clippingNode->addChild(background); clippingNode->setAlphaThreshold(GLfloat(0.5f)); clippingNode->setAnchorPoint(ccp(0.5,0.5)); clippingNode->setPosition(ccp(size.width/2, size.height/2)); this->addChild(clippingNode, 2, 9999); //==>>计算最大和最小的缩放值 CCSize orgSize = m_pStencil->getContentSize(); CCSize maxSize = size; CCSize minSize = CCSizeMake(2,2); float maxScale = maxSize.height * 1.0f / orgSize.height * 2.0f; float minScale = minSize.height * 1.0f / orgSize.height; if (!m_bDirection) { float tmp = maxScale; maxScale = minScale; minScale = tmp; } m_pStencil->setScale(minScale); CCSequence* layerAction = CCSequence::create ( CCScaleTo::create(m_fDuration, maxScale), CCCallFunc::create(this, callfunc_selector(CustomTransProgressInOut::finish)), NULL ); m_pStencil->runAction(layerAction); } void CustomTransProgressInOut::onExit() { this->removeChildByTag(9999); CCTransitionScene::onExit(); } NS_CC_END
测试代码:
TransitionsTest.cpp: CCTransitionScene* createTransition(int nIndex, float t, CCScene* s) { return CustomTransProgressInOut::create(t,s, "stencil.png",true); }
效果截图:
stencil文件:
效果文件:
发表评论