Google+ もご覧ください
ユーザーアイコン

cocos2d javascript bindingsでマルチプラットフォーム開発

第九回 cocos2d-iphone jsbとcocos2d-x jsbで違うタッチイベントの実装について知る

Seasons

第九回 cocos2d-iphone jsbとcocos2d-x jsbで違うタッチイベントの実装について知る

前回(第8回)までで4inchの対応方法、Retina画像の取扱方法まで紹介しました。ここまでくるとある程度JSBにおける開発環境に慣れてきたのではないかと思います。cocos2d jsbのコンセプトとして、cocos2d-xやcocos2d-iphone、cocos2d-html5で出来ることは全て実現することが目標ですが、JSBの実装の違いによるハマリ所があります。

今回はその中でもタッチイベントについて触れていきたいと思います。

cocos2d-iphone jsbとcocos2d-x jsbのタッチ処理の実装の違い

jsbの実装はcocos2d-iphoneが先にjsbindingsというライブラリでgithubに公開されたものの、その実装はObjective-Cの実装の都合もあり、Swizzleなどを駆使して実装されたものでした。特にその影響を受けた処理としてタッチイベントがあります。 cocos2dのタッチ処理には2種類の実装があり、StandardとTargettedがあります。

Standard

setTouchEnabledに対して、YESを設定したもの全てに対して、タッチイベントが呼ばれる仕組みとなっています。

Targetted

自身をタッチイベントのターゲットとして登録する処理(addTargetedDelegate)を行い、且つ優先度と下にイベントを流すかどうかの設定を行います。例えば、あるオブジェクトにタッチをしたらその下のオブジェクトまでタッチイベントを発生させたくない時などに利用します。

このタッチイベント処理の使い分けがcocos2dでは非常に重要となります。

しかし、cocos2d-iphoneのjsbでは実装の都合からStandardのみが実装されており、Targettedを利用することが出来ません。Targettedが使えない分、細かいタッチ制御は自分自身でおこなう必要があります。 一方、cocos2d-xのjsbは両方実装されているため、これまで通りのタッチ処理をjsbでも利用することができます。

それでは早速、それぞれのタッチ処理の実装方法を見ていきましょう。

Standardタッチ処理

Standardタッチ処理は、手軽に実装できるタッチ処理です。とにかくタッチイベントだけ欲しい場合には重宝するでしょう。サンプルコードを見ながら具体的な実装方法についてみていきましょう。

タッチイベントを有効にする方法

  1. cc.Layerを継承したクラスのメソッド内で、setTouchEnabled(true)を呼び出す。
  2. onTouchesXXXXX(Began,Moved,Ended,Cancelled)を必要に応じて実装する。

