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

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

第五回 this._super()とネイティブオブジェクトについて学ぶ

Seasons

第五回 this._super()とネイティブオブジェクトについて学ぶ

cocos2d jsbプログラムでは、cocos2d-xのクラスや機能をほとんど全て利用することが出来ます。しかし、cocos2d-x独自のお作法やクラスメソッド、インスタンスメソッドの呼び出し手続きが若干異なるため、本格的にコーディングに入る前にその仕組みを理解しておくと今後に役立つでしょう。今回は、jsbの仕組みの一つについて学んでいきましょう。

this._super() と ネイティブオブジェクト

前回のソースコードの以下の箇所をみてください。【ここ】の箇所。

var GameLayer = cc.Layer.extend({

    // Constructor
    ctor:function () {

        this._super(); => ここ
        this.init();

this._super()というメソッドが出てきています。実はこのメソッドを書き忘れると非常に分かりづらいエラーがでます。 試しにこの箇所をコメントにしてビルド、実行してみてください。以下のようなエラーがでると思います。

Cocos2d: Invalid Native Object
Cocos2d: JS: Error: Invalid Native Object

Invalid Native Objectというエラーがでてますね。一体これはなんでしょう? このメッセージは、jsbの仕組みにおけるネイティブオブジェクトを理解する必要があります。

実行はできるけれどエラーが出ます
実行はできるけれどエラーが出ます

JavaScriptオブジェクトとC++オブジェクト

サンプルコードでは、cc.Layer、cc.Sceneなどが登場し、普通にビルド、実行できました。 これには当然カラクリがあります。 次の図を見てください。

CCLayer関連図
CCLayer関連図

これまで何気なく、cc.Layerと記述していましたが、実は、このような構造で成り立っています。詳しい話は今回は割愛しますが、簡単に説明すると、cocos2d-x jsb側でプログラム実行時にJavaScriptのエンジンSpiderMonkeyに対して、ccというオブジェクトを生成した後、Layerというプロパティを定義しています。その関係が図のこの部分です。

Layer部の拡大
Layer部の拡大

しかし、このままでは、cc.Layerというオブジェクトが生成できるだけで何もできません。そこで、内部では、C++側のCCLayerオブジェクトを生成し、JavaScript側のオブジェクトに関連づけしておきます。さらに、CCLayerに含まれるメソッドが呼び出された時に、CCLayer側の処理を実行する関連付けも同時に行っています。

関連付け部分
関連付け部分

これにより、cc.Layer.createなどのメソッド呼び出しをJavaScript側で行うことで、CCLayer::createメソッドが呼び出されるわけです。

オブジェクトの継承

さて、話を元に戻しましょう。this._super()をコメントにするとエラーがでてしまうのでしたよね?

jsbにおける、this._super()というメソッドは、特殊な意味を持ち、スーパークラスのメソッドを呼び出します。今回の場合は、ctorメソッド内で呼び出しているので、スーパークラスのctorメソッドを呼び出そうとしています。

jsbでは、C++などの言語におけるサブクラスの定義が出来るメカニズムが提供されており、それは、cc.XXXX.extendという形で実現することができます。1

サンプルコードの場合は、cc.Layer.extendとなっており、cc.Layerを継承したサブクラス、GameLayerを定義しています。 ctorメソッドは、オブジェクトの生成時に呼び出されるコンストラクタメソッドでこれをオーバーライドしているわけです。

つまり、GameLayerを生成した時点でこの(ctor)メソッドがオブジェクトの継承順に従って呼び出されるべきなのですが、JavaScriptは言語仕様的に、簡単に呼び出せません。それをjsbでは、this._super()メソッドを実装し、これを明示的に呼ぶことで解決しています。

ctorでは、最終的にJavaScriptオブジェクトとC++オブジェクトの関連付けを行う処理を実行しているため、this._super()を呼び出さなかった場合、スーパークラス側のコンストラクタが呼び出されず、この処理が実行されません。

そうなった場合、このGameLayerオブジェクトは、(ネイティブ)オブジェクトとして機能しません。それをユーザーにエラーとして表示するように、jsbの各メソッド内部では、引数に渡されたオブジェクトの有効性をチェックしています。今回はそこがエラーになっています。

this._super()メソッドを呼び忘れない

説明が長くなりましたが、今後jsbで既存のcocos2dのクラスを継承したクラスを定義するとき以下のことを忘れずに行うようにしましょう。

各オーバーライドメソッド内部でthis._super()を必ず呼び出す。

理解度テスト

this._super()のことを理解できたかどうかを確かめるために、サンプルプログラムを修正してみましょう。

問題

cc.Nodeを継承したPersonを作成し、オブジェクト生成時に

"Hello cocos2d-x jsb"

というログを出力するようにしてください。
ログは、cc.log("メッセージ")で出力できます。
そのオブジェクトは、GameLayer ctorメソッド内でオブジェクトpとして生成してください
(今回は生成するだけでよいです)

実行結果
実行結果

回答

正解プログラムコード

次回予告

プログラムをうまく修正できましたか?このエラーは、うっかりしているとよく遭遇するのでエラーの解決策として、仕組みの理解から説明しました。次回もjsbのお作法について引き続き説明していきます。


  1. 詳しくは、jsb_cocos2d.jsにextendの実装が記述されています。 

Cocos2d jsb

記事をリクエストする

関連記事

コメント