小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

【玩轉cocos2d-x之二十七】CCSequence不能執(zhí)行CCRepeatForever

 Kitsdk 2014-02-24

原創(chuàng)作品,轉載請標明http://blog.csdn.net/jackystudio/article/details/17019023


之前在遇到這么一個問題,在CCSequence中加入CCRepeatForever,發(fā)現(xiàn)其他動作執(zhí)行沒問題,就是CCRepeatForever無法執(zhí)行。代碼并沒有問題,很奇怪。


1.示例

  1. CCBlink* blink=CCBlink::create(0.5f,10);//創(chuàng)建閃爍動畫,duration=0.5s  
  2. CCAnimation* animation=CCAnimation::create();  
  3. animation->addSpriteFrameWithFileName("CloseNormal.png");  
  4. animation->addSpriteFrameWithFileName("CloseSelected.png");  
  5. animation->setDelayPerUnit(1.0f);//幀間間隔1s  
  6. CCAnimate* animate=CCAnimate::create(animation);//創(chuàng)建幀動畫  
  7. CCRepeatForever* repeat=CCRepeatForever::create(animate);  
  8. CCSequence* sequence=CCSequence::create(blink,repeat,NULL);//創(chuàng)建連續(xù)動畫  
  9. CCSprite* close=CCSprite::create("CloseNormal.png");  
  10. close->setPosition(ccp(240,160));  
  11. this->addChild(close);  
  12. close->runAction(sequence);//執(zhí)行連續(xù)動畫  
結果精靈閃爍10次以后,幀動畫不執(zhí)行了。


2.原因

先了解一下CCSequence的創(chuàng)建和執(zhí)行原理


2.1.CCSequence的創(chuàng)建

創(chuàng)建CCSequence調用

  1. //創(chuàng)建CCSequence  
  2. CCSequence* CCSequence::create(CCFiniteTimeAction *pAction1, ...)  
內部調用了createWithVariableList,從實現(xiàn)可以看出這是一個遞歸調用。

  1. //獲取動作列表,創(chuàng)建CCSequence  
  2. CCSequence* CCSequence::createWithVariableList(CCFiniteTimeAction *pAction1, va_list args)  
  3. {  
  4.     CCFiniteTimeAction *pNow;//當前動作  
  5.     CCFiniteTimeAction *pPrev = pAction1;//第一個動作  
  6.     bool bOneAction = true;//只有一個動作的標志位  
  7.   
  8.     while (pAction1)  
  9.     {  
  10.         pNow = va_arg(args, CCFiniteTimeAction*);//獲取當前動作  
  11.         if (pNow)//如果存在  
  12.         {  
  13.             pPrev = createWithTwoActions(pPrev, pNow);//用前兩個動作創(chuàng)建CCSequence并賦給第一個動作  
  14.             bOneAction = false;//置false  
  15.         }  
  16.         else//如果不存在  
  17.         {  
  18.             // If only one action is added to CCSequence, make up a CCSequence by adding a simplest finite time action.  
  19.             if (bOneAction)//如果只有一個動作  
  20.             {  
  21.                 pPrev = createWithTwoActions(pPrev, ExtraAction::create());  
  22.             }  
  23.             break;//跳出循環(huán)  
  24.         }  
  25.     }  
  26.       
  27.     return ((CCSequence*)pPrev);//返回第一個動作  
  28. }  
假如有3個動作要被串聯(lián),則先把第1個和第2個串聯(lián)一個CCSequence,再把這個CCSequence和第3個動作串聯(lián)成最終的CCSequence,然后返回。從CCSequence的成員變量可以看到:

  1. CCFiniteTimeAction *m_pActions[2];//表明只包含2個動作對象指針  
使用遞歸多少會降低程序的運行效率,但是卻可以換來代碼的簡潔性,同樣的CCSpawn也是這么實現(xiàn)的。

在createWithTwoActions中,調用了initWithTwoActions函數,實現(xiàn)了把兩個動作串成一個CCSequence,關鍵代碼如下:

  1. float d = pActionOne->getDuration() + pActionTwo->getDuration();//獲取兩個動作的duration  
  2. CCActionInterval::initWithDuration(d);//賦給新的CCSequence  
  3.   
  4. m_pActions[0] = pActionOne;//同時把兩個動作賦給m_pActions指針數組  
  5. pActionOne->retain();  
  6.   
  7. m_pActions[1] = pActionTwo;  
  8. pActionTwo->retain();  

