× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。 |
cocos2d-xで、こんなエラーがでるときがある。
QuadCommand::init() 関数で、 glProgramState が null になっている。 これは、Spriteの初回draw()で発生する。 原因でよくあるのは、Sprite::init() が呼び出されていないとき。 Spriteクラスを継承して独自クラスにしたとき、 init()の中で
を忘れていないかチェック! PR |
やることは大して変わらない。
まず、ダウンロードページへ行く 最新のバージョンをダウンロードしたら解凍。 cocos2d-x-*.* という名前のディレクトリができる <cocos2d-x-*.*>/README.md に基本的に書いてあるが $ ./setup.py $ source ~/.bash_profile $ cocos new MyGame -p com.your_company.mygame -l cpp -d NEW_PROJECTS_DIR で作れる。 |
cocos2d-xには、グローバルZ値を設定できる。
これによって、親子関係に依らず表示順序を設定できる。 グローバルZは、設定したそのノードだけに効く。 例えばノードAの子ノードBにグローバルZを設定し、一番手前に表示したとする。 ノードBの子ノードCがあったとき、ノードCは、ノードBより手前には表示されない。 ノードAの子として通常のローカルZによって描画順序が決定される。 ノードCをノードBより手前に表示したいときは、ノードCにもグローバルZを指定する必要がある。 なお、グローバルZは、値が小さい方が手前に表示される。 この点、ローカルZと逆になっている。 なぜこんなことになっているのか…。 ちなみにdouble型。 さて、グローバルZが子ノードに伝播しないと、 Labelが困ったことになる。 Labelは内部的にSpriteを子ノードに持っているため、 label->setGlobalZ() を設定しても、実際の文字にはグローバルZの値が効かないのだ! 参考 大変困る話だ。 表示文字列が決まっているなら、文字全体を一枚のテクスチャで作ってしまっておけばSpriteで表示するといった手で逃げられるが。 |
以下のコマンドを実行する
$ cd <eclipseのworkspace> $ cd .metadata $ find . -name .markers -exec rm {} \; $ path/to/adt-bundle-mac-x86_64-YYYYMMDD/eclipse/Eclipse.app/Contents/MacOS/eclipse -clean -refresh 参考 |
cocos2d-xでandroidで、同じBGMが2度目以降再生されないバグがある。
(cocos2d-xトップディレクトリ)/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxMusic.java の中。 stopBackgroundMusic() のあと、同じファイルで playBackgroundMusic() すると音が鳴らない。 結論言うと、 prepare()をしていないから。 cocosの音声周りの実装は、SimpleAudioEngineを介して、Cocos2dxMusic.java を呼び出している。 Cocos2dxMusic は、メンバにAndroidSDKのMediaPlayerを保持し、これを操作している。 初回のplayBackgroundMusicは、createMediaPlayerメソッドを実行し、内部で mediaPlayerのインスタンス化、 setDataSource prepare setVolume を行っている。 その後playを実行し、音が鳴り始める。 さて、2回目にplayBackgroundMusicが呼ばれたとき。 直前に鳴らした音声の情報はmediaPlayerの中に残っており、(stopBackgroundMusicを実行しても、stopするだけでreleaseはしていない)、同ファイルだった場合は初期化処理を丸ごと飛ばす。 ここが問題。 このとき、本来実行すべきprepare()が抜けているのだ。 そこで、同ファイルのplayBackgroundMusicのとき、 prepare seekTo(0)…曲の先頭に移動 を行うようにした。
try{ this.mBackgroundMediaPlayer.prepare(); this.mBackgroundMediaPlayer.seekTo(0); } catch (final Exception e) { Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e); } } : これでOK。 ちなみにlibcocos2dxプロジェクトのjavaファイルを書き換えてビルドすれば ゲームプロジェクトにもちゃんと反映される。 |
デバイスによって画面の縦横比は違う。
これをどう対応するかというと、 AppDelegate.cppの bool AppDelegate::applicationDidFinishLaunching(); 関数の中で、以下の記述をする。 glview->setDesignResolutionSize(SCREEN_WIDTH, SCREEN_HEIGHT, ResolutionPolicy::SHOW_ALL); ここで、SCREEN_WIDTH, SCREEN_HEIGHTは自分で決めた値。 この値でcocos2d-xは画面を作る。 ゲームの実装部分は、この画面サイズと見なして作ればいい。 このサイズはいわば仮想画面のサイズで、デバイスの画面サイズとは違う。 この2つの画面をどう合わせるかが第3引数での指定になっている。 以下、指定できる値を列挙。
デフォルトはEXACT_FITになっている。 ぴったり描画するのは良いのだが、縦横比が変わるのはやはりよくない。 SHOW_ALLを使うのが良いと思う。 |
Androidアプリを作るときは、
必要に応じてスレッドを使いながら実装しないといけない。 とくに描画周りの処理を行うなら、必ず runOnUiThread の中に実装する。そうでないとすぐ落ちる。 cocos2d-xで動かしている場合、 mainLoopから呼び出される Layer::update() メソッドは、描画スレッドの内部であるようで、描画処理(リソースの読み込みやラベルの表示等)をしてもよい(当たり前。いつもそうしてる) だが、たまにupdate()でないところから描画処理を呼び出す流れになる場合がある。 例えば ・JNI経由でJavaからC++側を呼び出したとき ・・アラートのコールバックからゲーム側を呼び出す ・・シェア結果のコールバックからゲーム側を呼び出す ・・など ・AppDelegateの中から呼び出す ・・applicationDidFinishLaunching ・・applicationWillEnterForeground ・・など ・RootViewControllerからゲーム側を呼び出す ・AppControllerからゲーム側を呼び出す など こういうとき、描画処理を行うと、 フリーズ(描画スレッドの停止。タッチには反応し、音楽も鳴るなど) 表示くずれ などの現象が起きる 上記のような流れのときは、フラグを建てるだけにしておいて、 実際の描画処理はLayer::update()からフラグをチェックして行う のように実装する。 |
Qiitaのまとめ
修正した結果のファイル LINEツムツムとかも動かなくなったらしい Eclipseにおいては、cocos2d-xは外部ライブラリとしてリンクしているので、 修正する場合は、外部ライブラリのソースを書き換える。 ゲームディレクトリに内包されているほうのソースではない。 外部ライブラリのソースを変更し、外部ライブラリをビルドしてから ゲームのプロジェクトをビルドすると、cocos2d-xへの変更が反映される。 |
SNS周りの注意点
[twitter] iOSはSocialFrameworkですぐできる Androidは、Intentを使えば早いが、それだと投稿の成功・失敗が取れない。 インセンティブを付与したいときには、Twitterにアプリ登録をして、IDその他を取得。twitter4jを使ってOAuth方式で呼び出す 初回は認証を受ける処理に入るので、フローが変わることに注意。 認証用のIntentに飛ばすためだけのActivityを作ったりもする。 認証をキャンセルしたときに落ちたりもするので注意。(intent.getData().getQueryParameter("oauth_verifier”); が null になった場合、処理を続行させると落ちる) [facebook] iOSはSocialFrameworkですぐできる Androidはかなり面倒。Intentで飛ばすだけならいいが、やらないことも多い [LINE] LINEは画像と文字列を同時に投稿できない。スクショなど画像投稿系はLINEを外すことも多い 成功・失敗の判断ができない。ボタンを押した時点でインセンティブを付与してもいいが、そもそもアプリが入ってないときとかはさすがに付与しないよう注意 [iOS] 該当のアプリがインストールされていない場合、どうする? 投稿完了時にアラート表示する? スクショを撮るなどするとき遅いかもしれないので、インジケータを出す [Android] 該当のアプリがインストールされていない場合、PlayStoreのページに飛ばす。PlayStoreもインストールされてないときは、ブラウザで該当のページに飛ばす 投稿完了時にtoast表示 スクショを撮るなどするとき遅いので、ProgressDialogなど出す cocos2d-xの場合、シェアコールバックでそのままゲーム側の処理を行うべきでない。リソース周りへのアクセス等すると落ちる →フラグを立てるだけなどにしておいて、処理はメインループで行うのがよい。 |
cocos2d-x。
ActionManager::addAction()でEXC_BAD_ACCESS例外で落ちた。
こんな感じ。 (このスクショは別の件で起きたものだが、原因は同じ。いつもだいたいこういうコールスタックで落ちる) thisがnullptrになっているとかではない。 なんだろう?と思ったら、呼び出し元の
のnodeをaddChildしていなかった。 ので、メインループが1週したときにメモリが破棄された。 破棄されたがnodeポインタは破棄されたところをさし続けていて…というパターン。 簡単な話だが、nullptrになるわけではないので気付きにくいのはなんとかしたい。 |