1. 程式人生 > >cocos2dx 3.2 中Sequence和Spawn無法執行RepeatForever動作的問題解決

cocos2dx 3.2 中Sequence和Spawn無法執行RepeatForever動作的問題解決

   (博主qq,1204802552,歡迎交流)

 有時候,我們想在Sequence或者Spawn中加入RepeatForever的動作,但在實際執行中,該迴圈動作並未得到執行,我們先來說下解決的方法。

   對於Spawn,很簡單,我們只需要把RepeatForever動作拿出來單獨執行即可

        Animation *animation = Animation::createWithSpriteFrames(aniframe,0.1f);
Animate *animate = Animate::create(animation);
aniSprite->runAction(RepeatForever::create((ActionInterval *)animate));
aniSprite->runAction(MoveTo::create(5,PointMake(visibleSize.width-40, visibleSize.height/2)));

   對於Sequence,則要使用回撥函式來執行RepeatForever動作

      CallFunc *callfunc = CallFunc::create(this,callfunc_selector(HelloWorld::animateCallback));

       Action * seq = Sequence::create(MoveTo::create(5,PointMake(visibleSize.width-40, visibleSize.height/2)),callfunc,NULL);

       aniSprite->runAction(seq);

下面分析下具體原因:Spawn和Sequence都採用遞迴的建立方式

   我們先來看看Spawn的建立原始碼:Spawn有不同形式的Create函式,但最終它們都會呼叫CreateWithTwoActions,所以我們直接看該函式

   Spawn* Spawn::createWithTwoActions(FiniteTimeAction *action1, FiniteTimeAction *action2)
{
    Spawn *spawn = new Spawn();
    spawn->initWithTwoActions(action1, action2);
    spawn->autorelease();


    return spawn;
}


bool Spawn::initWithTwoActions(FiniteTimeAction *action1, FiniteTimeAction *action2)
{
    CCASSERT(action1 != nullptr, "");
    CCASSERT(action2 != nullptr, "");


    bool ret = false;


    float d1 = action1->getDuration();
    float d2 = action2->getDuration();


    if (ActionInterval::initWithDuration(MAX(d1, d2)))
    {
        _one = action1;
        _two = action2;


        if (d1 > d2)
        {
            _two = Sequence::createWithTwoActions(action2, DelayTime::create(d1 - d2));
        } 
        else if (d1 < d2)
        {
            _one = Sequence::createWithTwoActions(action1, DelayTime::create(d2 - d1));
        }


        _one->retain();
        _two->retain();


        ret = true;
    }


    return ret;
}

從上面的程式碼中可以看到,Spawn為了同步不同的動作,會呼叫Sequence,即它最終執行的其實是由Sequence建立的動作,那麼下面我們就來看看Sequence的建立和執行

  bool Sequence::initWithTwoActions(FiniteTimeAction *actionOne, FiniteTimeAction *actionTwo)
{
    CCASSERT(actionOne != nullptr, "");
    CCASSERT(actionTwo != nullptr, "");


    float d = actionOne->getDuration() + actionTwo->getDuration();
    ActionInterval::initWithDuration(d);


    _actions[0] = actionOne;
    actionOne->retain();


    _actions[1] = actionTwo;
    actionTwo->retain();


    return true;
}

從上面這段程式碼可以看出,一個Sequence動作包含了兩個子動作,它的duration為兩個動作的總和。

void Sequence::startWithTarget(Node *target)
{
    ActionInterval::startWithTarget(target);
    _split = _actions[0]->getDuration() / _duration;
    _last = -1;
}

void Sequence::update(float t)
{
    int found = 0;
    float new_t = 0.0f;


    if( t < _split ) {
        // action[0]
        found = 0;
        if( _split != 0 )
            new_t = t / _split;
        else
            new_t = 1;


    } else {
        // action[1]
        found = 1;
        if ( _split == 1 )
            new_t = 1;
        else
            new_t = (t-_split) / (1 - _split );
    }


    if ( found==1 ) {


        if( _last == -1 ) {
            // action[0] was skipped, execute it.
            _actions[0]->startWithTarget(_target);
            _actions[0]->update(1.0f);
            _actions[0]->stop();
        }
        else if( _last == 0 )
        {
            // switching to action 1. stop action 0.
            _actions[0]->update(1.0f);
            _actions[0]->stop();
        }
    }

else if(found==0 && _last==1 )
{
// Reverse mode ?
// XXX: Bug. this case doesn't contemplate when _last==-1, found=0 and in "reverse mode"
// since it will require a hack to know if an action is on reverse mode or not.
// "step" should be overriden, and the "reverseMode" value propagated to inner Sequences.
_actions[1]->update(0);
_actions[1]->stop();
}
    // Last action found and it is done.
    if( found == _last && _actions[found]->isDone() )
    {
        return;
    }


    // Last action found and it is done
    if( found != _last )
    {
        _actions[found]->startWithTarget(_target);
    }


    _actions[found]->update(new_t);
    _last = found;
}

