art-ts-sprite

icon-shingyo
TapShingyoは多数のSpriteから正解のものをタップしていく単純なゲーム次世代お経アプリです。

icon-ths-app続編アプリです。

このアプリで実装したSprite関係の処理をまとめました。

親子関係

Cocos2d-xではNodeにaddChildするだけで簡単に親子関係を構築できます。

アプリのタップターゲットとなる札は、枠と文字の2つのSpriteを重ねて表示しています。
art-sprite-child2

auto pFrame    = Sprite::create("img/frame.png");
Size frameSize =  pFrame->getContentSize();
this->addChild(pFrame);

auto pChar  = CardSprite::create("img/char/E4BB8F.png");
pChar->setPosition(Vec2(
    frameSize.width  * 0.5,
    frameSize.height * 0.5
));
pFrame->addChild(pChar);

透過・透明度

アプリでは、ダミーやタップできない位置のターゲットを半透明にすることで判別が付くようにしました。

実装はSpriteのOpacityを変更するだけです。
Sprite.setOpacity()引数は0 – 255の範囲で、数値が大きいほど色が濃くなります。

// Spriteを半透明で表示
auto pSprite = Sprite::create("img/image.png");
p->setOpacity(128);

タップ判定

イベントリスナにタップイベントをdispachし、イベント発火を検知します。
アプリでは、タップされた場合に、どの札がタップされたかを判定して処理分けをしています。

GameScene.h

public:
    virtual bool onTouchBegan(cocos2d::Touch *pTouch, cocos2d::Event *pEvent);
    virtual void onTouchEnded(cocos2d::Touch *pTouch, cocos2d::Event *pEvent);

GameScene.cpp

bool GameScene::init()
{
    // -- 省略 --
    // イベントリスナの処理
    auto dispacher     = Director::getInstance()->getEventDispatcher();
    auto eventListener = EventListenerTouchOneByOne::create();

    eventListener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
    eventListener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);

    dispacher->addEventListenerWithSceneGraphPriority(eventListener, this);
    :
    :
}

void GameScene::onTouchEnded(Touch* pTouch, Event* pEvent)
{
    auto pSprite = this->getChildByTag(targetFrameTag);
    if (pSprite == NULL)
    {
        return;
    }

    // タッチされたポイントとSpriteが重なるかを判定
    Point touchPoint = Director::getInstance()->convertToGL(pTouch->getLocationInView());
    Rect  spriteRect = pSprite->getBoundingBox();
    if (spriteRect.containsPoint(touchPoint) == false)
    {
        return;
    }
    // 正答がタップされた場合の処理
    :
    :

子Spriteの操作

アプリでは正解をタップした場合にすべての札を手前に移動し、次の問題へと進みます。
子要素の操作はNodeに対してgetChildren()を行ってループにかければ良いです。
簡単ですね。

アプリの実装コードです。

Sprite* s;
auto rect = this->getChildByName("GameLayer");
for (auto target : rect->getChildren()) {
    s = (Sprite*)target;
    s->runAction(MoveBy::create(0.015, Point(0, -1 * m_cardSize.height)));
}

失敗談

「ターゲットを移動する」という実装で次のような躓きがありました。

つまずきポイント1、this->getChildren()

一番最初にthis->getChildren()に対して移動処理を行ったところ、ターゲットだけではなく、背景もデバッグ表示もすべて移動し最終的にすべて画面からフェードアウトしてしまいました。

これがその悲しいイメージです。
art-ts-miss-sprite

thisはつまりSceneですから、シーン上のすべての子要素に処理を行っていたのですね。

それはそうです。
cocosは悪くない。

つまずきポイント2、親要素を移動

上記の対応として、空のSpriteを作成しすべてのターゲットをこれの子要素としました。

この際、Spriteをそれぞれ移動するよりも、親要素をの1つを移動する方がコスト的にもコード的にも良いという判断で、親要素に対して移動処理を行いました。
そのコードがコチラです。

auto rect = this->getChildByName("GameLayer");
rect->runAction(MoveBy::create(0.1f, Point(0, -1 * cardSize.height)) );

この実装の場合、画面表示はOKでしたがタップ判定の位置が元の位置にとどまってしまうという期待しない挙動となってしまいました。
Spriteを拡張した実装のせいかもしれませんが、原因がよく分からなかったため、子要素をすべて移動するという乱暴な手段を取りました。


単純なアプリにも苦労やドラマがある、、、

ぜひTapHannyaShingyoをDLしてみてください。

icon-ths-app


2016年04月04日:アプリリンクを追加

スポンサーリンク
ad_336
ad_336
  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存