Cocos2d-x:アドフリくん(AndroidStudio編その2)

SDKの導入

前回からの続きです。今回はCocos2d-xで作成したカラのプロジェクト(HelloWorld)にSDKを導入します(いきなり本番は怖いですからね)。
 

libsフォルダの設定

マニュアルはp25から。libsフォルダはビルドしないと生成されませんが、ビルド前に作成してもOKです。なので作成して指示通りjarファイルをいれました(階層はproj.android-studio/app/libs)。

build.gradleの設定

マニュアルp25にはbuild.gradleの設定についても説明されています。ここでgooglePlayServiceの設定をしましょう。またbuild.gradleのcompileSdkVersion/buildToolsVersion/targetSdkVersionの設定がサンプルプロジェクトと異なっていたので、サンプルプロジェクトに合わせました。
adfuly02

classフォルダ内の設定

マニュアルp26でadfurikunフォルダをclass内にコピーしました。これについては特に問題はないと思います。

srcフォルダ内の設定

マニュアルp27でsrc内にjp一式を追加(これもフォルダ上で行う)しました。ここまでの処理でproj.android-studio/appフォルダ内は以下のようになるはずです。
androstudio01

Android.mkの設定

マニュアルp27にはjni/Android.mkの設定についても説明されています。これはサンプルプロジェクトからコピペしたほうが安心でしょう(マニュアルではリワード動画がp27でインターステイシャルがp33です)。

AppActivityの設定

AppActivityの設定は大変なのでサンプルプロジェクトからコピペしましょう。ファイルの場所は「app/src/org/cocos2dx/cpp/AppActivity.java」です(マニュアルではリワード動画がp28でインターステイシャルがp34です)。
adfuly3
 
 
 

広告設定

マニュアルp48〜49でAndroidManifest.xmlの設定をしますが、サンプルプロジェクトのAndroidManifest.xmlをコピペして必要ない広告を削除するほうが良いでしょう。あとp49の後半はversion.xmlの設定なのですが、よく分からなかったので設定しなかったのですが動きました。また注意点としてはSmaAdについてはp67でresフォルダの要素を追加することも忘れずに(数の赤ラベル)。 
adfulyres
 
 
 

広告を表示する

広告を表示する処理はiOSと共通です。AppDelegete.cppで初期化するのを忘れないでください。→参考:Cocos2d-x:アドフリくんの導入(iOS編その3)
 
 
 

cocosコマンドでビルド

あとはビルドして確認するだけです。compileだけしてAndroidStudioからrunでもOKです。

----------------------------------------
cocos compile -s ~/cocos2d-x-3.11.1/project/adfulyTest -p android --android-studio
cocos run -s ~/cocos2d-x-3.11.1/project/adfulyTest -p android --android-studio
----------------------------------------

とりあえずカラのプロジェクトには組み込めて動画広告が再生されるのを確認しました。あとは本番のアプリへの組み込みです(緊張する…)。
 
 

Cocos2d-x:アドフリくん(AndroidStudio編その1)

Eclipseは使わない

Eclipseの方が慣れているが、最新のgooglePlayServiceに対応できないためAndroidStudioへ移行しました(サポートも切れていますし)。利用するマニュアルはiOSと同様に「adfurikun_Cocos2dx_moviereward_manual_1_4.pdf」です。 
 

サンプルプロジェクトの起動

マニュアルp14の通りに必要なSDKを更新しました(下図はクリックで拡大)。
androidstudio

つづいてマニュアルのp17。AndroidStudioになってもEclipse同様にコンソールからのビルドが必要です(下の階層は各自の設定に従ってください)。

----------------------------------------
cocos run -s ~/cocos2d-x-3.11.1/project/AdfurikunSampleCocos2dx -p android --android-studio
----------------------------------------

いきなりrunするのではなくcompileだけしてビルドできるか確認するだけでもOKです。その後でAndroidStudioで読み込みRunしましょう。

