以前より「子供向けのプログラミング学習書籍の執筆を行いたい」とリックテレコム社の担当者さんに相談していたところ、同社から「みんなのプログラミング入門」が出版されたとのことで献本いただきました。そこでこの本をレビューしてみたいと思います。

http://www.amazon.co.jp/dp/4865940138/
みんなのプログラミング入門

この本は「プログラミン」と呼ばれる文部科学省が提供している子供向けプログラミング学習サービスを用いて、プログラムの基礎を学ぶことができます。MITメディアラボが開発した「Scratch(スクラッチ)」に非常に似ていますが、個人的には「Scratch」よりも「プログラミン」の方がイラストがかわいいので好きです。子供にとってはキャラクターが大切なので重要な点ですね。

2年前にも「プログラミン」を利用した書籍が検討されていましたが、当時は「プログラミン」の書籍執筆は許されていませんでした。しかしここ最近「プログラミン」の書籍が多く出版されているので、規制が緩和されたのでしょう。

この本を手にとって一番最初に「読みやすい」と感じました。もちろん子供に読みやすいように全ページフルカラーで構成されています。また「プログラミン」自身が日本人好みのイラストを採用しているだけでなく、この書籍に出てくるキャラクターに親しみを感じます。読み進めていると、文章がダラダラと書かれているのではなく、文章中にもイラストが利用されており細かな気配りに感動しました。

しかし、どんなに文章が読みやすくても、子供が理解出来る程度に噛み砕いて書かれているのか気になるところです。そのため試しに1章を読みながら実際に「プログラミン」で作成してみました。結果、最後まで迷うことなくスラスラと進めることができました(大人なんだからできて当たり前と言われればそれまでですが。。。)。また手順だけでなく何故そのような結果になるのかまで判りやすく説明してありました。

fireworks

このような感じで4章までありますが、この本はこれだけでは終わりません。最後の付録には、プログラミング言語を用いた本格的なプログラミング体験を行う内容が収録されています。このように「プログラミン」の次のステップが用意されていることに好感が持てます。しかし1点残念なことは、これまで作ったプログラムとの関連性が薄いことです。例えば1章で作った内容を、実際のプログラミング言語に置き換えるなどすれば、子供にとっても理解しやすいのではないかと感じました。とはいえ、ここまでの内容をカバーしている書籍は少ないので付録としてでもあるだけありがたい内容かと思います。

私も以前より子供向けの書籍を書きたいと思っています。しかし私が書きたい内容は「プログラミン」や「Scratch」などではなくプログラミング言語を用いたものです。そこで一番の壁となるのが、プログラミング言語を扱うためのインストールなどの前準備です。この準備が難しければそこでつまずいてしまい、本来学びたかったプログラミング言語を学習することができません。インストール不要なブラウザ上でプログラミングできるサービスも多くありますが、そのサイトがいつ仕様変更されるかわからないため利用することは難しいです。以前、高校生向けにゲームプログラミングを講義したときは、ブラウザを利用したインストール不要のサービスを自前で用意し教えました。しかしこのサービスも一般に公開できるようなレベルではないため、これも難しいです。となると、開発環境の構築が容易なサービスを探すしかないですね。もう少し悩んでみたいと思います。

Cocos2d-x は、 iOS と Android のクロスプラットフォーム開発に適したゲームエンジンではありますが、広告や解析などサードパーティ製 SDK ( 3rd SDK ) を導入しようとすると、一筋縄ではいかないことが多々ありました。理由としては、 3rd SDK の多くが iOS 向け・ Android 向けに用意されており、ゲーム開発者が Cocos2d-x との連携を行っていたためです。そのため、 Cocos2d-x のほか、 Objective-C , Java や iOS フレームワーク, Android SDK , Android NDK などに渡って理解が必要になりました。また Cocos2d-x 用 SDK を提供しているサービスもありますが、 Cocos2d-x のマイナーバージョンにより導入手順が異なるなど、 3rd SDK の導入は困難でした。
そこで考案されたのが SDKBOX です。これは Cocos2d-x を利用したゲームへの 3rd SDK 導入を容易にしてくれるツールです。 Cocos2d-x と同じ Chukong により開発が進められているものであり、 SDKBOX も無料で利用することができます。 SDKBOX の初期リリース時はコマンドラインにより処理されるものであり正常に動作しないケースが多々ありましたが、現在では Cocos2d-x のプロジェクト管理ツールである「 Cocos 」上で SDKBOX の適用が可能となり、また SDKBOX によってはフルオートで全ての設定が完了します。
このように非常に便利な SDKBOX について、今回はその利用方法をご紹介します。

1. SDKBOX の紹介

SDKBOX は Cocos2d-x の公式サイトからも利用することができますが、 SDKBOX のホームページが用意されています。
http://www.sdkbox.com/
SDKBOXサイト

また Chukong が開発しているため Cocos2d-x 専用と思われがちですが、実は Unity や UnrealEngine 用も一部のサービスのみ用意されています。

導入が容易になる 3rd SDK は、下記で確認することができます。
http://www.sdkbox.com/integrations
SDKBOXプラグイン

  • アプリ内課金
  • 広告
  • 解析
  • ストア
  • ソーシャル
  • 動画

など幅広くカバーされていることがわかるでしょう。上記は SDKBOX Plugin として用意されており、 SDKBOX が 3rd サーバとの連携を行います。つまり SDKBOX Plugin さえ導入すれば、あとはプロジェクトの好きなタイミングで任意の処理を呼び出すだけです。
SDKBOXシーケンス図

2. SDKBOX が適用されたプロジェクトを用意

最も簡単に SDKBOX が適用されたプロジェクトを作成するには、 Cocos2d-x のプロジェクト管理ツールである「 Cocos 」を用いることです。 Cocos を利用したプロジェクト作成方法は、「Cocos Studio を使った Android APK ファイル生成方法」で紹介しましたが、このとき表示されていた「 SDKs 」の項が正に SDKBOX なのです。その一覧には SDKBOX Plugin が表示されています。導入するプラグインは最新である必要がありますので、必要なプラグインの右にある「 Download 」または「 Update 」をクリックしてチェックボックスを有効にし、チェックを入れてください。そして「 Create 」ボタンを押下します。下記では参考に「 Youtube 」プラグインにチェックを入れています。また言語には「 JavaScript 」を選択しています。
SDKBOXの導入方法

既存プロジェクトに別のプラグインを適用するときは、プロジェクトのコンテキストメニューを開き「 Properties 」を選択します。「 Properties 」ウィンドウで追加するプラグインを選択できます。
SDKBOXプラグインの追加(1)
SDKBOXプラグインの追加(2)

3. プロジェクト編集

「 Youtube 」プラグイン( v.2.1.1 )の場合、 AppDelegate.cpp だけは自動編集されないため、自分で追記が必要になります。
(今後のアップデートで AppDelegate.cpp の編集も不要になると思われます。)

・AppDelegate.cpp 編集
15行目

#ifdef SDKBOX_ENABLED
#include "PluginYoutubeJS.hpp"
#include "PluginYoutubeJSHelper.h"
#endif

77行目

ScriptingCore* sc = ScriptingCore::getInstance();
#ifdef SDKBOX_ENABLED
sc->addRegisterCallback(register_all_PluginYoutubeJS);
sc->addRegisterCallback(register_all_PluginYoutubeJS_helper);
#endif
sc->start();

4. ソースコード編集

それでは実際に Youtube を表示するコードを書いてみます。プラグイン利用時は、 init 関数により必ず初期化が必要になります。 Youtube プラグインの場合は、 Youtube 動画を再生できますので playVideo 関数により実行します。

・app.js 編集
2行目

var HelloWorldLayer = cc.Layer.extend({
    ctor:function () {
        this._super();

        var mainscene = ccs.load(res.MainScene_json);
        this.addChild(mainscene.node);

        sdkbox.PluginYoutube.init();
        sdkbox.PluginYoutube.playVideo("YqyPa0UR-R0", 0, true, true);

        return true;
    }
});

