ページ 11

cocos2d-x 再帰呼び出しについて

Posted: 2014年6月09日(月) 19:00
by ponkikki
お世話になっております。
現在cocos2d-xを用いて、ゲームを制作しているのですが、
アニメーションを作ろうと、作成した関数内でCCSequenceクラスをインスタンス化しました。インスタンス化したものにデータをセットしていき、そのインスタンスは、また新しいCCsequenceクラスをインスタンス化してデータをセットするのに使うので、作成したインスタンスを同じ関数内に渡して、再帰的に呼び出しています。
そして、最終的に出来上がった、CCsequenceクラスのインスタンスをアニメーションしたいスプライトに適用させようとしました。
以下のようにコードを組みました。

コード:

//再帰関数
cocos2d::CCSequence* HelloWorld::sequencer(cocos2d::CCSequence *seq)
{
    
    if (count != moveArray->count()){
        CCSequence *seqN = CCSequence::create(seq,(CCTargetedAction*)moveArray->objectAtIndex(count),NULL);
        count++;
        //②
        sequenser(seqN); //①
    }
    
    return seq;
    
}

main(){

CCSequence *resultSeq = sequencer(seed);

Mysprite->runAction(resultSeq);

}
デバッカでseqNにちゃんとデータがセットされているか確かめたら、
seqN
→m_pActions
→→[0] = 0x14209850(CCSequence*)
→→[1] = 0x1420a8c0(CCTargetedAction*)

のように意図した通りにデータがセットされていました。
ですが、
上記コードの①のところで再帰呼び出しをした後、seqNのアドレスを受け取ったseqの中身を確認してみたところ
先ほどまで入っていたアドレス 0x14209850 と 0x1420a8c0が無くなっていました。その代わりに、全く知らないアドレスが入っていました。
なので、ちゃんとしたseqが生成されないまま、アニメーションしたいスプライトに適用させても上手く挙動しませんでした。
アドレスが消滅する①の直前の②の部分で
Mysprite->runAction(seqN)
のようにしてみたら、アニメーションがちゃんとされました。
なので、①の部分でおかしなことになってしまったことがわかりました。
何故このようなことが起きてしまったのでしょうか?
使用している言語はC++です。

Re: cocos2d-x 再帰呼び出しについて

Posted: 2014年6月09日(月) 19:27
by h2so5
これだけではちょっと分からないです。
そもそもこのようなCCSequenceの使い方が想定されているかが不明ですし、再帰を使う理由もよく分かりません。
あと、コードを見て疑問に思ったのはcountがどのタイミングでリセットされているのかという所です。

Re: cocos2d-x 再帰呼び出しについて

Posted: 2014年6月09日(月) 21:16
by ponkikki
ご回答ありがとうございます。
わかりにくくて申し訳ありません。
簡単に以下のようなことをシミュレートしたくて、コードを組みました。

コード:


   
    CCSprite *MySprite = CCSprite::create("sequence_0000.png");
    MySprite->setPosition(ccp(800,400));
    this->addChild(MySprite);
    
    CCAnimation *animation = CCAnimation::create();
    animation->setDelayPerUnit(0.1);
    animation->addSpriteFrameWithFileName("sequence_0001.png");
    animation->addSpriteFrameWithFileName("sequence_0002.png");
    animation->addSpriteFrameWithFileName("sequence_0003.png");
    animation->addSpriteFrameWithFileName("sequence_0004.png");
    animation->addSpriteFrameWithFileName("sequence_0005.png");
   
    CCAnimate *animate = CCAnimate::create(animation);
    
   
    
    
    CCSprite *MySprite2 = CCSprite::create("sequence_0000.png");
    MySprite2->setPosition(ccp(800,500));
    this->addChild(MySprite2);
    
    CCAnimation *animation2 = CCAnimation::create();
    animation2->setDelayPerUnit(0.1);
    animation2->addSpriteFrameWithFileName("sequence_0001.png");
    animation2->addSpriteFrameWithFileName("sequence_0002.png");
    animation2->addSpriteFrameWithFileName("sequence_0003.png");
    animation2->addSpriteFrameWithFileName("sequence_0004.png");
    animation2->addSpriteFrameWithFileName("sequence_0005.png");
    
    CCAnimate *animate2 = CCAnimate::create(animation2);
    
    
    
    CCSprite *MySprite3 = CCSprite::create("sequence_0000.png");
    MySprite3->setPosition(ccp(800,600));
    this->addChild(MySprite3);
    
    CCAnimation *animation3 = CCAnimation::create();
    animation3->setDelayPerUnit(0.1);
    animation3->addSpriteFrameWithFileName("sequence_0001.png");
    animation3->addSpriteFrameWithFileName("sequence_0002.png");
    animation3->addSpriteFrameWithFileName("sequence_0003.png");
    animation3->addSpriteFrameWithFileName("sequence_0004.png");
    animation3->addSpriteFrameWithFileName("sequence_0005.png");
    
    CCAnimate *animate3 = CCAnimate::create(animation3);
    
    //各スプライトに適用するアクションを格納しておく配列です。
    CCArray *array = CCArray::create();
    
    array->addObject(animate);
    array->addObject(animate2);
    array->addObject(animate3);


  
  
 //各スプライトにアクションを適用 
    CCTargetedAction *tMove0 = CCTargetedAction::create(MySprite, (CCAnimate*)array->objectAtIndex(0));
    
    CCTargetedAction *tMove1 = CCTargetedAction::create(MySprite2, (CCAnimate*)array->objectAtIndex(1));
    
    CCTargetedAction *tMove2 = CCTargetedAction::create(MySprite3, (CCAnimate*)array->objectAtIndex(2));
    
    //各スプライトのアニメーションの順番を決める
    CCSequence *seq = CCSequence::create(tMove0,NULL);
    CCSequence *seq2 = CCSequence::create(seq,tMove1,NULL);
    CCSequence *seq3 = CCSequence::create(seq2,tMove2,NULL);
    
    MySprite->runAction(seq3);

このコードでは、まず3つのスプライトそれぞれに適用するアクションを用意します。(animate,animate2,animate3)
次に、それぞれのスプライトに用意したアクションを適用していきます(tMove0,tMove1,tMove2)
そして、CCSequenceでアクションの順番を決めます。
このコードではちゃんと3つのスプライトが順番にアニメーションされました。
先ほどのコードに書いてあったmoveArrayには、今書いたコードのtMoveが適用したいスプライト分大量に格納されていて(今のコードだと3つ)、さらにスプライトの数もゲームを進行している中で変わってくるので、CCSequenceに渡す引数の数が可変的に変わっていきます。
(あるときはCCSequence *seq = CCSequence(tMove0,tMove1,tMove2,tMove3,tMove4,NULL)だっだり、また或る時はCCSequence *seq = CCSequence(tMove0,tMove1,tMove2,NULL)だったり)
なので、先ほどのコードのような感じにしてみました。
countは関数を抜けた後に初期化しています。

Re: cocos2d-x 再帰呼び出しについて

Posted: 2014年6月09日(月) 21:34
by h2so5
CCSequence::createにCCArrayを渡すことができるので、数を可変にしたいのであればCCArrayを使ったほうがいいと思います。
http://www.cocos2d-x.org/reference/nati ... 83a7b1d3eb
http://www.cocos2d-x.org/wiki/CCArray

Re: cocos2d-x 再帰呼び出しについて

Posted: 2014年6月09日(月) 22:50
by ponkikki
CCArrayで単純に渡せたのですね。
なんとか自分の意図した通り動きました。
ありがとうございました。