----------------------------------------
cocos compile -s ~/cocos2d-x-3.11.1/project/AdfurikunSampleCocos2dx -p android --android-studio
----------------------------------------

問題がなければ実機上で起動されます(iOSの時と同様に広告の認証が済んでないと動画は再生されません)。ソースを変更した場合はeclipse同様に毎回compileが必要になります。
adfulycapture
 

次回はSDKの導入

続いてはiOSの時と同様にカラのプロジェクトにSDKを組み込みます。
 
 
 

Cocos2d-x:アドフリくんの導入(iOS編その3)

利用しない広告を外す

前回の続きです。
マニュアルp6の「パフォーマンス」で「動画広告は負荷が大きいので利用する種類は調整してください」的な事が書いてあります。ということで今回は以下のように5種類の広告に絞ることにしました。VungleとUnityAdsを使わなかった理由は、これらは動画を見てもユーザーがアプリをインストールしない限り利益が発生しないからです(単価は高いらしいけど)。Aplovinもこのタイプなのですが、1つくらいは試してみようと入れています。
adfuly

ということでVungleとUnityAdsの設定を外します。

importのコメントアウト

まずはマニュアルp83,94のADFMovieRewardCocosAdapter.mへのインポートをやめます。具体的には以下のようにimportをコメントアウトします。
adfuly2

関連フォルダの削除

続いてマニュアルp81,92の関連するフォルダを削除します。具体的には以下の2つのフォルダを削除しました。
adfuly3

Compile Sourcesの確認

上記の処理を行うとマニュアルp83,94のCompile Sourcesからも該当するファイルが削除されます。下の画像のようにMovieReward6001.mやMovieReward6006.mの項目がなくなります。
adfuly4

必要のないframeworkの削除

最後にマニュアルp82,93の処理で追加したframeworkを削除しようと思ったのですが、これらは全て他の広告で利用しているものと重複していたので削除してはダメ。
でもって、ビルドが通る事を確認(警告の数は前回と同じでした)。
adfuly5
 
 
 

広告を表示する

次にボタンを押したら動画広告を表示するようにします(マニュアルはp100〜)。マニュアルよりもサンプルプロジェクトを参考にしたほうが混乱しません(マニュアルにも「詳細」はンプルプロジェクトをご確認下さい…とあるし)。

AppDelegateでの処理

サンプルプロジェクトの「HelloAdfurikunReward.cpp」と「HelloAdfurikunReward.h」を確認すれば利用方法は分かると思います。しかし見落としがちなのはAppDelegate.cppにも処理を追加する点です。コメントがなくて分かりにくいのですが、4行目でのADFMovieReward.hの読込。40行目でのリワード広告の初期化。41行目でインターステイシャルの初期化をしています(インターステイシャルを使わない場合はコメントアウトしてOKだと思う)。尚、この処理はマニュアルでいうとp104の部分だと思います。
adfuly6

BGMやアニメの扱い

サンプルプロジェクトにもコメントが書いてありますが、動画広告を表示するときにはBGMやアニメを停止しましょう。

動画が表示されることを確認

色々とログが書き出されますが、サンプルプロジェクトと同じ内容のログならOK。この段階でiPhone版のアプリに組み込む手順は全て学べたと思うのですが、以下の理由で先にAndroid版でもビルドできるか確認することにしました。
 
 
 

実際に組み込む前にAndroidへの組み込みも確認

最後にサンプルプロジェクトと今回練習で作成したプロジェクトのフォルダ構成を確認したら結構違っています。私はAndroidのビルド設定をするときClassフォルダ内の全てを組み込むようにしているのですが、このファイル構成では色々問題が発生しそうなのでAndroid版でもビルドできるか確認しようと思います。

adfuly7

Cocos2d-x:アドフリくんの導入(iOS編その2)

SDKの導入(iOS)