5. アプリ実行

それでは実機を用いでアプリを実行しましょう。 Cocos Studio より「 Run Android 」を選択します。ビルドが始まりますのでしばらく待ちましょう。
アプリの実行アプリのビルド

ビルドが完了すると、アプリが実行されます。その画面には Youtube 動画が再生されているでしょう。
Android端末上での動作確認

6. まとめ

SDKBOX を利用することにより、 Cocos2d-x 以外の知識を使わず 3rd SDK を導入できることができました。しかもたった2ファイル・6行追加するだけの工数です。いかに SDKBOX が開発を容易にしてくれるものかが解って頂けたと思います。
今回は「 Youtube 」プラグインを用いて SDKBOX を紹介しましたが、ほかのプラグインも同様に簡単に 3rd SDK を導入することができます。また SDKBOX バージョンを重ねるごとに設定が簡単になっていますし、プラグインもかなり増えています。ぜひ今後も SDKBOX に注目してみていただければと思います。

Cocos Studio は、 Windows と Mac 上で動作する Cocos2d-x のUIエディタ・アニメーションエディタとして知られていますが、ここ最近機能が豊富になっています。従来、 Cocos2d-x を利用した Android 向けの開発は環境構築に苦労していましたが、 Cocos Studio を利用するとこの環境構築が大変容易になり、かつ Cocos Studio のみで APK 作成が可能となっています。
今回はこの Android の環境構築から APK 作成の一連の流れを紹介します。

1. Cocos インストール

まず最初に Cocos Studio をインストールしなければいけないですが、現在のバージョンでは Cocos と呼ばれるツールに Cocos Studio が含まれています。そのため、 Cocos2d-x の公式サイトから Cocos インストーラをダウンロードしてください。
http://cocos2d-x.org/download/
Cocos Studio ダウンロード

ダウンロードが終わったら、ダウンロードした Cocos インストーラを実行し、画面に従ってインストールを進めてください。特別な設定はないので問題なくインストールが完了するでしょう。

2. Cocos Studio の実行・設定

Cocos のインストールが終わったら、早速実行しましょう。画面右上にある「 New Project 」ボタンをクリックし、プロジェクトを作成します。今回は Cocos Studio を利用するため、 Editor の項において Cocos Studio にチェックを入れてください。そして最後に「 Create 」ボタンをクリックします。

  • Project Name … プロジェクト名
  • Project Path … 配置する場所
  • Engine Version … Cocos2d-xのバージョンの選択
  • Engine Type … エンジンの状態がコンパイル済み or ソースコード
  • Language … 開発言語の選択
  • Editor … エディタの利用
  • SDKs … プロジェクトに導入する SDKBOX (こちらについては「3rd SDK導入を容易にする SDKBOX の利用方法」をご覧下さい)

Cocos におけるプロジェクト作成

プロジェクトが作成されると、自動的に Cocos Studio が立ち上がります。次に Cocos Studio の設定を行いましょう。 Windows の場合は「 Editor => Preferences… 」、Macの場合は「 Cocos Studio => Preferences… 」を選択することで設定画面を開きます。そして左ペインから「 Platform 」を選択してください。この Android Path 項目で Android アプリの開発に必要な設定を行うことができます。

  • SDK … Android SDK のパスを設定
  • NDK … Android NDK のパスを設定
  • ANT … Apache ANT のパスを設定
  • JDK … Java Developer Kit のパスを設定

Cocos Studio の設定 ( Windows )Cocos Studio の設定 ( Mac )

ANT は Cocos に含まれているものを利用しますが、他の ANT を利用したい場合は「 Browse… 」ボタンより変更してください。ここで「 One Click Configure 」ボタンがあり、 適切な SDK, NDK, JDK をダウンロードすることができますが、本来必要な License Agreement の表記がありません。Google や Oracle のサイトより内容に同意した上でご利用ください。設定はこれだけです。

3. Android 端末で実行

設定が正常に整っていると、適切に編集を行ったプロジェクトを Android 端末上で実行することができます。メニューより「 Run on Android 」を選択し「 Run Project 」ボタン(ドロイドのアイコン)をクリックしてください。
Android 端末で実行 ( Windows )Android 端末で実行 ( Mac )

すると Android 向けにビルドが開始されますので、処理が終わるまでしばらく待ちましょう。
Android 向けのビルド

ビルドが正常に終了すると、自動で端末にインストール・実行されます。ここでのビルドは、プロジェクトのソースコードを含めてビルドを行っているため、Cocos Studio プレビュー機能の動作と異なることに注意してください。
Android 端末上で実行

4. Android APK 出力設定・出力

画面上部にある項目から「 Publish and Package… 」を選択します。
Android APK 出力設定

「 Publish and Package 」画面が表示されますので、そこから「 Package 」にある「 Settings 」ボタンをクリックします。
Android APK 出力設定 ( Windows )Android APK 出力設定 ( Mac )

「 Project Settings」画面が表示されますので、左ペインから「 Package 」の項を選択するとパッケージ( APK )生成時の出力パス設定を行うことができます。適切なパスを入力してください。
Android APK 出力先設定 ( Windows )Android APK 出力先設定 ( Mac )

続いて左ペインから「 Android Setting 」の項を選択すると keystore や Build Options の設定を行うことができます。デバッグだけであれば設定は必要ありませんが、リリースするのであれば keystore や Package Identifier ・ Android Version の設定を行いましょう。ここで keystore を作成することも可能です。
keystore ・ Build Options 設定 ( Mac )keystore ・ Build Options 設定 ( Windows )

これで設定が完了しましたので、「 Publish and Package 」画面にて「 OK 」ボタンをクリックしましょう。
Android APK 出力 ( Windows )Android APK 出力 ( Mac )

パッケージのビルドが開始されますので、ビルドが終わるまで少し待ってください。正常に終了すると、「 Project Settings」画面で設定したパスに、 APK ファイルが出力されています。
Android APK のビルド

まとめ

従来のCocos2d-xでは、プロジェクトの作成・実行・APK作成などをコマンドプロンプトやターミナル上で行っていました。それが今回ご紹介したように全てGUI上で行うことができるようになり、非常に便利な開発環境となっています。また今回は紹介を飛ばしましたが、 Cocos のプロジェクト作成機能には、 3rd パーティ製 SDK の導入を容易にする SDKBOX の機能も有しています。さらに快適な開発環境になること間違いないので、ぜひこれを機に Cocos ・ Cocos Studio を利用してみてください。

Cocos2d-xにはEventManagerが用意されており、タッチイベントなどのEventListenerを登録することで、タッチ処理を行うことができるようになります。
このEventListenerには、

  • シングルタッチ … cc.EventListener.TOUCH_ONE_BY_ONE
  • マルチタッチ … cc.EventListener.TOUCH_ALL_AT_ONCE
  • キーボード … cc.EventListener.KEYBOARD
  • マウス … cc.EventListener.MOUSE
  • 加速度センサ … cc.EventListener.ACCELERATION

などのEventListenerが用意されており、またカスタムイベント(cc.EventListener.CUSTOM)の登録を行うことも可能です。
今回は、シングルタッチイベントの利用方法を紹介します。

1. 画面のタッチイベント

app.jsを次のように書き換えましょう。

var HelloWorldLayer = cc.Layer.extend({
    sprite:null,
    ctor:function () {
        this._super();

        var size = cc.winSize;

        this.sprite = new cc.Sprite(res.HelloWorld_png);
        this.sprite.setPosition(size.width / 2, size.height / 2);
        this.addChild(this.sprite, 0);

        cc.eventManager.addListener(listener, this);

        return true;
    }
});

var HelloWorldScene = cc.Scene.extend({
    onEnter:function () {
        this._super();
        var layer = new HelloWorldLayer();
        this.addChild(layer);
    }
});

