とあるプログラマの備忘録

都内某所に住むプログラマが自分用に備忘録を残すという趣旨のブログです。はてなダイアリーから移動しました!

【続】cocos2d-x onTouchMoved内でのAction競合について

さて前回投げた記事の全く違う所で実は複数の方からコメントを頂きました
折角コメントを頂いたのでいくつかの方法を試してみようと思います。

実際こういうモーション処理の構想ってアプリの特性に合わせて作っていくものだと思うので
(同時タップがONかとか複数のオブジェクトのモーションが同時におきるのかとか..etc)
一概には言えませんが参考程度にソースをあげてみたいと思います。

では早速

こんな会話がありました

フラグでもいいですけど、actionにタグをつけておいて、sprite本体にaction実行中か直接確認す る方法がありますよ。

action1=cc.MoveTo.create (0.5 ,cc.p(100,100));
action1.setTag(1);
sp1.runAction(action1);

act=sp1.getActionByTag(1);
if (!act1) { cc.log("実行完了"); }

jsですいません

サンプルソースまで書いていただき誠にありがとうございますm(__)m これの利点は複数のアクションにタグをつけて個別に問い合わせられる事でしょうか。

タグつけないで直接spriteに実行中actionの数を聞くのがありました。
こちらは試してないですが。c++もほぼ同じでしょう

act_mgr= cc.Director.1().getActionManager();
act_count=act_mgr.getNumberOfRunningActionsInTarget(sprite1);

なるほど、なるほど、ActionManagerにターゲット指定してアクションの個数を数えられるんですね、早速ためしてみましょう!

//タッチ移動イベント
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
    //0,0のオブジェクトを召還
    auto obj = arrTotal[0][0];
    
    auto actionManager = Director::getInstance()->getActionManager();
    auto a_count = actionManager->getNumberOfRunningActionsInTarget(obj->sprite_block);
    
    is_lock = a_count ? true : false;
    
    //動かしてみる
    if ( !is_lock) {
        auto move = MoveTo::create(1.0f, Point(obj->getPositionX(), obj->getPositionY() - 10));
        obj->getBlock()->runAction(move);
    }

いいかんじです、このソースをみるとDirectorがNodeのアクションを管理しているようにみえますのでこれができるならonTouchMoved内でなくともフラグの管理が可能なはずです、
ただ件数を数えるにはtargetを指定してあげる必要があるので複数の同時にうごかすのであればまた工夫が必要そうです。

onToucheMove内部ではステータスの変更だけにし、scheduleUpdate() で有効にしたupdate処理でそれぞれのアクションを登録すべきかと。
イベント処理内でビューの動作変更などをやり始めると、あっという間に収集つかなくなりますよ。

確かに今はonTouchMoved内で1個の動作を行っているだけですが、 これからモーションを増やす度にここに書くと収集がつかなくなるというご指摘です
この問題はもう少し後に考える予定でしたが、構想段階でこれを考えていた方がのは間違いないでしょう
なのでサンプルでこんなものを書いてみました。

//ロック
void HelloWorld::onLock()
{
    is_lock = true;
}

//ロック解除
void HelloWorld::unLock()
{
    is_lock = false;
}


//タッチ移動イベント
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
    if(!is_lock) return;
    
    on_down_motion = true;
}

//update
void HelloWorld::update(float delta)
{
    if (is_lock) return;
    
    auto obj = arrTotal[0][0];
    auto onlock = CallFunc::create(this, callfunc_selector(HelloWorld::onLock));
    auto unlock = CallFunc::create(this, callfunc_selector(HelloWorld::unLock));
    
    if(on_down_motion){
        auto motion = MoveTo::create(1.0f, Point(obj->getBlock()->getPositionX(), obj->getBlock()->getPositionY() - 10));
        auto move = Sequence::create(onlock, motion, unlock, NULL);
        obj->sprite_block->runAction(move);
        on_down_motion = false;
    }
}

the・サンプルと言った感じですけど
onTouchMoved内は非常にすっきりしました

またis_lockとon_down_motion二つのフラグで管理しているのは
updateとonTouchMovedの呼ばれるタイミングが違う事によるものです。 またこれ以降ロックかけたくない処理があった場合も考えれば、処理をしないのか 割り込みOKなのかの考慮も入れておいた方がいいでしょう。

update内に書いたモーション処理は別個のメソッドに移したり、
モーションフラグを一括で初期化してくれるようにしたり
update内に書くとそれはそれで問題がありそうなので新しいスケジュールを作った方がいいとか
まだまだ問題点がありそうですがこの方法なら自分の理想に一歩近づけたかと思います。

コメント頂きました皆様ありがとうございました。