前回の続きです。
いきなりアプリに組み込むのは怖いので、カラのプロジェクトを作って練習をすることにしました。マニュアルは引き続きadfurikun_Cocos2dx_moviereward_manual_1_4.pdfで、Xcode(iOS)への導入に挑戦していきます(P37〜)。

サンプルプロジェクトを参考に

前回動作確認をしたサンプルプロジェクトが無ければ途方に暮れていたと思います…。マニュアルと合わせてサンプルプロジェクトの構造を確認しながら導入するのがオススメです。

足りないファイルを補完しよう

p37から設定を開始し、p42で問題が発生します。p42ではADFMovieInterstitialNativeManager.mmとADFMovieInterstitialCocosAdapter.mのコンパイル設定をするように説明されていますが、このファイルはマニュアル通りに作業しても組み込まれません。
 
なのでサンプルプロジェクトを基に必要なファイルを手作業で追加することにしました。主にインターステイシャル系のファイルが抜け落ちています。良い機会だったのでサンプルプロジェクトと比較して足りなさそうなファイルを組み込みました。下図のようにサンプル(左)と同じ構成になるようにしました。
adfuly00

足りないファイルはサンプルのclassフォルダ内にあります(下図)。これでp42の設定ができるはずです。
adfuly01

Xcode8/iOS10対応

マニュアルp46の設定はサンプルプロジェクトのinfo.plistには存在しなかった。たぶん古いままなのだと思う。ということできちんと設定した(下図はp44とp46の設定を追加したinfo.plistの部分)。
adfuly02

とりあえずビルドに挑戦

まだ広告会社毎の設定をしていないのでビルドは失敗すると思うのですが、とりあえずビルドしてみました。以下のようにMovieReward6002.mで1つエラーが出ただけでした(もっとエラーだらけになると思ったのに)。
adfuly03
 
 
 

各アドネットワークの設定

続いては各アドネットワーク別の導入です。引き続きXcodeで設定していくのでマニュアルはP70からです。とりあえずサンプルプロジェクトと同じように全てのアドネットワークの設定をしたいと思います。

Applovin導入

P71:ここまでの操作で登録されているはずなので何もしなくてOK
p75:前回出ていたバンドルIDの警告はApplovinのだったのですね。
P76:ここまでの操作で登録されているはずなので何もしなくてOK
 

AdColony導入

P76:ここまでの操作で登録されているはずなので何もしなくてOK
p77:libz.1.2.5.dylibというライブラリが追加できない。ググってみたら今では拡張子が変わってlibz.1.2.5.tbdになったようだ。
参考リンク:How can i add libz.1.2.3.dylib to iOS 9.1 in Xcode 7?
 

サンプルプロジェクトと比較して設定した方が良いと思う

このあたりでマニュアルに沿った設定が面倒になり、サンプルプロジェクトと比較して必要な設定をする方針に変更。まずは「Compile Sources」を設定。サンプルプロジェクトよりファイル数は2つ少なくなります。画像はクリックで拡大されます。
adfuly04
 
次に「Link Binary with Libraries」の設定をサンプルプロジェクトと同じようにします。RequiredとOptionalの設定も同じにすることを忘れずに。練習用に作成したプロジェクトにはサンプルプロジェクトには存在しない「OpenGLES.frameworks」があるのですが、削除するのは不安なので残しておきました。
adfuly05
 
でもってビルドしたら通りました(警告数は24)。
adfuly06
 
 
 

各アドネットワークのメモ

Applovin(マニュアルp75)

・Applovinでは広告の読み込みに失敗したときに実行されるメソッドがある。
・バンドルIDは申請したのと同じにしないとダメ。

AdColony(マニュアルp80)

リンクが切れている。しかし、たぶんマニュアルp44の件だと思う。

UnityAds(マニュアルp84)

AppStore向けの署名を含んだバイナリでないとビュー内でのダウンロードに失敗する。
たぶん真っ当な処理。検証中に広告からのインストールなんてしないと思うし。