var listener = cc.EventListener.create({
    event: cc.EventListener.TOUCH_ONE_BY_ONE,

    onTouchBegan: function (touch, event) {
        cc.log("onTouchBegan");
        return true;
    },

    onTouchMoved: function (touch, event) {
        cc.log("onTouchMoved");
    },

    onTouchEnded: function (touch, event) {
        cc.log("onTouchEnded");
    },

    onTouchCancelled: function (touch, event) {
        cc.log("onTouchCancelled");
    }
});

HelloWorldLayer クラスのコンストラクタでは、 cc.eventManager に対してlistenerを追加しました。また第2引数は、画面となる自分自身ですので this を渡します(12行目)。
追加する listener は、26行目に定義しています。この EventListener の作成は、 cc.EventListener.create 関数により行なわれます。その引数は連想配列によりキーと値を設定します。連想配列に必要なキーは event です。今回はシングルタッチイベントを用いるため、値を cc.EventListener.TOUCH_ONE_BY_ONE とします。またシングルタッチイベントで取得する関数を定義します。シングルタッチイベントでは、次の4つのイベントを取得することができます。

  • onTouchBegan イベント (タッチした瞬間に発生)
  • onTouchMoved イベント (スワイプ中に発生)
  • onTouchEnded イベント (タッチ終了時に発生)
  • onTouchCancelled イベント (タッチ処理がキャンセルされた時に発生)

これらを連想配列のキーとし、関数を値とします。またシングルタッチイベントの場合、 onTouchBegan イベントは必須項目となります。 onTouchBegan イベントの関数には戻り値が必要であり、 true を返すことで onTouchMoved イベントや onTouchEnded イベントなど以降のイベントを発生させることができます。もし以降のイベントを発生させたくない場合は、 false を返すと良いでしょう。

タッチイベントの確認

それでは実行してみてください。そして画面をタッチしてみましょう。それぞれのイベントではログを出力するようにしているため、コンソールログには、次のように表示されるでしょう。

onTouchBegan
onTouchMoved
onTouchMoved
onTouchMoved
onTouchEnded

最初に onTouchBegan が表示され、スワイプしている時間に比例して onTouchMoved が表示されています。そして最後に onTouchEnded が表示されています。もし onTouchBegan イベントの戻り値を false としていたならば、コンソールログには onTouchBegan のみが表示されます。

2. ノードのタッチイベント

これまでは画面のタッチイベントについて説明しましたが、あるスプライトがタッチされたことを判定したい場合もあるでしょう。ここではその方法を紹介します。
と言っても、実は簡単です。それは cc.eventManager に対してEventListenerを追加するの第2引数に対象とするインスタンスを渡すだけです。具体的にソースコードを見ると理解が早いでしょう。
app.js の HelloWorldLayer を次のように書き換えましょう。

var HelloWorldLayer = cc.Layer.extend({
    sprite:null,
    ctor:function () {
        this._super();

        var size = cc.winSize;

        this.sprite = new cc.Sprite(res.HelloWorld_png);
        this.sprite.setPosition(size.width / 2, size.height / 2);
        this.addChild(this.sprite, 0);

        cc.eventManager.addListener(listener, this.sprite);

        return true;
    }
});

変更したのは、12行目の cc.eventManager.addListener 関数の第2引数を this.sprite に変更しただけです。つまり this.sprite に対して listener を追加したことになります。それでは実行し画面をスワイプしてみましょう。そしてコンソールログを見てみましょう。

onTouchBegan
onTouchMoved
onTouchMoved
onTouchMoved
onTouchEnded

前回と同じログが表示されたでしょう。しかし、 Cocos2d-x のロゴ以外を触れても同じようにイベントが発生します。実は、画面をタップするといつでもどこでもイベント発生します。そのため、 onTouchBegan イベントで画像タッチの判定を行う必要があります。それでは onTouchBegan イベントの関数を次のように修正してください。また画像がタップされたことを判りやすくするために、 onTouchMoved イベントの修正も行いましょう。

onTouchBegan: function (touch, event) {
    cc.log("onTouchBegan");

    var target = event.getCurrentTarget();
    var location = target.convertToNodeSpace(touch.getLocation());
    var spriteSize = target.getContentSize();
    var spriteRect = cc.rect(0, 0, spriteSize.width, spriteSize.height);

    if (cc.rectContainsPoint(spriteRect, location)) {
        cc.log("ロゴがタッチされました");
        return true;
    }

    return false;
},

onTouchMoved: function (touch, event) {
    cc.log("onTouchMoved");

    var target = event.getCurrentTarget();
    var delta = touch.getDelta();
    target.setPosition(cc.pAdd(target.getPosition(), delta));
},

onTouchBegan イベントの第2引数 event には、cc.eventManager.addListener 関数の第2引数で渡したノードが含まれています。 event.getCurrentTarget 関数によりそのターゲットを取得します(4行目)。第1引数 touch には、タッチした位置が格納されていますが、これは画面上のタッチ位置を示しているため、ターゲットを基準とした位置に変更します(5行目)。このタッチ位置が、画像の内側にあるかどうかの判定には、画像の位置とサイズが必要になるため、7行目に構造を定義します。なお、ターゲットを基準としているため、位置は (0, 0) となります。そして cc.rectContainsPoint 関数にターゲットの構造と位置を渡すと、ターゲットの内部がタップされた時は true が、ターゲットの外部がタップされた時は false が返ります(9行目)。ここでは true が返ると、ログを表示するようにしており、以降のイベントを有効とするため onTouchBegan 関数の戻り値を true としています。
onTouchMoved イベントでは、第1引数 touch に含まれる移動の差分を用い、ターゲットの位置に加えています(22行目)。つまりロゴ画像をスワイプすると、スワイプに合わせてロゴ画像が移動します。

それでは実行してみましょう。ロゴをスワイプすると画像が動く様子がわかるでしょう。またロゴには次のように表示されているでしょう。もし、画像以外をタップすると、コンソールログには onTouchBegan のみが表示されます。

onTouchBegan
ロゴがタッチされました
onTouchMoved
onTouchMoved
onTouchMoved
onTouchEnded

3. 複数ノードのタップイベント

さっきは1つのノードに対するタップ処理でしたが、次は複数ノードに対するタップイベントを考えてみましょう。複数ノードそれぞれに EventListener を追加すると、追加したノード分イベントが発生します。しかし、複数ノードに対してイベントが発生した場合、ある問題が出てきます。ここではその問題と解決方法を紹介します。
app.js の HelloWorldLayer を次のように書き換えましょう。なお res フォルダに、

  • cat1.png
  • cat2.png
  • cat3.png

の3つの画像を追加しています。

var HelloWorldLayer = cc.Layer.extend({
    ctor:function () {
        this._super();

        var size = cc.winSize;

        var cat1 = new cc.Sprite("res/cat1.png");
        cat1.setPosition(size.width / 2, size.height / 2 + 100);
        cat1.setName("すもも");
        this.addChild(cat1, 10);

        var cat2 = new cc.Sprite("res/cat2.png");
        cat2.setPosition(size.width / 2, size.height / 2);
        cat2.setName("あんず");
        this.addChild(cat2, 30);

        var cat3 = new cc.Sprite("res/cat3.png");
        cat3.setPosition(size.width / 2, size.height / 2 - 100);
        cat3.setName("こうめ");
        this.addChild(cat3, 20);

        cc.eventManager.addListener(listener, cat1);
        cc.eventManager.addListener(listener.clone(), cat2);
        cc.eventManager.addListener(listener.clone(), cat3);

        return true;
    }
});

ネコの画像を3匹表示します。またそれぞれのノードに対してEventListenerを追加しますが、これまで通り listener を利用します。しかし、1つの EventListener は1つのノードにのみ有効ですので、他のノードに対しては listener をクローンして利用します。(22〜24行目)
それでは実行してみましょう。ネコをスワイプすると、ネコが移動することがわかるでしょう。しかし、2匹以上のネコが重なっていると、それらが同時に移動します。場合によっては、前面の1匹のみを動かしたいこともあるでしょう。
その場合は、 EventListener に swallowTouches のキーを追加し、値を true とすることで実現します。 swallow とは日本語で「ツバメ」以外に「受け入れる」や「吸収する」などの意味も持っています。つまり、タッチイベントを下のレイヤに通さないようにできます。ただし onTouchBegan イベントで false を返すと、 swallowTouches が true であっても下のレイヤでイベントが発生します。
それでは listener を次のように変更してください。