2.2.duration

從示例可以看出,閃爍動畫blink的duration是0.5s,那CCRepeatForever呢?1s?當然不是,1s只是幀動畫animate的幀間間隔,每個幀動畫包含2幀,而CCRepeatForever的duration是0。因此,當示例中的閃爍動畫blink和重復動畫repeat串聯(lián)成CCSequence sequence的時候,sequence的duration就變成0.5+0=0.5s,這很重要。


2.3.m_split

CCSequence中有這么一個成員變量

  1. float m_split;//記錄了第一個動畫時長占總時長的比例,也就是2個動畫的時長分界  
當執(zhí)行runAction的時候,CCSequence會調用

  1. void CCSequence::startWithTarget(CCNode *pTarget)  
  2. {  
  3.     CCActionInterval::startWithTarget(pTarget);  
  4.     m_split = m_pActions[0]->getDuration() / m_fDuration;//獲取第一個動畫占總時長的比例  
  5.     m_last = -1;  
  6. }  
而這里由于blink占了0.5s,repeat占了0s,總時長0.5s,所以m_split是0.5/0.5=1。blink占滿了整個CCSequence。這時候再來看CCSequence::update(float dt)函數的執(zhí)行,就會恍然大悟了。

  1. int found = 0;//當前播放動作索引  
  2. float new_t = 0.0f;//新播放進度  
  3.   
  4. if( t < m_split ) {//播放進度<分界進度  
  5.     found = 0;//設置當前播放的是第一個動作  
  6.     if( m_split != 0 )//如果第一個動作時長占比!=0  
  7.         new_t = t / m_split;//計算出第一個動作新的播放進度  
  8.     else  
  9.         new_t = 1;//設置第一個已播放完畢  
  10.   
  11. else {//播放進度>=分界進度  
  12.     found = 1;//設置當前播放的是第二個動作  
  13.     if ( m_split == 1 )//如果第一個動作時長占比==1  
  14.         new_t = 1;//設置第二個動作已完成  
  15.     else  
  16.         new_t = (t-m_split) / (1 - m_split );//計算出第二個動作新的播放進度  
  17. }  


3.注意

(1)CCSpawn也會有這個問題,所以CCSpawn也無法執(zhí)行加入其中的CCRepeatForever動作。

(2)CCRepeatForever的反轉動作也是無效了,一個不會停止的動作從什么地方開始反轉?當然你可以先把動作反轉了再加入CCRepeatForever中,這是沒問題的。


4.解決方案

(1)對于同時動作,不使用CCSpawn,采用分別執(zhí)行

  1. close->runAction(blink);  
  2. close->runAction(repeat);  
(2)對于連續(xù)動作,不直接往CCSequence中加入CCRepeatForever,而是把CCRepeatForever放入瞬時動作CCCallFunc中,再把CCCallFunc加入CCSequence中執(zhí)行。

  1. close=CCSprite::create("CloseNormal.png");  
  2. CCBlink* blink=CCBlink::create(0.5f,10);  
  3. CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(TestScene::repeatFunc));//創(chuàng)建CCCallFunc對象  
  4. CCSequence* sequence=CCSequence::create(blink,callFunc,NULL);//把CCCallFunc對象加入CCSequence中  
  5. close->setPosition(ccp(240,160));  
  6. this->addChild(close);  
  7. close->runAction(sequence);  
  8.   
  9.   
  10. void TestScene::repeatFunc()  
  11. {  
  12.     CCAnimation* animation=CCAnimation::create();  
  13.     animation->addSpriteFrameWithFileName("CloseNormal.png");  
  14.     animation->addSpriteFrameWithFileName("CloseSelected.png");  
  15.     animation->setDelayPerUnit(1.0f);  
  16.     CCAnimate* animate=CCAnimate::create(animation);  
  17.     CCRepeatForever* repeat=CCRepeatForever::create(animate);  
  18.     close->runAction(repeat);  
  19. }  

(3)對于CCAnimation幀動畫,可以設置循環(huán)屬性,而不使用CCRepeatForever。

  1. animation->setLoops(-1);  


5.總結

雖然CCRepeatForever也同樣繼承于CCActionInterval,理論上是延時動作的子類,但是和一般的延時動作又有很大的不同,所以平時在使用的時候必須很小心,不能當成一般的CCActionInterval使用。而在cocos2d-x動作的分類上是不是應該把它從CCAction繼承出來會比較好一點?

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多