Maio

マニュアルに特記事項無し

Tapjoy(マニュアルp91)

ソースがマニュアルの記述と異なっている。デバッグモードの切り替えは引数で設定できるようになっているっぽい。変更しなくてOKだよね…。

Vungle(マニュアルp95)

これもUnityAdsと同じ、AppStore向けの署名を含んだバイナリでないとビュー内でのダウンロードに失敗する。
  
 

次回は…

マニュアルp6に「アドネットワーク数は、アプリの全体の負荷に応じて適時調整して下さい」とあるので、次回は不必要なアドネットワークを削る作業をしたいと思います。
さらにボタンをタップしたら動画広告ことにも挑戦したいです。

Cocos2d-x:アドフリくんの導入(iOS編その1)

動画リワード広告とアドフリくん

1年前から興味があったものの弾幕ゲームとの相性が悪いために導入しなかった「動画リワード広告」。しかし今回のアプリは育成要素があり動画リワード広告と相性が良いです(動画を見ると獲得Goldを5倍にする施策をします)。

ただ、この動画リワード広告は出稿数が少なく広告を頻繁に表示できないというデメリットがあります(気合いの入った動画広告を作成できるアプリメーカは少ないため)。そこで複数の広告社の動画をとりまとめて、広告切れが発生しにくくなるようなシステム(メディエーションというらしい)を提供する会社が現れました。世界的にはgoogleが有名ですが、日本ではアドフリくんが1強らしいです。→アドフリ君webサイト

利益の発生ポイント

バナー広告の場合はクリックされたときに開発者に利益が入る仕組みですが、動画リワード広告は大抵の場合は動画を見るだけで利益となります(ただしバナーより大幅に安い…)。また広告会社によってはアプリがインストールされたときに利益が発生するタイプもあるようです(これは利益が高いらしい)。
 
 
 
 

サンプルアプリの起動

アドフリくんの審査が通るとSDKやサンプルがダウンロードできるので、早速ダウンロード(Cocos2d-x用ver1.4)しました。ここではマニュアル(adfurikun_Cocos2dx_moviereward_manual_1_4.pdf)をベースに躓いた部分と対応策をメモしていきます。
 

cocos2dフォルダ毎コピー

まず13ページ目1-1(4)SDKサンプル導入で少し戸惑いました。サンプルプロジェクトのcocos2dフォルダに…とありますが、ダウンロードしたデータにcocos2dフォルダはありませんでした。ここは単純に他で作成したプロジェクトのcocos2dフォルダを丸ごとコピーでOKでした。ちなみに私が利用しているCocos2d-xのverは3.11.1で、アドフリ君では動作確認されていないものでしたが問題有りませんでした(今のところ)。
 
adfuly01

XcodeからAndroid用のファイルは除く

まずは慣れたxcodeでのビルドに挑戦。cocos2dお馴染みのproj.ios_mac内のxcodeプロジェクトをダブルクリックして開きます。しかし「jin.iniが見つかりません」的なエラーが表示されます。これはAndroid用のファイルなので必要有りません。というかAndroidフォルダはiOSには必要ないのでフォルダ毎削除しました(以下のようにiOSのフォルダだけでOK)。これでビルドが通りました。
 
adfuly00
 

サンプルプロジェクトのバンドルID

ビルドは通りますがログに以下のような警告が表示されます。しかし広告ID(マニュアルp12)が設定されていれば問題ないようでした(というか申請したBundleIDにしたらアプリが上書きされてしまいますし…テスト用のIDがあっても良いと思うのに…)。
adfulu006

申請後スグには確認できない

しかし所定の操作をしても広告が表示されません。これは各広告会社への申請が完了していないためでした。初めて利用するときは焦らずにゆっくり待ちましょう。
adfuly
 
 

広告が流れた!