var listener = cc.EventListener.create({
    event: cc.EventListener.TOUCH_ONE_BY_ONE,
    swallowTouches: true,
    :
});

3行目に swallowTouches を追加しました。それではこれで実行してみましょう。
複数ノードのタッチイベントの確認

ネコをスワイプすると、ネコが重なっていても前面のネコのみが移動することがわかるでしょう。ここで1点注意してください。cat1, cat2, cat3に対して EventListener を追加するとき、cat1, cat2, cat3の順番に追加しました。一方、表示順は前面から cat2, cat3, cat1としています(localZorderがそれぞれ30, 20, 10)。それでは実際のタッチ判定の順番はどうでしたでしょうか?3匹のネコが重なっている箇所をタッチすると、最前面のネコが移動しました。つまり標準では前面から順番にタッチ判定が成されることがわかるでしょう。

まとめ

ここでは、タッチイベントについて紹介しました。 Cocos2d-x には、タッチイベントの仕組みが用意されており、 EventListener を利用することにより簡単に扱えることを学びました。ノードに対するタッチイベントを設定したい場合は onTouchBegan イベントにおいてタッチされたかの判定を行うこと、 以降のイベントを取得したい場合は true を返す必要がありました。複数ノードに対してタッチ判定を行う場合は、 前面からの表示順でタッチイベントが処理されることもわかりました。
タッチイベントは多くの場面で利用するため、ぜひ覚えておきましょう。

Cocos2d-x にはボタンのクラスが3つ用意されています。どのボタンを使うと良いのでしょうか?これらのボタンにはそれぞれ特徴がありますので、これらを紹介したいと思います。ぜひ Cocos2d-x のボタンをマスターしてください。

1. cc.Menu クラス

  • メリット
    • メニューで利用するときに便利
  • デメリット
    • 1つのボタンとして利用するには不便
    • ボタンのイベントが1種類 ( TouchEnded )

概要

最も古くからあるボタンです。クラス名に Menu とあるように、もともとはメニューの表示を簡単に実装するために用意されていました。 Tests のメニューが良い例ですね。ボタンの実態は cc.Menu ではなく、 cc.MenuItem クラスが担っています。 cc.Menu クラスは、 cc.MenuItem クラスを管理するために用いられます。そのため、単独のボタンとして利用するには少々不便ですが、次に紹介する cc.ControlButton クラスが誕生するまでは、これを使うしかなかったのです。今では、単独のボタンで利用するメリットはありませんが、メニューとして利用するのであれば使いやすいでしょう。

cc.MenuItem クラスには、次のようなサブクラスがあります。

  • cc.MenuItemLabel クラス(文字のボタン)
    • cc.MenuItemFont クラス
    • cc.MenuItemAtlasFont クラス
  • cc.MenuItemSprite クラス(画像のボタン)
    • cc.MenuItemImage クラス
  • cc.MenuItemToggle クラス(トグルボタン)

cc.MenuItemLabel クラスと cc.MenuItemSprite クラスには、さらにサブクラスが用意されており、全部で6種類のボタンが用意されています。

サンプル

実際にメニューとして利用する方法を確認しましょう。以降のサンプルは、プロジェクト作成時に用意されている HelloWorldLayer クラスを編集しています。

var HelloWorldLayer = cc.Layer.extend({
    ctor:function () {
        this._super();

        var size = cc.winSize;

        //ボタン生成
        var item1 = new cc.MenuItemFont("Button1", this.onTouchButton1, this);
        var item2 = new cc.MenuItemFont("Button2", this.onTouchButton2, this);
        var item3 = new cc.MenuItemFont("Button3", this.onTouchButton3, this);
        var item4 = new cc.MenuItemFont("Button4", this.onTouchButton4, this);
        var item5 = new cc.MenuItemFont("Button5", this.onTouchButton5, this);

        //ボタン管理
        var menu = new cc.Menu(item1, item2, item3, item4, item5);
        menu.alignItemsVertically(); //自動整列
        menu.setPosition(size.width / 2, size.height / 2); //画面中央に配置

        //ボタン表示
        this.addChild(menu);

        return true;
    },

    onTouchButton1:function (sender) {
        cc.log("Touch Button1");
    },

    onTouchButton2:function (sender) {
        cc.log("Touch Button2");
    },

    onTouchButton3:function (sender) {
        cc.log("Touch Button3");
    },

    onTouchButton4:function (sender) {
        cc.log("Touch Button4");
    },

    onTouchButton5:function (sender) {
        cc.log("Touch Button5");
    }
});

実行結果

cc.Menuクラスによるボタン表示

解説

ここでは、文字列をボタンとする cc.MenuItemFont クラスのボタンを利用し、5つのボタンを作成しました。インスタンス生成時の引数は、

  • 第1引数: ボタンの文字列
  • 第2引数: コールバック関数
  • 第3引数: ターゲット

を示します。そして、これらのボタンを管理する cc.Menu に渡し、 menu を生成しました。それぞれのボタンは位置を指定しませんでしたが、 menu の alignItemsVertically 関数を呼び出すことで、自動的に整列させることができます。位置の指定は、この menu にだけに行えば大丈夫です。
これを実行すると、次のように整列されたボタンが表示されます。

ただし、このボタンのコールバックが返ってくるタイミングは、タップが終了するタイミング ( TouchEnded ) のみであることに注意してください。

2. cc.ControlButton クラス

  • メリット
    • ボタンのイベントが豊富 ( iOSのボタンイベントと同様 )
    • ボタンの背景画像に cc.Scale9Sprite を利用した際、自動で文字列に合わせたサイズが適用される
    • ボタンの状態に対して、ラベルや画像を個別に設定することが可能
  • デメリット
    • 必ずラベル ( cc.Label ) が必要

概要

cc.ControlButton クラスは、Cocos2d-x v2 系の頃に、従来より高機能なオブジェクトが作られていた頃に用意されたボタンです。そのため、ボタンより取得できるイベントが豊富です。ちょうど、 iOS のボタンで取得できるイベントと同じものが用意されています。

  • TOUCH_DOWNイベント
  • TOUCH_DRAG_INSIDEイベント
  • TOUCH_DRAG_OUTSIDEイベント
  • TOUCH_DRAG_ENTERイベント
  • TOUCH_DRAG_EXITイベント
  • TOUCH_UP_INSIDEイベント
  • TOUCH_UP_OUTSIDEイベント
  • TOUCH_CANCELイベント

cc.ControlButton クラスのインスタンス生成時には、ボタンの文字列となる cc.Label クラスとボタンの背景画像となる cc.Sprite クラスのインスタンスを用意する必要があります。ここで背景画像のない文字列のみのボタンとすることは可能ですが、文字列のない画像のみのボタンとすることはできません。もし画像のみのボタンとしたい場合は、空文字のラベルを用意する必要があります。

サンプル

実際にボタンを作成してみましょう。

/*
 * 注意: project.json 内にて、 module キーに対して extensions を追加する必要があります。
 *    また resource.js に画像ファイルを設定しています。
 */
