弾幕の器2:モチーフ

弾幕の器のAndroid5対応が予想以上に時間がかかり、今週はプログラム的な進展がないので、続編のデザインの一部を公開。
 

続編のタイトル

続編のタイトルは迷ったのですが「弾幕の器2」とすることにしました。元々は「弾幕の座」というタイトルを考えていたのですが、予想以上に「弾幕の器」の反響が良かったためナンバリングに変更です。
 

星座がモチーフ

弾幕の器は旧日本海軍をモチーフに艦艇を命名しましたが、続編では星座がモチーフになります(なので弾幕の座というタイトルが候補だったわけです)。
アイデアノートは以下の様な感じで、艦艇のクラスは星座名になっており、各艦艇名は星座に属する星の名前になっています。
———————————–
●アクイラ級(わし座)Aquilae
出力系が改善された駆逐艦。機動力が高く高出力な
砲塔も搭載できる。しかし搭載スペースが少ない。
・アルタイル(Altair)-一等星
・アルシャイン(Alshain)
・タラゼド(Tarazed)
・デネブ(Deneb)
・ベゼク(Bezek)
———————————–
●キグナス級(はくちょう座)Cygni
アクイラ級を大型化した駆逐艦。大きさのわりに
機動力も高く、出力系もさらに増強されている。
・デネブ(Deneb)-一等星
・アルビレオ(Albireo)
・サドル(Schedar)
・ギエナ(Gienah)
・V1489(V1489)-2012年現在の最大の恒星
———————————–
ちなみにデネブという名前の星は結構あり、上記でもわし座とはくちょう座に存在しています。しし座のデネボラもデネブの派生です。意味は「しっぽ」という意味なのであちこちにあるわけです。くじら座はしっぽが長いのでデネブが3つあります。
あと、みずがめ座の星の名前は特徴的で幸運だらけ。→参考:wikipedia「みずがめ座
 
艦艇のデザインも星座をイメージして以下の様な感じになっています(まだ確定ではありませんが)。弾幕の器には無い左右非対称な艦艇も登場。※クリックで拡大
enemy
砲塔は少し小さくしました。あと砲塔が1種類増え、強力なクラスター弾を発射する予定です。空母は廃止するので小型機は登場しません。空母の代わりに要塞のカテゴリが追加されます。
 

ちなみに弾幕の器のモチーフは

弾幕の器は「艦これ」ブームに便乗しようとしたわけではありません。往年の名作で「ボスは旧日本海軍の艦艇で砲塔を破壊すればクリア」というカプコンのシューティングゲーム「1943」がモチーフになっています。
本当は実在する艦艇の名称を付けたかったのですが、4x4x5のメニュー構成には合わないため架空の艦艇名にしました。ちなみに以下の様な命名則になっています
————————- 
・駆逐艦:天候に関連する名称(雨型/雲形/風型/雪型/雷型)
————————- 
・巡洋艦;水(海/川)に関する名称(川型/波形/潮型/霧型/島型)
島型は戦艦にちかいので陸地の要素も加えて島型になりました。
————————- 
・戦艦:陸(地名)に関する名称(石型/地型/山型/社型/国型)
石型は鉱石の名前。地型は昔の地名。社型は神社の名前、国型は日本の昔の名称。
————————- 
・空母:架空の動物(虎型/亀型/鳳型/龍型/神型)
方向を守護する白虎/玄武/朱雀/青龍+神様。
————————- 
続編も旧日本海軍風にしようとも思ったのですが、神様まで出してしまったのでやめました。続編の最強カテゴリは、大きすぎて分割された「アルゴ船座」の予定です。
 
 
 

「弾幕の器」のAndroid5対応

Android5への対応

先程Android5に対応した弾幕の器のバージョンをアップしました。ゲーム内容に変更はありません。Android4.xでもGalaxyNoteだけはクラッシュが頻発すると報告があるのですが、これも直っていたら良いなぁと思いつつ実機がないため確認することはできていませんでした。
 
Android4.xにかかわるバグも少し修正。
————————————————
・被弾時のクラッシュ修正(ゲームオーバーと同時にクラッシュ)
自機が破壊され存在していない時に当たり判定のルーチンに入ってしまうことがあり「自機がないよ!」とエラーになる事がありました。何故、想定外のルーチンに入るのか分からないのですが、チェックを2重にして対処。

・ver3.6でのみエラー
Cocos2d-xのver3.2ではエラーにならなかった処理がver3.6だとエラーになるので修正(記事後半にある型指定の部分)。
————————————————
修正できていない既存のバグ
————————————————
iOSでも発生しているクラッシュで。ゲームを開始する時や、ゲーム終了後に「もう一度」ボタンをタップした時にクラッシュ。
————————————————
以上。

 