広告の申請が完了したので、サンプルを再度確認。無事広告が流れました!。
adfuly02
 

次回はSDKの導入

いきなり完成しているアプリにsdkを導入するのは怖いので、カラのプロジェクトを作成しsdk導入の練習をすることにしました。
次回は、そのあたりをメモしようと思います。
 
 
 

Cocos2d-x:3.11.1のインストール

cocos2d-xのバージョンを上げるたびに同じことを書いているような気もしますが、忘れないように書いておきましょう。
 

コンパイルエラー(実機)

作成したばかりのプロジェクトは実機で実行するとがエラーとなってコンパイルできません。 これはPNGのメタデータに関する設定で修正できます。
→参考:png読み込み時にlibpng error:
xcode_cap_2
 

警告の削除

cocosでプロジェクトを作成すると警告がたくさんでます。これらはcocos2d_libs内の警告なので、cocos2d_libsのbuild setting にあるworning policiesの「inhibit all warnings」をyesに設定します。こうすることでcocos2d_libsで発生する全ての警告を抑制(inhibit)できます。
ポイントなのはcocos2d_libsの警告だけを抑制するだけで、ユーザーが生み出した警告は抑制されない点です。
せめて自分だけでも警告のでないコーディングを心がけましょう。
→参考:cocos2d-xによるビルド時の警告を消す

xcodeCapture

v3.6では以下リンクの処置だけでもOKだったような気がしましたがダメでした。上記を設定すれば以下の処理をする必要はありません。
→参考:Xcodeでサブプロジェクトのコンパイル警告の抑制

cocos2d-x:高頻度scheduleの問題

v3.11.1でも発生

以前記事にした「3.6だとOKだけど3.10でクラッシュする問題」ですが、v3.11.1でも発生しました(AndroidだけでなくiOSでも…)。しかも50fpsに設定しても「たまに」クラッシュしてしまいます。

update

scheduleではなくupdateにすると大丈夫なので、今後はupdateを利用していこうと思います。

scheduleを利用したい場合

どうしてもscheduleを利用したい場合は、thisの型を取得して比較し、目的のクラス(例えばEnemyBullet)でない場合はreturnしてthisを利用する前に処理を抜けるようにします(少々強引か…)。型を調べるのは以下のサイトが参考になりました。
→参考:Cocos2d-x v3:Nodeの種類を特定する
 
cocos2dの基本クラスは「N」で始まるようなので、以下のように処理を書きました。
———————————
if (typeid(*this).name()[0] == ‘N’){
 CCLOG(“error return”);
 return;
}
———————————
クラッシュの原因はthisが参照できずsetPositionなどでEXC_BAD_ACCESSになってしまうことなのですが、this自体はNodeとして値が取得できます。なので、この方法でthis(EnemyBullet等のクラス)が取得できず、ただのNode扱いになってしまう場合に回避処理を取ることができるのです(たぶん)。
 
 
 

Cocos2d-x:v3.10でのAndroid開発環境メモ

Android studioに挑戦-あきらめ

cocos2d-xはv3.7からAndroid studioに対応したらしい。eclipseは非推奨となり今後サポートされなくなるのでAndroidStudioへの移行が必要。
AndroidStudioのインストールは成功したが、Runするとエラーになってしまう。今回は時間がないので使い慣れたeclipse(luna)を使うことにした。
今振り返るとNDKの設定をデフォルトから変更すべきだったのかもしれない。
Android studioでのNDKの設定はprojectを開いている状態で、メニューのFile->project structureを選択し、表示されるウインドウの左カラムからsdk locationを選択する(下図)。
現状は画像のようにバンドルされていたデフォルトのNDKを利用しているが、Cocos2d-xの場合は少し古いNDKでないとビルドできないことが多いので
ASsdk
 

bash_profileの設定