var HelloWorldLayer = cc.Layer.extend({
    ctor:function () {
        this._super();

        var size = cc.winSize;

        //ボタンの背景
        var bgButton = new cc.Scale9Sprite(res.Button_png);
        var bgHighlightedButton = new cc.Scale9Sprite(res.Button_Highlighted_png);

        //ボタンのラベル
        var title = new cc.LabelTTF("Button", "Marker Felt", 30);
        title.color = cc.color(159, 168, 176);

        //ボタン
        var button = new cc.ControlButton(title, bgButton);
        button.setBackgroundSpriteForState(bgHighlightedButton, cc.CONTROL_STATE_HIGHLIGHTED);
        button.setTitleColorForState(cc.color.WHITE, cc.CONTROL_STATE_HIGHLIGHTED);
        button.setPosition(size.width / 2, size.height / 2);
        button.zoomOnTouchDown = false;

        //イベント
        button.addTargetWithActionForControlEvents(this, this.touchDownAction, cc.CONTROL_EVENT_TOUCH_DOWN);
        button.addTargetWithActionForControlEvents(this, this.touchDragInsideAction, cc.CONTROL_EVENT_TOUCH_DRAG_INSIDE);
        button.addTargetWithActionForControlEvents(this, this.touchDragOutsideAction, cc.CONTROL_EVENT_TOUCH_DRAG_OUTSIDE);
        button.addTargetWithActionForControlEvents(this, this.touchDragEnterAction, cc.CONTROL_EVENT_TOUCH_DRAG_ENTER);
        button.addTargetWithActionForControlEvents(this, this.touchDragExitAction, cc.CONTROL_EVENT_TOUCH_DRAG_EXIT);
        button.addTargetWithActionForControlEvents(this, this.touchUpInsideAction, cc.CONTROL_EVENT_TOUCH_UP_INSIDE);
        button.addTargetWithActionForControlEvents(this, this.touchUpOutsideAction, cc.CONTROL_EVENT_TOUCH_UP_OUTSIDE);
        button.addTargetWithActionForControlEvents(this, this.touchCancelAction, cc.CONTROL_EVENT_TOUCH_CANCEL);

        this.addChild(button);

        return true;
    },

    touchDownAction:function (sender, controlEvent) {
        cc.log("touchDownAction");
    },
    touchDragInsideAction:function (sender, controlEvent) {
        cc.log("touchDragInsideAction");
    },
    touchDragOutsideAction:function (sender, controlEvent) {
        cc.log("touchDragOutsideAction");
    },
    touchDragEnterAction:function (sender, controlEvent) {
        cc.log("touchDragEnterAction");
    },
    touchDragExitAction:function (sender, controlEvent) {
        cc.log("touchDragExitAction");
    },
    touchUpInsideAction:function (sender, controlEvent) {
        cc.log("touchUpInsideAction");
    },
    touchUpOutsideAction:function (sender, controlEvent) {
        cc.log("touchUpOutsideAction");
    },
    touchCancelAction:function (sender, controlEvent) {
        cc.log("touchCancelAction");
    }
});

実行結果

cc.ControlButtonクラスによるボタン表示

解説

ここでは、ボタンの文字列に「Button」と表示する cc.Label を用意しています。また背景画像に cc.Scale9Sprite を利用しています。これらを引数とし、 cc.ControlButton クラスのインスタンスを生成しました。 cc.ControlButton では、ボタンの状態に応じてラベルや背景画像を変更することができます。各イベントに対するコールバックは addTargetWithActionForControlEvents 関数を用い紐づけます。上のソースコードでは全てのイベントを紐づけていますが、もちろん必要なイベントだけ宣言してもいいですし、全て同じコールバック関数を呼び出しても問題ありません。全て同じコールバック関数を呼び出すときは、コールバック関数の第2引数でイベントの種類を判別することができます。

3. ccui.Button クラス

  • メリット
    • ccui.Button クラスのみで完結するシンプルなボタン
  • デメリット
    • ボタンのイベント取得時に、type による分岐が必要

概要

ccui.Button クラスは、Cocos Studioのために用意されたクラスです。しかし Cocos Studioを利用しなくても、ボタンとして非常に使いやすいクラスです。 cc.ControlButton クラスでは、ラベルと画像をそれぞれ用意していましたが、 cc.Button クラスではその必要はありません。そのため、ソースコードがシンプルになります。画像だけのボタンや文字列だけのボタンも作成可能です。

サンプル

実際にボタンを作成してみましょう。

/*
 * 注意: project.json 内にて、 module キーに対して cocostudio を追加する必要があります。
 *    また resource.js に画像ファイルを設定しています。
 */
var HelloWorldLayer = cc.Layer.extend({
    ctor:function () {
        this._super();

        var size = cc.winSize;

        //ボタン
        var button = new ccui.Button(res.Button_png, res.Button_Highlighted_png);
        button.setPosition(size.width / 2, size.height / 2);
        button.setScale9Enabled(true);
        button.setContentSize(140, 55);

        //ラベル
        button.setTitleText("Button");
        button.setTitleFontName("Marker Felt");
        button.setTitleFontSize(30);
        button.setTitleColor(cc.color(159, 168, 176));

        //イベント
        button.addTouchEventListener(this.touchEvent, this);

        this.addChild(button);

        return true;
    },

    touchEvent: function(sender, type){
        switch (type) {
            case ccui.Widget.TOUCH_BEGAN:
                cc.log("Touch Down");
                break;

            case ccui.Widget.TOUCH_MOVED:
                cc.log("Touch Move");
                break;

            case ccui.Widget.TOUCH_ENDED:
                cc.log("Touch Up");
                break;

            case ccui.Widget.TOUCH_CANCELED:
                cc.log("Touch Cancelled");
                break;

            default:
                break;
        }
    }
});

実行結果

ccui.Buttonクラスによるボタン表示

解説

ここでは、Scale9 を有効にした例を紹介しています。 ccui.Button クラスのインスタンス生成時に、引数として通常ボタン画像と選択時ボタン画像を渡しました。 setScale9Enabled 関数の引数を true とすることで画像の Scale9 が有効になります。またその画像の表示サイズを setContentSize 関数にて設定します。 cc.ControlButton クラスのように自動でサイズを設定してくれないので注意しましょう。
ボタンの文字列は、 setTitleText 関数で設定することができます。その他、フォント名・フォントサイズ・フォントカラーの設定も可能です。
イベントに対するコールバックは addTouchEventListener 関数を用い紐づけます。コールバック関数においては、第2引数よりイベントの種類を取得できるので、これにより細かな設定を行うことができます。

まとめ

ここで紹介したように、Cocos2d-xで用意されているボタンは3種類あります。またそれぞれ特徴があり、どれが一番良いかは必要な機能や好みによって分かれますが、私がよく好んで利用するのはシンプルにコードを書くことができる ccui.Button クラスです。またより細かな設定が必要な時は cc.ControlButton クラスを、メニューとして利用する時は cc.Menu クラスを利用します。
Cocos2d-x初期の頃は、cc.Menu クラスしかなく TOUCH_BEGAN イベントを取得したい時は、 cc.Sprite クラスをベースに自前でボタンを作成していました。その頃から比べると、ボタンの種類が増え非常に便利になっています。ぜひそれぞれのボタンの特徴を覚え、ニーズにあったボタンを利用しましょう。

Cocos2d-x (JS)では画像表示に cc.Sprite クラスを用います。これは基本中の基本であり、既に知ってるよっという方は多いと思います。しかし何の問題もなく表示できるのはネイティブアプリのお話であり、ブラウザアプリでは一癖あります。知らなければ嵌ってしまい、無駄に時間を費やす結果となってしまうので、ぜひ一読ください。

cc.Spriteクラスの基本

Cocos2d-x (JS) における cc.Sprite クラスの利用方法は、プロジェクト作成時に用意される app.js ファイルの HelloWorldLayer クラスの29行目にも書かれている通りです。Sprite生成後、 getContentSize() 関数によりテクスチャのサイズを取得する(下記2行目)と、正常にテクスチャの幅を取得することができます。

this.sprite = new cc.Sprite(res.HelloWorld_png);
cc.log("===== HelloWorld width: " + this.sprite.getContentSize().width);

ロゴ画像のサイズを取得

真ん中に表示されている Cocos2d-x のロゴの幅は、195ピクセルですので正しいですね。

ロゴ画像の幅は195ピクセル

新しい画像を追加

では、新しい画像を追加してみましょう。 Cocos2d-x のルールの通りresディレクトリに sumomo_and_koume.png を配置しました。

新しい画像を追加