從上面兩段程式碼可以理解到:Sequence根據子動作的duration所佔比例以及執行時間來判斷哪個動作需要得到執行。對於普通的兩個動作,他們都可以得到執行。。。。。。。。但是,一個RepeatForever動作的duration為0,也就是說其所佔執行時間的比例為0,即是不會執行,這個可以從Update的前段程式碼可以看出,這個分析結果也符合我們看到的實際執行效果。

    但是,我們來看看紅色的那部分程式碼。假如我們把RepeatForever動作當做引數1傳入,當執行的時候,該動作被跳過了,於是紅色部分的程式碼得到執行,經過除錯也確實如此。

      我們看下注釋:// action[0] was skipped, execute it. ----------excute可以翻譯為執行,也可以翻譯為處死!!從程式碼看,action [ 0 ]在啟動之後馬上被結束,所以註釋中的excute極有可能是處死的意思。於是我嘗試改造程式碼,不呼叫stop,並向update傳入0.0f,我想要看到的效果是:RepeatForever動作得到執行,但是實際執行效果並沒有發生變化,令我百思不得其解,也許我瞭解的還不夠深入有什麼遺漏了,待我找個時間再研究研究,也希望各位能指點迷津

相關推薦

cocos2dx 3.2 SequenceSpawn無法執行RepeatForever動作的問題解決

   (博主qq,1204802552,歡迎交流)  有時候,我們想在Sequence或者Spawn中加入RepeatForever的動作,但在實際執行中,該迴圈動作並未得到執行,我們先來說下解決的方法。    對於Spawn,很簡單,我們只需要把RepeatForever

Android Studio 3.2KotlinDatabinding同時使用問題

今天使用Androidstudio 3.2 編譯以前的專案,結果總是遇到 無法找到 符號DataBindingComponent 的問題,經過一系列搜尋,測試.最終發現網上的方法根本無效。  果斷刪除如下 kapt ‘com.android.databinding:compil

hbase shelldisable drop無法執行

hbase shell balancer_switch drop disable 大數據 1 通過hbase的web監控頁面查詢工作狀態發現Regions in Transition區域有長時間未執行的任務,此時需要關閉hbase-master並重啟,再這個問題處理過程中我直接使用/etc

cocos2dx 3.x 生成的exe 模擬器無法執行(黑屏)

修改 SimulatorWin::run() 方法 如下: // load project config from command line args vector<string> args; for (int i = 0; i < __a

Cocos2dx 3.x Lua socket node.js 利用scoket互相通訊讀寫二進位制資料

第一部分,Lua socket如何讀寫二進位制資料。 cocos2dx 3.x 版本已經集成了lua socket所以可以直接使用無需自己整合。首先需要初始化lua socket 如下: socket = require("socket"); tcp

將舊專案基於cocos2dx 2.x的除錯繪製轉移到cocos2dx 3.x

1、首先必須修改原先在draw函式中繪製渲染的方式。3.x不是直接呼叫draw函式進行繪製的,而是通過renderCommand進行延時渲染。 老專案的渲染方式-draw函式中呼叫 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS

thinkphp 3.2依靠關聯模型來關聯三個表

需要 用戶 9.png mod 做到 圖模型 查詢 think image 這裏說的是用thinkphp3.2關聯模型關聯三個表 根據用戶表查詢出三個表的數據,需要兩個model來配合,第一個model是根據user表來查詢到班級的信息,然後第二個model是根絕banj