実装コードは以下のような感じになります。

    var GameLayer = cc.Layer.extend({
        ctor: function() {
            this._super();
            // Standardタッチを有効にする
            this.setTouchEnabled(true);
        },

        // タッチイベントが発生
        onTouchesBegan: function(touches,event) {
            cc.log("touch!!");
        }
    }

画面をタッチすると、touch!!というメッセージがコンソールログに表示されます。

タッチ情報の取得

タッチされた位置などを取得するには、引数で渡ってくるタッチオブジェクトから取得します。

        onTouchesBegan: function(touches, event) {
            var c = touches.length;
            var touch = touches[0];
            var pos = touch.getLocation();
            cc.log("touch!!" + "count[" + c + "]" + pos.x + "," + pos.y);
        }

touchesは、マルチタッチ前提で複数のタッチオブジェクトが入っている可能性があるため、シングルタッチの情報は0番目のオブジェクトから情報を取得します。

cocos2d-iphone版のjsbは、このStandardタッチ処理のみ実装されているため、タッチのハンドリングが少々面倒になりがちです。ゲームのような細かいタッチ制御が前提になる場合は、次のTargettedが実装されているcocos2d-xのjsbを利用するようにしましょう。

Targettedタッチ処理

次にTargetedタッチ処理について説明します。このタッチ処理は、その名の通り指定したターゲットに対してタッチイベントを付与する処理です。ゲームで例えるなら、操作物や対象物に対してのみタッチ判定を設けたい場合に重宝します。またタッチ後のイベントを下に流すかどうかの制御も出来るため、細かい制御が可能です。

タッチイベントの有効にする方法

このTargettedタッチ処理を実装するには、Standardとは異なり、あるクラスを継承する形で実装することが望ましいです。例えば、あるスプライトオブジェクトにこのタッチイベントを付与したい場合は、cc.Sprite.extendでスプライト継承して新たなスプライトクラスを作成します。

言葉で説明するのは少々難しいため、具体的にコードで見ていきましょう。

    var IconSprite = cc.Sprite.extend({
        _rect: null,
        _id: 0,

        ctor: function(id) {

            this._super();
            this.init("Icon.png");
            var rc = this.getTextureRect();
            this._rect = cc.rect(0, 0, rc.width, rc.height);
            this._id = id;
        },

        onEnter: function() {
            cc.log("onEnter :IconSprite");
            cc.registerTargettedDelegate(0, true, this);
            this._super();
        },

        onExit: function() {
            cc.log("onExit :IconSprite");
            cc.unregisterTargettedDelegate(this);
            this._super();
        },

        rect: function() {
            return cc.rect(-this._rect.width / 2, -this._rect.height / 2,
                this._rect.width,
                this._rect.height);
        },

        containsTouchLocation: function(touch) {
            var getPoint = touch.getLocation();
            var myRect = this.rect();

            myRect.x += this.getPosition().x;
            myRect.y += this.getPosition().y;
            return cc.rectContainsPoint(myRect, getPoint);
        },

        onTouchBegan: function(touch, event) {
            if (this.containsTouchLocation(touch)) {
                cc.log("sprite touch!!" + this._id);
                return true; /* 下のオブジェクトにもタッチ処理を流すには、false */
                // standard touchの対象にもなる
            }
            return false;
        },

    });

少々コードが大きくなりますが、1つ1つ解説していきます。

  1. cc.Spriteを継承したクラスIconSpriteを作成します。
  2. onEnter, onExitにて、registerTargettedDelegate,unregisterTargettedDelegateを呼び出し、自身を登録する。引数の数字は優先度。
  3. onTouchXXXX(Began,Moved,Ended,Cancelled)を必要に応じて実装する。

基本的にこの手続きだけでよいですが、他にもいくつかメソッドが実装されています。 これらはスプライトのタッチ判定をサポートするための実装で、cocos2d-xのサンプルにも含まれているPaddle.jsから引用したものです。

追加のメソッド

  • rectプロパティ = スプライトのサイズを格納。
  • containsTouchLocation = タッチオブジェクトからタッチされた位置がスプライトの中かどうかを判定し、結果を返します。

このメソッドを利用して、onTouchBegan内でスプライトがタッチされたかどうかを判定しています。タッチされていればcc.logで"sprite touch"と表示します。

onTouchBeganの戻り値

onTouchBeganは、戻り値の値でその後の挙動が変化します。ソースコードにも記載されていますが、falseを返すとその後、別のオブジェクトにタッチイベントを流します。trueを返すと、タッチイベントはそのオブジェクトで終了します。

例えばオブジェクトが重なっている場合、下のオブジェクトにもタッチイベントを流したい時には、falseを返すようにしましょう。

オブジェクトの重なっている例
オブジェクトの重なっている例

Targettedタッチイベントオブジェクトの使い方

さて、このように実装したIconSpriteクラスは、次のように利用します。

    var icon = new IconSprite(1);
    this.addChild(icon);
    icon.setPosition(cc.p(200, 200));

オブジェクトはnewのキーワードを用いてオブジェクトを生成します。cc.Spriteを継承していますのでcc.LayerなどにaddChildで登録することができます。今回、引数に1を渡していますが、これは内部でオブジェクトを識別するための番号になります(詳しくはソースコードを確認してください)。自分で実装する方法以外に、すでにcocos2dのオブジェクトが持つtagを利用しても良さそうですね。

今回の実装を全て収録したソースコードは、こちらで確認できます。


次回予告

次回は、cocos2d jsbのデバッグ環境について少し触れてみたいと思います。

今回のサンプルプロジェクトは、こちらからダウンロードできます。

Cocos2d jsb
タグ:

記事をリクエストする

関連記事

コメント