cocos2d-x v3.0でのタッチイベントの取り方

  • 37
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

cocos2d-xはv2.0とv3.0でタッチイベントなどのイベント取得方法が変更になっています。これを踏まえて、サンプルを作成しながら解説します。
詳細は本家の記事を参照して下さい。

元のテンプレートのソースから出発して、コメントを追加しました。

  • HelloWorldクラスMoleSceneクラスに変更します。(必ずしも必要ではありません。)
  • HelloWorldScene.hMoleScene.hに、HelloWorldScene.cppMoleScene.cppに変更します。(必ずしも必要ではありません。)
  • ソースの可読性を上げるため、using句を追加します。(必ずしも必要ではありません。)
using namespace cocos2d;
  • cocos2d-xのサンプルにあるアイコン( Icon.png)をResourcesに追加します。
  • スプラッシュスクリーンの代わりに、アイコンを読み込むようにします。
  • スプライトと画面サイズがクラス全体で必要になりますので、メンバー変数にします。
MoleScene.h
#ifndef __MOLE_SCENE_H__
#define __MOLE_SCENE_H__

#include <CCGeometry.h>
#include "cocos2d.h"

using namespace cocos2d;

class MoleScene : public cocos2d::Layer
{
private:
    // 画面サイズ
    Size visibleSize;

    // スプライト
    cocos2d::Sprite* sprite;

public:
    // C++にはIDがないので、クラスのインスタンスポインタを返すことを推奨する。
    static Scene* createScene();

    // initメソッドは、cocos2d-iphoneではIDを返すが、cocos2d-xではboolを返すという違いがある。
    virtual bool init();  
    // a selector callback
    // セレクタのコースバック
    void menuCloseCallback(cocos2d::Ref* pSender);

    // static create()関数のマニュアル実装
    CREATE_FUNC(MoleScene);

    // 次の位置を取得する。
    Point* getNextPosition();
};

#endif
// __MOLE_SCENE_H__
MoleScene.cpp
/*
 * Sample2: 簡単なもぐらたたき風サンプル。
 *
 * Copyright (C) Takao WADA.
 */
#include "MoleScene.h"

USING_NS_CC;

/**
 *  シーンを作成する。
 *
 *  @return シーン
 */
Scene* MoleScene::createScene()
{
    // 'scene' は autorelease オブジェクト
    auto scene = Scene::create();

    // 'layer' は autorelease オブジェクト
    auto layer = MoleScene::create();

    // レイヤーをシーンの子として追加する。
    scene->addChild(layer);

    // シーンを返す。
    return scene;
}

/**
 *  インスタンスを初期化する。
 *
 *  @return 成功したらtrue
 */
bool MoleScene::init()
{
    //////////////////////////////
    // 1. 親クラスを初期化する。
    if ( !Layer::init() )
    {
        return false;
    }

    // 画面サイズを取得する。
    visibleSize = Director::getInstance()->getVisibleSize();
    // 画面の原点を取得する。
    Point origin = Director::getInstance()->getVisibleOrigin();

    /////////////////////////////
    // 2. クリックすると終了する”X”画像付きのメニュー項目を追加する。これは変更してもよい。

    // プログラムを終了する"close"アイコンを追加する。これは autorelease オブジェクト。
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           CC_CALLBACK_1(MoleScene::menuCloseCallback, this));

    closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                                 origin.y + closeItem->getContentSize().height/2));

    // メニューを作成する。これは autorelease オブジェクト。
    auto menu = Menu::create(closeItem, NULL);
    // メニューの位置を設定する。
    menu->setPosition(Point::ZERO);
    // メニューを子レイヤーとして追加する。
    this->addChild(menu, 1);

    /////////////////////////////
    // 3. 独自のコードを追加する。
    this->setTouchMode(Touch::DispatchMode::ONE_BY_ONE);

    // ラベルを作成し、初期化する。
    auto label = LabelTTF::create("whack a mole sample", "Arial", 24);

    // 画面の中央にラベルを位置づける。
    label->setPosition(Point(origin.x + visibleSize.width/2,
                             origin.y + visibleSize.height - label->getContentSize().height));

    // ラベルをレイヤーの子として追加する。
    this->addChild(label, 1);

    // cocosアイコンを追加する。
    sprite = Sprite::create("Icon.png");

    // スプライトを画面の中央に位置づける。
    sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    // スプライトをレイヤーの子として追加する。
    this->addChild(sprite, 0);

    // シングルタッチイベントリスナーを作成する。
    auto listener1 = EventListenerTouchOneByOne::create();
    // スワロータッチモードにするとonTouchBeganメソッドはタッチイベントは他では使われない。
    listener1->setSwallowTouches(true);

    // onTouchBeganイベントコールバック関数実装のラムダ式の例
    listener1->onTouchBegan = [](Touch* touch, Event* event) {
        // event->getCurrentTarget() は、リスナーのsceneGraphPriorityの優先順に対象オブジェクトを返す。
        auto target = static_cast<Sprite*>(event->getCurrentTarget());

        // ボタンに対する相対的な位置を取得する。
        Point locationInNode = target->convertToNodeSpace(touch->getLocation());
        // コンテンツのサイズを取得する。
        Size s = target->getContentSize();
        // コンテンツ矩形を作成する。
        Rect rect = Rect(0, 0, s.width, s.height);

        // クリックエリアをチェックする。
        if (rect.containsPoint(locationInNode))
        {
            log("sprite began... x = %f, y = %f", locationInNode.x, locationInNode.y);
            // 不透明度を変更する。
            target->setOpacity(180);
            return true;
        }
        return false;
    };

    // タッチが移動した場合
    listener1->onTouchMoved = [](Touch* touch, Event* event) {
        // ターゲットを取得する。
        // auto target = static_cast<Sprite*>(event->getCurrentTarget());
        // ここに移動した場合の処理を書く。touch->getDelta()で移動量が取得できる。
    };

    // タッチイベントが終了した場合
    listener1->onTouchEnded = [=](Touch* touch, Event* event) {
        // ターゲットを取得する。
        auto target = static_cast<Sprite*>(event->getCurrentTarget());
        // ここに終了した場合の処理を書く。
        log("sprite onTouchesEnded.. ");
        // スプライトを画面の中央に位置づける。
        sprite->setPosition(*getNextPosition());
        // 不透明度を元に戻す。
        target->setOpacity(255);
    };

    // イベントリスナーをスプライトに追加する。
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite);

    return true;
}

/**
 *  メニューの"Close"が選択された場合のコールバック関数。
 *
 *  @param pSender 送信元
 */
void MoleScene::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
    return;
#endif

    // ディレクタを終了する。
    Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

/**
 *
 *  画面上のランダムな位置を取得する。
 *
 *  @return 画面上のランダムな位置
 */
Point* MoleScene::getNextPosition()
{
    // スプライトを新しい位置に変更する。
    Point* point = new Point(random() % (int)visibleSize.width, random() % (int)visibleSize.height);

    return point;
}