この画像を表示するためのコードを、次のように用意しました。

var sumomoKoume = new cc.Sprite("res/sumomo_and_koume.png");
cc.log("===== SumomoKoume width: " + sumomoKoume.getContentSize().width);
sumomoKoume.attr({
    x: size.width / 2,
    y: size.height / 2
});
this.addChild(sumomoKoume, 1);

それではブラウザで実行してみましょう。

画像サイズが0と表示される

あれ?画像は表示されているのに、テクスチャの幅を取得できていません。これではサイズを利用した細かな配置処理を行うことができないですね。。。なぜ幅が0と表示されているのでしょうか?

サイズを取得できない理由

勘の鋭い方はもうおわかりかと思いますが、 Cocos2d-x (JS) には、事前にリソースを読み込むための resource.js が用意されています。今回の場合、 resource.js に記述していないため、まだ読み込まれたことのないテクスチャを利用しようとしていることになります。そして読み込みが終わる前にサイズを取得しようとしているため、値が 0 と表示されてしまったのです。 そのため、resource.js に sumomo_and_koume.png を記述しておけば、読み込みが完了しているため正常にサイズを取得することができます。

var res = {
    HelloWorld_png : "res/HelloWorld.png",
    SumomoKoume_png : "res/sumomo_and_koume.png",
};

非同期読み込みで画像を表示する方法

しかし、 resource.js が膨大な量になれば、それだけ起動に時間がかかることになります。起動時間を短縮し、ゲーム中にテクスチャの非同期読み込みを行いたいこともあるでしょう。実はそのような仕組みもCocos2d-x (JS) には備わっているのです。それが addLoadedEventListener 関数です。テクスチャの読み込みが完了すると、任意の関数が呼び出されます。

var sumomoKoume = new cc.Sprite("res/sumomo_and_koume.png");
sumomoKoume.addLoadedEventListener(function()
{
    cc.log("===== SumomoKoume width: " + sumomoKoume.getContentSize().width);
    sumomoKoume.attr({
        x: size.width / 2,
        y: size.height / 2
    });
    this.addChild(sumomoKoume, 1);
}, this);

画像サイズが正しく表示される

これをうまく利用すれば、メモリを圧迫することなく、快適なゲームを作ることができるのではないでしょうか。とても便利な機能ですので、ぜひ活用してください。

ここでは、Windows上にCocos2d-x(JS)のブラウザアプリ開発環境を構築する手順を示します。

Cocos2d-xのダウンロード

次のCocos2d-xダウンロードページから、Cocos2d-xをダウンロードしてください。
http://www.cocos2d-x.org/download/version
Cocos2d-xのダウンロード

Pythonのダウンロードおよびインストール

Cocos2d-xのインストールはPythonで書かれたスクリプトにより行われるため、Pythonをインストールする必要があります。次のPythonダウンロードページから、Python v2.xをダウンロードしてください。
https://www.python.org/downloads/
Pythonのダウンロード

ダウンロードしたインストーラにより、画面の指示に従ってPythonをインストールして下さい。標準インストールですと「C:¥Python27」にインストールされます。インストールが完了したら、環境変数であるPath変数にPythonのパスを登録します。

PythonのパスをPath変数に追加する

Cocos2d-xのインストール

ダウンロードしたzipファイルを解凍し、任意のフォルダに配置してください。
以降は、Cocos2d-x v3.7をCドライブ直下に配置した場合の手順を示します。ご自身の環境に適したユーザ名・フォルダ名に適宜書き換えてください。
プロジェクトの作成・実行には「cocos」コマンドを利用します。これから「cocos」コマンドを利用利用できるように環境設定を行いましょう。

  1. ターミナルを起動し、Cocos2d-xのディレクトリへ移動します。
    > cd c:¥cocos2d-x-3.7
  2. 環境設定を自動で行ってくれる「setup.py」を実行します。
    > setup.py

    途中でAndroid NDK, SDK, ANTの場所を問われますが、これはAndroidアプリを作成するために必要なものですので、今回のブラウザアプリには不要です。エンターキーを押して処理を飛ばしましょう。一連の処理が終わると、次のようなメッセージが表示されます。

    Please restart the terminal or restart computer to make added system variables take effect

    環境変数を設定したため、それを反映させるためにターミナルを再起動します。

Cocos2d-xのインストール

プロジェクトの作成

プロジェクトの作成には「cocos new」コマンドを利用します。
以降は、ホームディレクトリに新しいプロジェクトを作成する方法を示します。ご自身の環境に適したユーザ名・ディレクトリ名に適宜書き換えてください。

  1. プロジェクトを配置するディレクトリに移動します。下記は、ホームディレクトリへ移動する例です。
    $ cd
  2. 「cocos new」コマンドを利用し、プロジェクトを作成します。
    $ cocos new NewProject -l js --no-native
    • cocos new … プロジェクト作成コマンド
    • NewProject … プロジェクト名
    • -l js … 開発言語オプションによりjs(JavaScript)を選択
    • –no-native … ブラウザアプリ専用プロジェクトとする

プロジェクトの作成

これでホームディレクトリに、「NewProject」ディレクトリが用意されました。

プロジェクトの作成完了

プロジェクトの実行

それでは作成したプロジェクトを実行しましょう。プロジェクト実行コマンドは「cocos run」です。
以降は、書類フォルダに作成したプロジェクトをブラウザで実行する方法を示します。ご自身の環境に適したユーザ名・フォルダ名に適宜書き換えてください。

  1. プロジェクトのフォルダへ移動する。
    > cd Documents/NewProject/
  2. 「cocos run」コマンドを利用し、プロジェクトを作成します。
    > cocos run -p web
    • cocos run … プロジェクト実行コマンド
    • -p web … 実行プラットフォームオプションによりweb(ブラウザ)を選択

プロジェクトの実行

すると次のような画面が表示されるでしょう。

ブラウザで表示

画面に何も表示されない

もし画面が真っ黒のまま何も表示されない場合は、JavaScriptが有効になっていない可能性がありますので、JavaScriptを有効にしてください。Chromeの場合ですと、「設定 > 詳細設定を表示… > プライバシー > コンテンツの設定 > JavaScript」より、JavaScriptを有効にすることができます。
JavaScriptを有効にする

WebGLを有効にする

Cocos2d-x(JS)は、WebGLを利用することができます。ブラウザのWebGLが有効になっているか、確認してください。Chromeの場合ですと、URL欄に「chrome://flags」と入力し「WebGLを無効にする」の項目を確認して下さい。次の画面は「WebGLを無効にする」を「有効にする」表記になっているため少々判り難いですが、この画面の通りであれば、WebGLが有効になっています。
WebGLを有効にする

開発中はブラウザのキャッシュを無効にする

開発中は、ソースコードやリソースを頻繁に修正するでしょう。そのときブラウザにキャッシュが残っていては、思い通りに動かないことがあります。そのため、あらかじめブラウザのキャッシュを無効にしておくといいでしょう。Chromeの場合ですと、「デベロッパーツール > 設定」より、「Disable cache (while DevTools is open)」にチェックを入れることによりキャッシュを無効にすることができます。
キャッシュを無効にする

まとめ

以上で、WindowsにおけるCocos2d-x(JS)のブラウザアプリ開発環境の構築ができました。

  • Cocos2d-xのインストールは、setup.pyにより環境設定を行う
  • プロジェクトの作成には、「cocos new」コマンドを利用する
  • プロジェクトの実行には、「cocos run」コマンドを利用する
  • ブラウザ上で動かすときは、JavaScriptを有効にする
  • ブラウザによってはWebGLを無効になっているため、ブラウザの設定よりWebGLを有効にする
  • 開発中は、ブラウザのキャッシュを無効にする

ここでは、Mac上にCocos2d-x(JS)のブラウザアプリ開発環境を構築する手順を示します。

Cocos2d-xのダウンロード

次のCocos2d-xダウンロードページから、Cocos2d-xをダウンロードしてください。
http://www.cocos2d-x.org/download/version
Cocos2d-xのダウンロード