bash_profileはmiで編集するのが便利。miは「不可視ファイルを開く」があるので。
cocos2d-x:v3.10をビルドできた設定は以下の通り(パス部分のみ抜粋)。
ポイントはNDKのバージョン。以下のように「r10e」をダウンロードしてきて利用した(現時点での最新はr11cでv3.6で利用していたのはr9d)。
SDKはAndroidstudioで管理しているsdkへのパスにした。
——————————————————————
export NDK_ROOT=/Users/designdrill/androidDev/android-ndk-r10e
export ANDROID_SDK_ROOT=/Users/designdrill/Library/Android/sdk
export ANT_ROOT=/Users/designdrill/androidDev/apache-ant-1.9.7/bin
——————————————————————
少し躓いたのはantの設定。これは上記のようにbinまでパスに含める必要がある
→参考:[Mac]Cocos2d-x開発環境構築

eclipseの設定

eclipseの最新版(最終版?)はmarsだがメニュー構成が結構異なるので、使い慣れたlunaを利用することにした。
sdkへのパスは現状eclipseにバンドルされたsdkを利用(下図)しているが、これはAndroidStudioの方に合わせた方がよいかもしれない(bash_profileもAndroidStudioのにしているし)?。sdkは同じURLから更新されるので問題ないと思うが、結構ファイルサイズが大きいし、各々でバージョンアップしなければならないので。
eclipse
eclipseのsdkの設定はpreferencesのAndroidから行う(上図)。
 
ちなみにAndroid SDKへのURLは現在Android studioへのリンクになっているが、Android sdkは単体でもダウンロードが可能(android-sdk-macosx:現時点最新はr24.4.1)。Android Stdioのサイトにある「Download Options」をクリックすると単体のandroid-sdkが置いてある場所に移動します(下図)。
macsdk

Nend広告の組み込み

まずはNend広告を組み込まずに実機プレイまで可能なことを確認。この段階でAndroid固有のバグがないかを確認する。
バグがないことを確認したらNend広告の組み込み。build_native.pyで生成されたフォルダなどは削除せずに上書きビルドする。
このときAndroidManifest.xmlにgoogle-play-serviceの設定があるとビルドを通らないので、これはコメントアウトしてeclipseで読み込んだ後に有効にする(たぶん私の環境設定の不備のためだと思う)。
あと今回躓いたのは以下の点!

Nendのバナー広告だけ出ない!

現時点で最新のnend_java(net/nend/NendModule:日付2015/10/16)だとbuild_native.pyが通らない。なので1つ古いnend_java(日付:2015/10/1)を利用してbuild_native.pyを通した
しかし、これだとバナー広告が表示されない(インターステイシャルは表示される)。なのでbuild_native.pyを通してから、eclipseに読み込む前にNendModule.javaだけを新しいファイル(日付:2015/10/16)のに差し替えた。するとバナーも表示された。
nend
そもそも最新のNendModule.javaがビルドを通らないのがいけない。またNDKのバージョンなどが関係しているのだろうか?
とりあえず上記の対応で安定して機能しているので良しとしよう。
 
 
 

Cocos2d-x:v3.6だとOK、v3.10だとクラッシュ

結論:100fpsとか無理だから!

 

弾幕ゲームの制作を始めた頃(Cocos2d-x v3.2)の問題

弾の移動処理はupdate関数内に記述していた。しかし弾の移動速度が微妙に揺らぐ(カクつく感じではなくsinカーブのような緩急がつく感じ)。人によっては気づかないレベルだが、見ていると気持ち悪くなる(乗り物酔いの感じ)。

schedule関数に切り替える

弾の移動処理をschedule関数内に記述し、実行間隔を1/60秒(60fps)に設定。しかしupdateと同じ症状。

100fpsに!!

scheduleの実行間隔を0.01秒(100fps)に変更すると揺らぎが無くなった!!
弾幕の光、弾幕の器、弾幕の器2の弾の移動処理はすべて100fpsで処理されている。
Android5への対応でCocos2d-xのバージョンを3.6に変更したが、100fpsの設定は変更無し。