自分用のメモ

この対応は先週末に完了させる予定でしたが手間取って本日までかかってしまいました。なのでメモを残すことに。iOSのデータは保険として修正せずに残し、Android版の方のみ移行処理をすることにしました。

・cocos2d-x(v3.6)で新規にプロジェクトを作成
・まずはXcodeで動作確認をするためClassや必要素材をコピーしてきて組み込み。
———————————–
v3.6ではサウンド機能を利用する時に「SimpleAudioEngine.h」のincludeが必要なので追記。ソースの変更はこれだけ。
———————————–
・xcodeでの動作は問題なく完了。

↓しかしメインのAndroidで躓く

・jni/Android.mkを書き換えてmakeするファイルを追加
・build_native.pyを実行してeclipseに組み込むデータを作成する

しかしエラーとなり読み込むべきデータが生成されない

一度諦め、過去に作成したnend広告の確認データでbuild_native.pyを試す。

しかしエラー。以前は問題なかったのに…

さらに諦め、新規にプロジェクトを作成してbuild_native.pyを試す

問題なくデータが完成

jni/Android.mkを書き換えてbuild_native.pyを試す

問題なくデータが完成。原因はNendか…

Nend広告のSDKが6/17に色々バージョンアップ(iOS/Android/Cocos2d)されているのでダウンロードしたけれどXcode6用のため利用せず。

これまで利用してきたverのNendを組み込む

build_native.pyを実行するとNend関連のエラー(undefined reference to)

試しにエラーとなったNend関連の処理をコメントアウト

build_native.pyが成功した(すごく短時間で完了)。

コメントアウトを解除し、ClassフォルダにNend関連のcppファイルをいれる。
※これはeclipseの段階で読み込むものと思っていた…

build_native.pyが成功した。

 
ここで再度、弾幕の器をCocos2d-xのv3.6へ移行したプロジェクトを試す

まずNendを全て外したファイルを作成しxcodeで正常起動を確認

build_native.pyを実行するとエラーが1件
EnemyDest.cppのデータを記憶する仕組みの型指定がエラー

修正:cocos2dの最新マニュアルで確認
——————-
(旧)long size = 0;
(新)ssize_t size = 0;
——————-

build_native.pyが成功し、Eclipseに読込むデータが作成された
しかしビルドの段階でエラー

なんとなくビルドエラーはeclipseで修正する様な気がするので
Nendを再び組みbuild_native.pyが成功するか確認。

build_native.pyが成功し、Eclipseに読込むデータが作成された
が、やはりビルドの段階でエラー

とりあえずeclipseに読み込む。

Eclipseでも問題

Eclipseを開くと、過去に問題なかったプロジェクトにエラー表示が付いている。前回v3.6を試した時には何も問題なかったのに何故?何も変更していないと思うのに…

以下のサイトを参考に環境設定でNDKの再設定をしてcleanを実行したらエラーが消えた。
→参考:cocos2d-xのAndroidプロジェクトをビルドする方法について

ビルドは成功し実機での起動も確認。しかしNendが表示されない。
単純にNend設定はしわすれていた。Nendの表示に必要な手順をマニュアルに従い行う。

問題なくNendの表示ができた。

念のためアプリを削除し、インストールから全艦制覇しながら問題が無いか確認。

問題はないようなのでアプリを登録。
 

バージョンコード

Androidのバージョン設定にはversionCodeとversionNameがある。versionCodeはgoogle内でのアプリ管理に利用されversionNameはユーザーの目にするバージョン番号。
引っかかったのはversionCodeは整数でないといけない点。今回は4.1としたかったが、それはできない。次から以下のサイトの方と同じ様に管理しよう。
→参考:android:versionCodeの最大値+管理しやすい設定値
——————-

android:versionCode=”41″
android:versionName=”4.1″
——————-
 
メモ終わり
 
 
 

菱形のあたり判定


 

対惑星レーザーの拡張

6月中にオーバーライドを習得すれば良いと思っていたのですが、大まかに習得できたので続編の制作に本格的に入ろうと思います。まずは簡単そうな対惑星レーザーの拡張作業から。
今回のアプリでは対惑星レーザーの長さを制限してビームサーベル的な攻撃を追加するので新たにレーザーの素材を作成し、それに適用する当たり判定の仕組みを追加しました。
 

菱形のあたり判定

