フライングで公開してしまったのですが、無事Advent Calendarのトップバッター役割を果たせてホッとしています。
今年はcocos2d-xにとっても激動の年でしたね。
2系でのお仕事も一段落ついたので、来年は3系で攻めたいと思います。
はじめに
今回の記事の内容は基本的に2系での内容です。
3系では調査していないので、事情が多少違うかもしれませんが、参考になればと思います。
概要
cocos2d-x(js)において、WebView等を利用するために別アクティビティに遷移し、イベント内容をCocos側(C++,JavaScriptなど)で処理したいケースは多いと思います。
以前、Android GUIの処理に関しては次のような簡単なメモを記事【cocos2d-xのtouchイベント内でtoastを表示したいとき】にしたのですが、イベントリスナーを持つGUIの場合、そのイベント処理をGLThreadで行う必要があります。
その辺りについて解説したいと思います。
Androidにおけるcocos2d-xのイベントについて
基本的にほとんどの処理がmainスレッドで行われるiOSと異なり、Androidではcocos2d-xの処理は基本的にGLThread上で行われます。
描画処理は元より、パネルのタッチイベントやゲームロジック(C++,JavaScript,Lua)もおおよそはこのスレッド上で実行されます。
そのため、Android GUIを利用する際には上記の記事で解説したようにHandlerクラスを使って、UIスレッド上で処理するように実装しなければいけません。
一方でこういったGUIからタップ等のイベントを受け取り、ゲームロジックへイベント通知する際にはどうすればよいのでしょうか?
Androidにおいてはゲームロジックの処理は全てGLThreadからコールされる必要があります。(内部で他のスレッドを利用するのはOK)
関数コールバックや非同期処理などのイベントリスナーはGLThread上で動作するよう実装しなければいけません。
GLThreadからUIThreadに処理を渡すのは比較的容易なんですが、UIThreadからGLThreadに処理を渡すのは少々厄介です。
基本的に、Cocos2dxActivityあるいはそのサブクラスのActivityはシステムに常駐していると思いますので、Activityのインスタンスをどちらかに保持しておいて、そこからrunOnGLThreadをコールするのが簡単だと思います。
この辺り、非常に野暮ったいコードになるので3系ではもっとスマートにアクセスできるとよいのですが(未確認)
サンプルコード
下記のようなUtilityメソッドを用意しておくと便利かと思います。
public static void runOnCocos2dxActivity(Runnable runnable) {
sCocos2dxActivity.runOnGLThread(runnable);
}
JNI経由のコールバックとしては次のような感じになるかと思います。
hoge.runOnCocos2dxActivity(new Runnable() {
public void run() {
Callback.onSuccess();
}
});
JNIはこんな定義かな
extern "C"
{
JNIEXPORT void JNICALL Java_jp_hoge_src_Callback_onSuccess(JNIEnv* env, jobject thiz);
}
実際はコールバック関数の格納コンテナや、C++インターフェースを考える必要がありますが、エッセンスだけ記載しておきます。
cocos2d-jsでの注意
先ほどコールバックについて少し解説しましたが、cocos2d-x上では実はコールバック関数内でCocosAPIを使用しないのであれば普通に動作したりします。
しかし、cocos2d-jsにおいてはコールバック関数内のスクリプトのパースに失敗し、まったく動作せずにエラーメッセージだけが出力されます。
基本的にJavaScriptはSpiderMonkeyが動作しているGLThread上でしか動作しないので、コールバック関数も常にGLThread上で動くようにしておきてください。
終わりに
Qiitaでのアドベントカレンダーは初参加なので、正直書き方がよくわかってなくて、これでいいのかなー?
迷いがあるのですが、おかしなところがあればご容赦ください。
では、みなさま良い年越しを^^