100fpsでクラッシュ

弾幕の檻Android版からCocos2d-xのバージョンを3.10にアップ。実機でアプリがクラッシュ。iOSでもクラッシュするのでAndroid固有の問題ではない。
100fpsの処理を60fpsにしたらクラッシュしなくなった。そして3.2から苦しめられていた微妙な揺らぎも発生しない!
 
 

そもそも60fps以上を設定することが間違い

スマホの描画は60fpsが最大(ゲーミングPCのように120fpsとか無理!)だと思うので、100fpsで弾を移動させること自体が間違い。100fpsでの処理についてはずっと気になっていた。前回の記事(計算負荷を減らす)のなかでも問題にしており、揺らぎがギリギリ気にならない83fpsまで頻度を落としている。
今回iOS版(Cocos3.2:fps83)とAndroid版(Cocos3.10:fps60)の比較動画を作成したが、83fpsと60fpsに大きな差はない。やはり60fps以上の設定は無意味。でも以前のCocosでは気持ち悪い揺らぎが発生して、仕方なく無茶なfpsを設定

 
 

詳細

すぐにクラッシュするのではなく1秒くらい経過してからクラッシュ
クラッシュの直接の原因はschedule内でthisがspriteとして参照できなくなるため(下図)。
スクリーンショット 2016-05-11 0.00.47
 
正常な場合は以下のようにthisはspriteとして参照できている。
スクリーンショット 2016-05-10 23.59.38
 

その他

・fpsが高くても1秒は耐える。という挙動が気になったので、アプリでは58fpsと微妙に処理頻度を落とした。
・schedule間隔が0.0になっている場所があった(fps無限大!)しかし、ここではクラッシュしなかった(何故?)。
 ※計算式でschedule間隔を設定しており、その計算式が間違っていた。
 ※炎弾のアニメ処理で3.10で高速にアニメが再生され不審に思い調べて問題が判明。
 
 
 
 

Cocos2d-x:計算負荷を減らす

要約

・ルートの計算を避けてgetDistanceを使うのをやめる。
・座標系は回転させていないのでconvertToWorldSpaceを使わなくても何とかなる。
 
 

fpsの低下を検知して演出を変更する

今作成しているゲームは「弾幕の器」シリーズよりもたくさんの弾を表示します。そのため古い機種では60fpsを維持できなくなってきました。なのでfpsの低下が一定時間続くと「光の演出」をOFFにする処理を追加しました。fpsの測定はupdateの引数deltaで計算可能です。具体的には以下のようなコードを書きました。

--------------------------------------------------------------------
void GameScene::update(float delta){//----deltaには前回のコールからの差(秒)が渡される
 if (delta > (1.0/40)){//---fpsが40を下回った?
  fpsDelayCnt++;
  if (fpsDelayCnt >= 40){//----40fps以下の速度低下が約1秒継続した
   //---画質を落とす処理
   this->unscheduleUpdate();//---fpsのチェックはやめる
  }
 }else{
  fpsDelayCnt=0;
 }
}
--------------------------------------------------------------------

 

弾道の計算頻度

次は計算頻度の見直しです。これまでの弾の移動とあたり判定の処理は以下のように1秒間に100回の頻度で行っていました。60fpsだから移動頻度は1/60秒のハズなのですが「1/60だと微妙に速度が揺らぐ」感じがするのです。動きが各つくのではなく、sinカーブ的に速度が緩く揺らぐ気がするのです。

--------------------------------------------------------------------
this->schedule(schedule_selector(EnemyBullet::hitTest), 0.01);
--------------------------------------------------------------------

デザインにおける「モアレ」と似たような(周波数的な)現象なのかな?と思い、数値を微妙に変えていったのですが60fps界隈では違和感は消えませんでした。結局、違和感が気にならないレベルは以下のように0.012でした。少しの変更ですが%的には約16%(100fps→83.3fps)の負荷が減ります