【Java】 劍指offer(53-3) 陣列數值下標相等的元素 《劍指Offer》Java實現合集 《劍指Offer》Java實現合集

  本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目   假設一個單調遞增的數組裡的每個元素都是整數並且是唯一的。請程式設計實現一個函式找出陣列中任意一個數值等於其下標的元素。例如,在陣列{-3, -1,1,

Spring原始碼構建專案,匯入eclipse後,缺失spring-cglib-repack-3.2.4.jarspring-objenesis-repack-2.4.jar的解決辦法

Spring原始碼在匯入ide之後,發現有spring-cglib-repack-3.2.8.jar和spring-objenesis-repack-2.6.jar不存在,在spring-framework目錄下執行gradle objenesisRepackJar和gradle cglibRe

cocos2dx[3.2](1) 淺析cocos2dx3.2引擎目錄

    3.x的引擎目錄與2.x的引擎目錄的差別是非常大的。3.x主要是將引擎的各個檔案按照用途進行了分類,使得引擎目錄結構更加清晰了。     從目錄中我們主要了解一下以下幾個檔案: 檔名 說明 build 官方編譯的專案解決方案。

3-3 Linux使用者使用者組進階命令

1、 鎖定使用者 命令:passwd -l   使用者名稱 2、解鎖賬戶 命令:passwd  -u  使用者名稱 3、無密碼登入 命令:passwd  -d   使用者名稱 4、主要組與附屬組 使用者可以同時屬於多個組   一個主要組  多個附屬組 5、將使

Spring原始碼匯入缺少spring-cglib-repack-3.2.9.jarspring-objensis-repack-3.0.1.jar

如下圖匯入使用gradle轉換後(gradle cleanidea eclipse)的Spring-beans工程報缺少spring-cglib-repack-3.2.9.jar和spring-objensis-repack-3.0.1.jar 解決方法,

python v3.3.2使用subprocess模組與其它程式進行管道通訊

下面是python指令碼sup.py: import subprocess p = subprocess.Popen("test.exe", stdin = subprocess.PIPE,stdout = subprocess.PIPE, stderr = subpr

Swift開發筆記3.Swiftsettergetter的基本用法

Swift中有儲存屬性和計算屬性兩種。其中在計算屬性中可以實現setter和getter方法,我們在playground中定義兩個結構體: struct Point { var x = 0.0, y = 0.0 } struct Size { var wi

(OK) Android Studio 3.2 建立新的AVD時,出現錯誤(No space left on device)—— on Fedora 27

To install:- Google APIs Intel x86 Atom System Image (system-images;android-27;google_apis;x86)Preparing "Install Google APIs Intel x86 At

cocos2dx[3.2](15)——顏色混合BlendFunc

原文:點此 1、概念     “混合”是指兩種顏色的疊加方式。在新圖片將要渲染畫到螢幕上的時候,將用在新圖片中的紅、綠、藍和透明度資訊,與螢幕上已經存在的圖片顏色資訊相融合。     說的具體一點,就是把某一畫素位置上原來的顏色和將要畫上去的顏色,通過某種方式混在

cocos2dx[3.2]小知識——Sprite轉換為Image

RenderTexture* pRender = RenderTexture::create(pNewSpr->getContentSize().width, pNewSpr->getContentSize().height, Texture2D::PixelFormat::RGBA8888);

cocos2d-x學習筆記(10)重複動作RepeatForeverRepeat 以及動作組合SequenceSpawn

Repeat和RepeatForever Sprite* sprite=Sprite::create("sprite.png"); sprite->setPosition(Point(visibleSize.width/2,visibleSize.height/

cocos2dx-3.2(35) ClippingNode 遮罩

我的生活,我的點點滴滴!! 可以根據一個模板切割圖片的節點--ClippingNode。這個類提供了一種不規則切割圖片的方式,在這種方式以前,我們可以使用紋理類 自帶的setTextureRect函式來切割矩形區域,而新特性中提供的ClippingNode最大的不同之處就

[C++ primer學習筆記] 3.2.1 定義初始化string物件

類可以定義多種初始化物件的方式:或初始值的數量不同; 或初始值的型別不同。初始化的不同方式:拷貝初始化:使用等號(=)初始化變數,實際上執行的是拷貝初始化,編譯器把等號右側的初始值拷貝到新建立的物件中去直接初始化:不使用等號,則執行的是直接初始化當初始值只有一個時,使用直接/