Cocos2d-xのインストール

ダウンロードしたzipファイルを解凍し、任意のディレクトリ(ホームディレクトリなど)に配置してください。
以降は、Cocos2d-x v3.7をホームディレクトリに配置した場合の手順を示します。ご自身の環境に適したユーザ名・ディレクトリ名に適宜書き換えてください。
プロジェクトの作成・実行には「cocos」コマンドを利用します。これから「cocos」コマンドを利用利用できるように環境設定を行いましょう。

  1. ターミナルを起動し、Cocos2d-xのディレクトリへ移動します。
    $ cd cocos2d-x-3.7/
  2. 環境設定を自動で行ってくれる「setup.py」を実行します。
    $ ./setup.py

    途中でAndroid NDK, SDK, ANTの場所を問われますが、これはAndroidアプリを作成するために必要なものですので、今回のブラウザアプリには不要です。エンターキーを押して処理を飛ばしましょう。一連の処理が終わると、次のようなメッセージが表示されます。

    Please execute command: "source /Users/(ユーザ名)/.bash_profile" to make added system variables take effect

    環境変数を設定したため、それを反映させるために「source /Users/(ユーザ名)/.bash_profile」を実行します。

    $ source /Users/(ユーザ名)/.bash_profile

Cocos2d-xのインストール

プロジェクトの作成

プロジェクトの作成には「cocos new」コマンドを利用します。
以降は、ホームディレクトリに新しいプロジェクトを作成する方法を示します。ご自身の環境に適したユーザ名・ディレクトリ名に適宜書き換えてください。

  1. プロジェクトを配置するディレクトリに移動します。下記は、ホームディレクトリへ移動する例です。
    $ cd
  2. 「cocos new」コマンドを利用し、プロジェクトを作成します。
    $ cocos new NewProject -l js --no-native
    • cocos new … プロジェクト作成コマンド
    • NewProject … プロジェクト名
    • -l js … 開発言語オプションによりjs(JavaScript)を選択
    • –no-native … ブラウザアプリ専用プロジェクトとする

プロジェクトの作成

これでホームディレクトリに、「NewProject」ディレクトリが用意されました。

プロジェクトの作成完了

プロジェクトの実行

それでは作成したプロジェクトを実行しましょう。プロジェクト実行コマンドは「cocos run」です。
以降は、ホームディレクトリに作成したプロジェクトをブラウザで実行する方法を示します。ご自身の環境に適したユーザ名・ディレクトリ名に適宜書き換えてください。

  1. プロジェクトのディレクトリへ移動する。
    $ cd ~/NewProject/
  2. 「cocos run」コマンドを利用し、プロジェクトを作成します。
    $ cocos run -p web
    • cocos run … プロジェクト実行コマンド
    • -p web … 実行プラットフォームオプションによりweb(ブラウザ)を選択

プロジェクトの実行

すると次のような画面が表示されるでしょう。

ブラウザで表示

画面に何も表示されない

もし画面が真っ黒のまま何も表示されない場合は、JavaScriptが有効になっていない可能性がありますので、JavaScriptを有効にしてください。Safariの場合ですと、「Safari > 環境設定… > セキュリティ」より、JavaScriptを有効にすることができます。
JavaScriptを有効にする

WebGLを有効にする

Cocos2d-x(JS)は、WebGLを利用することができます。ブラウザのWebGLが有効になっているか、確認してください。Safariの場合ですと、「Safari > 環境設定… > セキュリティ」より、WebGLを許可することができます。
WebGLを許可する

開発中はブラウザのキャッシュを無効にする

開発中は、ソースコードやリソースを頻繁に修正するでしょう。そのときブラウザにキャッシュが残っていては、思い通りに動かないことがあります。そのため、あらかじめブラウザのキャッシュを無効にしておくといいでしょう。Safariの場合ですと、「Safari > 環境設定… > 詳細」より「開発」メニューを表示した後、「開発」メニューよりキャッシュを無効にすることができます。
開発メニューを表示する
キャッシュを無効にする

まとめ

以上で、MacにおけるCocos2d-x(JS)のブラウザアプリ開発環境の構築ができました。

  • Cocos2d-xのインストールは、setup.pyにより環境設定を行う
  • プロジェクトの作成には、「cocos new」コマンドを利用する
  • プロジェクトの実行には、「cocos run」コマンドを利用する
  • ブラウザ上で動かすときは、JavaScriptを有効にする
  • ブラウザによってはWebGLを無効になっているため、ブラウザの設定よりWebGLを有効にする
  • 開発中は、ブラウザのキャッシュを無効にする

Cocos2d-xの統合

Cocos2d-xロゴ
Cocos2d-x v3.7の登場により、これまでブラウザアプリの開発を行うことができたCocos2d-JSがなくなり、Cocos2d-xに統合されました。Cocos2d-xは、iOSやAndroidのようなネイティブアプリの開発を行うことができますが、今後は開発言語としてJavaScriptを選択することで、ブラウザアプリの開発も行うことができることになります。

Cocos2d-x(JS)のメリット

Cocos2d-xのC++版と比較して、Cocos2d-xのJavaScript版(以下、Cocos2d-x(JS)と略します)を利用するメリットとしては、次のことが挙げられるでしょう。

  • ネイティブアプリ
    • クロスプラットフォーム開発(iOS, Android, Windows, Mac, Linux, …)
    • アプリの更新なしで、ソースコードの追加が可能(Apple Storeは規約により不可)
    • SpiderMonkey搭載(JavaScriptエンジン)
  • ブラウザアプリ
    • クロスブラウザ開発(Chrome, Firefox, IE, Safari)
    • ブラウザ上で特別なプラグイン不要
    • WebGL利用(WebGLが利用できない場合はCanvasを利用)

Cocos2d-x(JS)の事例

まだ数は少ないものの、日本においてもCocos2d-x(JS)を利用したアプリ開発は増えています。有名なところですと、Greeの釣りスタ、エイチームのユニゾンリーグなどがあります(正しくはCocos2d-JSを利用)。

釣りスタ

http://jp.product.gree.net/tsurista/
釣りスタ釣りスタAppStore釣りスタGooglePlay

ユニゾンリーグ

http://app.a-tm.co.jp/unisonleague/
ユニゾンリーグ釣りスタAppStore釣りスタGooglePlay

またCocos2d-x(JS)を利用し、ネイティブゲーム(iOS, Androidアプリ)とブラウザゲーム(Facebookアプリ)の同時開発を行っている事例もあります。それはBig Fish GamesのBig Fish Casinoです(正しくはCocos2d-JSを利用)。

Big Fish Casino

http://www.bigfishgames.com/online-games/19475/big-fish-casino/

Big Fish CasinoBig Fish Casino AppStoreBig Fish Casino GooglePlayBig Fish Casino Facebook

実際のところ、データの持ち方など異なるため、ネイティブアプリとブラウザアプリで完全に同一なソースコードにすることは難しいですが、それでもこのような事例があることは非常に心強いです。

Cocos2d-x(JS)のパフォーマンス

開発言語がJavaScriptだと、C++と比較し処理速度が遅いのではないかと思われる方が多いですが、実際にはそこまでC++に劣ることはありません。
ネイティブアプリの場合、裏ではC++で処理されているCocos2d-xが動いています。FireFoxのJavaScriptエンジンであるSpiderMonkeyにより、JavaScriptとC++の変換が行われているため、高い処理能力を保っています。シューティングゲームの弾幕のような高負荷な処理でない限り、問題になることはないでしょう。またCocos2d-xはオープンソースソフトウェア(OSS)ですので、パフォーマンスチューニングも容易です。
一方、ブラウザアプリの場合、WebGLを利用していますので高パフォーマンスを得られることが期待できます。特別なプラグインなど必要ありません。WebGLが利用できないときは、従来のCanvasが利用されます。ただWebGLでもCanvasでも利用可能なゲームとする場合はパフォーマンス面では注意が必要です。

Cocos2d-x(JS)のセキュリティ