これまでの対惑星レーザーの当たり判定は矩形で、長さを制限しても使い回すことは可能でした。しかしC言語を学ぶという目的もあるので、新しく菱形のあたり判定を持つレーザーにしたかったのです。
矩形の場合はスプライトの4隅の座標を利用してヒットエリアを構成しましたが、菱形の場合は各辺の中点を利用するようにします。しかしレーザーのグロー部分には当たり判定を付けたくなかったので、幅の判定は半分にしました。
というわけで動画のようにグロー部分に触れても被弾しません(被弾すると音が鳴るようにしています)。スプライトの大きさに合わせて計算されるので、将来的には対惑星レーザー以外にも利用できそうです。
 

すり抜け

ゲームの処理は60fpsなので0.1秒(6f)で横幅(640px)を移動すると、1fあたり100px移動することになります。つまり100pxの飛び飛びの移動。ということで動画の後半のように高速で操作するとレーザーをすり抜けることになります。
これは弾幕の器にも存在していた現象で、対処するためには自機の導線と敵弾の導線が交わるかを確認する必要があります。しかし、それは処理負荷が高く弾幕の密度を濃くできなくなるので、今回も無視していきます。
 
 
 

cocos2d-x:オーバーライドを学んだ

間違った思い込み

継承について曖昧知識しかないため、間違った思い込みをして遠回りしてしまいました(今も正しく理解できているのか不安ですが…)。今週、やっと継承を利用した構成で通常砲塔とレーザー砲塔を作成できました。
弾幕の器の攻略動画のリリースが完了したら、続編の進捗動画をリリースするようにしたいと思います。
 

基底クラスから派生クラスのメソッドを実行したい

基底クラスと派生クラスを利用しての弾幕ゲーム作成を進めているのですが、いきなり躓きました。基底クラスから派生クラスのメソッドの実行方法が分かりません。起動時間の処理はすべての砲塔に共通なので基底クラスに記述。攻撃方法は砲塔毎に異なるので派生クラスに記述。
————————————
・基底クラス:起動時間が終わったので攻撃開始
   ↓
   ↓どうやって実行するの?
   ↓
・派生クラス:攻撃開始の処理
————————————
派生クラス毎にキャストすれば実行できるのですが、そもそもが派生クラス毎にキャストしたくないから基底クラス/派生クラスを学び始めたのです。なのでキャストして利用するのは多分間違いだと思う。
 

テンプレートっぽい?

クラスに疎いので検索キーワードも良く分からず時間がかかってしまいましたが、オーバーライドという仕組みを利用することが分かりました。ポイントは派生クラスで利用するメソッドも基底クラスで定義しておく点です。基底クラスで定義したメソッドを派生クラスで上書きするからオーバーライドというらしいです(たぶん)。
 
これに利用するのがvirtual指定子です。基底クラスで「仮」に設定しておくから「virtual」なのかな。以下のサイトが参考になりました。必ず上書きが必要な場合は純粋仮想関数を使うと良いのだそうです。
→参考:ロベール先生:仮想関数
→参考:オーバーライドと仮想関数
 

メモリの解放

私の勘違いは、派生クラスを作成すると基底クラスのオブジェクトが作成され、それを派生クラスのオブジェクトが内包している(つまり2つのオブジェクトが存在している)というものでした。ですが実際は1つで基底クラスをベースにした派生クラスのオブジェクトが1つだけ作成されているのです(たぶん)。
 
Cocos2d-xではautoreleaseメソッドを利用することでメモリ管理を「おまかせ」にすることができます。砲塔作成に利用している基底クラスは単独では利用しないので、派生クラスにだけautoreleaseメソッドを利用すれば良いハズ。それでメモリリークしなければ私の理解で正しいような気がする(たぶん)。
 
 
 

クラスの継承について試行錯誤。とランキング

<自分用のメモ>
 
私が長年利用してきたActionScript2やJavaScriptはプロトタイプベースの言語で、Cocos2d-x(C++)はクラスベースの言語。「弾幕の器」は勢いで制作したため上手くクラスを活用できていないので、今週は少しクラスの学習を進めた。

継承の活用