--------------------------------------------------------------------
this->schedule(schedule_selector(EnemyBullet::hitTest), 0.012);
--------------------------------------------------------------------

 

あたり判定の再考

「弾幕の器」でのあたり判定は「丸弾は2点間の距離」と「矩形はベクトル的な処理」に分けていました。しかし今回の弾幕ゲームでは、すでにfpsを維持するのが難しいので「矩形はベクトル的な処理」は廃止します。つまり長方形の弾は出ません、十字型の弾が登場しますが、実は緑丸にしかあたり判定がありません!
d2
矩形のあたり判定については以下の記事を参考にしてください。重そうな処理でしょ?
→参考:弾幕ゲーム第2弾:矩形のあたり判定
→参考:cocos2d-x:当たり判定のすり抜け対応
 
 

getDistanceの利用をやめる

ということで、あたり判定の処理は「2点間の距離」のみになりました。Cocos2d-xでは2点間の距離を求めるメソッド「getDistance」があり、大まかには以下のようなコードになります。

--------------------------------------------------------------------
Point shipPos = spShip->getPosition();
float shipDist = shipPos.getDistance(this->getPosition());
if(shipDist < 10){//---弾と敵の距離が10より小さくなったら被弾
 //---被弾処理
}
--------------------------------------------------------------------

getDistanceは距離を求めるため「計算にはルートが含まれます」。しかし、あたり判定はルートを省略できるためgetDistanceを使うことを廃止し以下のように書き換えました。両辺を2乗した形です。

--------------------------------------------------------------------
sqrt(x^2+y^2) = distance;
 ↓
x^2+y^2 = distance*distance
--------------------------------------------------------------------

また、Y座標だけ先に計算して範囲外だったらX座標の計算を省略できるようにしました、以下のような感じです。

--------------------------------------------------------------------
//---まずは弾と敵のY座標の距離だけを算出
float ship_y = shipPos.y;float my_y = myPos.y;
float dist_y = ship_y - my_y;
float dist_y_abs = dist_y*dist_y;

if (dist_y_abs < 10*10){//----ルートするのではなく距離の方を2乗したほうが計算負荷は低い
 //----Y座標の距離が範囲内にある時だけX座標の計算をする
 float ship_x = shipPos.x;float my_x = myPos.x;
 float dist_x = ship_x - my_x;
 float dist_x_abs = dist_x*dist_x;
 if ((dist_y_abs+dist_x_abs)<(10*10)){//---ここでもルートではなく2乗
  //---被弾処理
 }
}
--------------------------------------------------------------------

 

convertToWorldSpaceを利用するのをやめた

砲塔は敵母艦内に配置されており自弾と座標系が異なるためconvertToWorldSpaceで座標を算出し直していました。convertToWorldSpaceの処理内容を確認すると「よく分からない3次のベクトル計算(座標系が回転していてもOKな感じの式)」があったので利用するのをやめました。今回は座標系は回転していないので加算のみで対応できるため自作した方が処理が軽くなります。大まかには以下のような変更です。

--------------------------------------------------------------------
Point fortLocalPos = spFort->getPosition();//---母艦内の砲塔の位置を取得
Point fortPos = this->convertToWorldSpace(fortLocalPos);//---グローバル座標に変換
--------------------------------------------------------------------



--------------------------------------------------------------------
Point fortLocalPos = spFort->getPosition();
Point fortPos = fortLocalPos + enemyShipPos - Point(center_x,center_y);
--------------------------------------------------------------------

enemyShipPosは母艦の座標(母艦はグローバル座標に配置されている)。Cocos2d-xでは画像の中心が原点なので、最後の項のように中点座標を引く必要があります。
 
 

古い機種でも遊べるようになったと思う

上記の配慮をしなかった時と比べると、体感できるほど処理が軽くなったよ。