セキュリティ面についても、ネイティブアプリの場合「–compile-script」オプションを利用することでJavaScriptのソースコードがjscファイルにコンパイルされます。そのため生のソースコードが晒されることはありません。ブラウザアプリについては、Cocos2d-x(JS)に限った問題ではなくブラウザアプリ全体に言えることですが、重要な処理はサーバ上で行うなど事前に設計を塾考する必要があるでしょう。

ネイティブゲームからブラウザゲームへの回帰

数年前に、ブラウザゲームからネイティブゲームへのシフトがありましたが、スマートフォンのネイティブゲームの方が表現の高いゲームを作ることができたからでした。しかし、ブラウザゲームとネイティブゲームで利用されている技術はあまりにも違いすぎており、ネイティブゲームへのシフトが遅れた企業が非常に多かったことは記憶に新しいですね。
ここ最近は、スマートフォンにおいてもの高スペックなものが多く、ブラウザでもサクサクと動くゲームが作れるようになっています。そのため、またブラウザへの回帰があるのではないかと考えている企業が多いです。

この先ブラウザゲームへの回帰があるかどうか、私自身まだ判断しきれていないですが、今後は可能な限りCocos2d-x(JS)を利用するべきだと考えています。
Cocos2d-x(JS)は、ネイティブアプリもブラウザアプリもどちらでも開発することができますが、両方のアプリを同時に作ることを推奨しているものではありません。しかし、Cocos2d-x(JS)の利用方法はほぼ同じです。今はCocos2d-x(JS)でネイティブアプリを製作し技術を身につけておけば、もしブラウザゲームへの回帰があるときは、スムーズにブラウザゲームへシフトすることができるでしょう。ブラウザゲームへの回帰がなかったとしても、ゲームの公式サイトでお試しプレイができるなど、利用方法はいくらでもあると思っています。

Cocos2d-xを利用したゲームの開発言語

また日本のスマホマーケットにおいて、Cocos2d-xのシェア率は上がっているにも関わらず、Cocos2d-xの開発者が不足しています。これは日本ではCocos2d-xのメインの開発言語となっているC++に問題があるのではないかと思っています。C++と聞いただけで拒絶反応を示す開発者もいれば、メモリ管理に悩まされ去っていく開発者もいます。
その点JavaScriptであれば初心者に優しい言語であり、開発者の中でも人気の高い言語になっています。サーバエンジニアの方でも気軽に開発することができるでしょう。しっかりとしたゲームを作るにはメモリ管理は避けて通れない道ですが、まずはゲーム製作の楽しさを知ってもらうことの方が重要かと思っています。

このブログの目的

Cocos2d-JSを含め、Cocos2d-x(JS)の日本語の情報は非常に少ないです。そのため、このブログでCocos2d-x(JS)の情報を紹介できればと思っています。

cocos-docの編集方法

はじめに

ここでは、まだ一度もGitHubを利用したことがない方向けに、「cocos-doc」の編集方法を紹介します。詳細については「手順」で紹介しますが、一度「概要」に目を通し全体の流れを把握してください。説明は「cocos-doc」で行っていますが、一般的なGitHubの利用方法ですので、オープンソースである「cocos2d-x」に通ずるものでもあります。また「手順」ではなるべく簡単な方法を紹介しています。そのため細かく言うと正しい方法でないものも含まれていますが、まずはチャレンジしてもらえると幸いです。1つでも多くの日本語のドキュメントが作成されることを願っています。

概要

ドキュメントやファイルの変更は、cocos2d/cocos-docリポジトリのものを変更しますが、これらを直接変更することはできません。自分で編集可能な{your name}/cocos-docリポジトリを用意し、ローカルへダウンロードします。
次にダウンロードしたドキュメントやファイルを、ローカル上で編集します。
編集が終わったら、それらの変更内容をGitHubへ送信します。この段階では、{your name}/cocos-docリポジトリだけが変更されているので、この変更内容をPull Requestを利用してcocos2d/cocos-docリポジトリへ通知します。
Chukong社の担当者が、上記Pull Requestを確認し、問題ないと判断されるとcocos2d/cocos-docリポジトリに反映されます。

用意するもの

手順

  1. リポジトリの作成
    cocos2d/cocos-docリポジトリのフォークし{your name}/cocos-docリポジトリ作成します。最初に以下のURLへアクセスしてください。
    https://github.com/cocos2d/cocos-docs
    画面右上にある「Fork」ボタンをクリックします。すると{your name}/cocos-docリポジトリが作成されます。
    Fork
  2. ドキュメントのダウンロード
    {your name}/cocos-docリポジトリの管理は、SourceTreeを利用します。SourceTreeを起動し、「リポジトリを追加」ボタンを押下します。
    GitHub02
    次の画面が表示されるので、「ソースパス / URL」に{your name}/cocos-docリポジトリのURLを入力します。このURLは、GitHub上に記されているのでそれをコピーするといいでしょう。「保存先のパス」「ブックマーク名」は任意で編集してください。「クローン」ボタンを押下すると、「保存先のパス」へ{your name}/cocos-docリポジトリがダウンロードされます。このダウンロードには少々時間が掛かりますので、気長に待ってください。
    SourceTree
  3. ファイルの編集
    ファイルは自由に編集しても問題ありません。必要なファイルの追加・編集・削除は、Finder上で行うことができます。ここでは次のディレクトリに日本語用のファイルとなる「ja.md」を追加する方法を示します。
    cocos-docs/tutorial/parkour-game-with-cocostudio/chapter1
    まず「en.md」をコピーして「ja.md」にリネームします。
    GitHub04
    ファイルの拡張子は「md」ですので、マークダウン方式で記述を行います。テキストエディタで編集してもいいですが、Macであれば「Markdown Life」のようなエディタを利用すると編集が楽になります。
    GitHub05
    ファイルの編集が終わったら、次はそのファイルを呼び出す箇所の修正も行いましょう。上記の「ja.md」は目次にリンクを貼りたいと思います。目次は次のファイルですので、適切に編集を行います。
    cocos-docs/catalog/ja.md
    GitHub06
    ここまでで、1つのファイルの追加、1つのファイルの編集を行ったことになります。
  4. コミット&プッシュ
    3.における編集は、ローカルにあるファイルだけです。これらの編集をGitHubの{your name}/cocos-docリポジトリに反映する必要があります。それにはコミットとプッシュという操作を行います。厳密には、コミットとプッシュにはそれぞれの役割があるのですが、ここでは簡単にまとめて操作を行いましょう。
    SourceTreeのブックマークより、「cocos-docs」リポジトリをダブルクリックし、リポジトリの詳細を開いてください。そして「コミット」ボタンを押下してください。すると「作業ツリーのファイル」に編集を行ったファイルが表示されています。
    GitHub07
    これらをドラッグアンドドロップで「Indexにステージしたファイル」へ移動してください。「コミットメッセージ」に編集を行った内容を記述し、「コミットを直ちにプッシュする(origin)」にチェックを入れてください。そして最後に「コミット」ボタンを押下しましょう。これでコミット&プッシュは完了です。
    GitHub08
  5. Pull Request
    4.の操作で、{your name}/cocos-docリポジトリが変更されたので、次はこの変更をcocos2d/cocos-docリポジトリへ通知する必要があります。これにはPull Requestを利用します。GitHubの自分のリポジトリを表示してください。ここで4.で編集した「コミットメッセージ」が表示されていることを確認してください。
    GitHub09
    問題なければ「Pull Request」を押下します。編集された内容が表示されるので、念のため目を通しておきましょう。そして「Click to create a pull request for this comparison」を押下します。
    GitHub10
    ここで「タイトル」と「メッセージ」を記述し、「Send pull request」を押下すれば完了です。
    GitHub11
    それでは、cocos2d/cocos-docリポジトリへPull Requestが送られたか確認してみましょう。「Open」のPull Requestの一覧に表示されていますね。後は担当の方がチェックしてくれるまで、気長に待ちましょう。
    GitHub12