砲塔は4種類あるがクラスは完全に独立している。そのため「攻撃開始」や「ダメージ処理」の共通の処理を各々に記述しており効率が悪い。また同じメソッドを実行するにも以下の様に砲塔のクラス別にキャストしなくてはならず不便(実際は砲塔の種類毎にif文で分岐させるので、さらに複雑になってしまう)。
——————–
//small fort
auto spEnemy = (SmallFort*)spFort;
spEnemy->attackStart();
——————–
//shield fort
auto spEnemy = (ShieldFort*)spFort;
spEnemy->attackStart();
—————————
なので今回は砲塔に共通のメソッドを持つ基底クラスを作成し、そこから各砲塔のクラスを派生させるようにする。
今回は基底クラスとしてFortCoreを作成し、各砲塔のクラスを派生させる。以下のソースはFortCoreを基にシールド砲塔のクラスを作成している。
—————————
class FortShield: public FortCore{
 //処理
};
—————————
結果として最初のソースは以下の様に共通のFortCoreでキャストすれば砲塔の種類にかかわらず共通のメソッドを実行できるようになる。
—————————
auto spEnemy = (FortCore*)spFort;
spEnemy->attackStart();
—————————
この辺りのノウハウは結構深そうなので今後も精進しよう。
 

階層の指定にrootを使わない

検索でゲームの作成について調べると、特定のスプライトをroot(シーン)から辿ってしていするケースが良くある。しかしトランジションを利用する場合はシーンが複数存在し特定できずエラーになる。なのでrootから辿ってスプライトを取得するのはやめたい。
———————————
scene/layer/SpriteBatchNode/自弾のスプライト
scene/layer/敵のスプライト
———————————
弾幕の器での自弾と敵の階層は上記の様になっています。弾幕の器では自弾のスプライトから敵のスプライトへのパスは以下の様に記述していました。
———————————
auto nowScene = Director::getInstance()->getRunningScene();
auto gameLayer = (GameScene*)nowScene-> getChildByTag(tagGameLayer);
auto spEnemy = (EnemyDest*)gameLayer-> getChildByTag(tagEnemy);
———————————
しかし今回は以下の様に記述します。簡単なのですがSpriteBatchNodeの存在を忘れておりgetParentを2つ利用することに中々気がつけませんでした。
———————————
auto gameLayer = this->getParent()->getParent();
auto spEnemy = (EnemyShip*)gameLayer->getChildByTag(tagEnemy);
———————————
ネットではスプライトの取得にrootから辿っているものが多いのですが何故なのだろう?
 

GooglePlayランキング

GooglePlayで「弾幕」で検索したら「弾幕の器」が2番目になっていた。
device-2015-06-07-231614
ダウンロード数は圧倒的に少ないのに何故上位に位置できるのか調べるたら、ダウンロード数だけでなく「起動率」も影響しているらしいとのこと。
→参考:Google Playの人気アプリからランキングロジックの実態に迫る!!
ちなみに「弾幕の器」のダウンロード数と所持数は以下の様な感じ。相変わらず半分以上の方がアプリを削除..。
スクリーンショット 2015-06-07 23.25.10
 
 
 

Nexus7の動画キャプチャ

戦艦「扶桑」の攻略動画

弾幕の厚い艦艇ではiOSシミュレータでは処理が追いつかずfps落ちしてしまい、正確な攻略動画が作れません。ということでAndroid4.4から利用できる動画キャプチャを利用しました。60fpsでのキャプチャができたのですがyoutubeにアップしたら30fpsになっていた。720p以上でないと60fpsにはできないのかな?

screenrecordで画面を録画

参考になったのは以下のサイト。あと色々躓いたので補足。
→参考:screenrecordで画面を録画する方法

adbコマンドを利用できる場所

screenrecordを利用するためには、ターミナルでadbコマンドを利用できる階層に移動しなければなりません。私の場合はeclipse(luna)フォルダ内のsdkフォルダ内のplatform-toolsフォルダまで降ります(このフォルダ内にadbファイルがあります)。
—————————————
eclipse/sdk/platform-tools
—————————————
 

USBハブに注意

参考にしたサイトではadbのdeviceコマンドを利用して利用できるデバイスを確認しているのですが、私の環境ではNexus7が認識されませんでした。調べた結果原因はUSBハブのようで、直で繋いだら認識しました。
 

ギャラリーで確認

私もサイトに合わせてsdkcardという階層に動画を保存しました。動画の確認はギャラリーからできます。他にも「ESファイルエクスプローラ」というのも良さそうです。以下の動画で説明してる方も利用していました。
→参考:youtube「How-to Record Android Screen on a Mac
 

サウンドには非対応

残念なことにサウンドをキャプチャすることはできません。
 

転送先

pullコマンドはadbシェルでは利用できないのでexitコマンドで抜けてbashに戻りましょう。pullコマンドは転送先の場所を省略することができました。省略した場合はplatform-toolsフォルダ内に保存されます。ユーザーのrootではないことに注意してください。