たつぷりの調査報告書

博士後期課程(理学)の学生が趣味でUnityやBlenderで遊ぶブログです。素人が独学で勉強した際の忘備録です。

自作音ゲーをiphone向けにビルド

こんにちは。過去何度かにわたって「UnityでMIDIを使ったリズムゲームを作り、電子ドラムで操作する」ことを試みてきました。この記事は以下の記事の続きです。

tatsupuri.hatenablog.com

上の記事では、iOSアプリとして実際にビルドする部分は特に何も書きませんでした。今回はこれまで作ってきたプロジェクトを実際にビルドする部分について書きます。一つ一つは小さな問題なのでまとめて記事にしました。

なお、この記事で書くのは特殊なケースだったり常識的なことだったりするので、ほぼ備忘録のつもりで書いてます。

iOS向けにビルド

今回の目標はこれまで作ってきたゲームをiOSバイスで動くようすることである。そのためにiOS用にビルドして手元のiphone8で実機テストする。 iOS向けにビルドするときは、まずUnityでビルドが行われて、Xcodeプロジェクトが作成される。次にXcodeでのビルドがうまくいくと実機に転送できるという二段構えである。

今回はどちらのステップでも問題が起きた。

Unityでビルドできない

基本的にUnity Editor上では正しく動作していたのでビルドを試みたが、ターゲットプラットフォームに関係なくUnity上でビルドが通らなかった。これは以下で説明するようにUnity Assembly Definitionに関する問題が生じていた。

Unity Assembly Definitionの問題

今回MIDI周りのプログラムの一部はGitHubで公開されているプロジェクトを改造して利用している。そこでは、これらのプログラムはUnityの拡張Editor用として用意されていた。そのため、これらをゲームそのものに利用しているとビルド時にエラーが起きるよふうだ。

そもそも全くこの辺りの制御をどうやっているのか知らなかったので、とりあえずファイルをパラパラみてみた。すると.asmdefファイルというものがあった。これが原因だと考えて、Unity Assembly Definitionについて調べた。

基本的にUnity Assembly Definitionは、「C#のビルドファイル(アセンブリ)を分割して出力する」ことができる機能である。こうすることでコンパイルの高速化や、マルチプラットフォーム向けの開発など様々な利点があるようだ。

確かに.asmdefをインスペクターで確認すると、Editorで動かす時にしか機能しないようになっていた。

よって、Unityでビルドをするためには利用したファイルの参照関係を正しく理解して整理する必要がある。しかし今回はサボって以下のような手順をとった。

デフォルトでは全て、Assembly-CSharp.dllに紐づく。今回は、MIDIを読み込んでノートを生成する部分に関与する部分のスクリプトを持ってきて、それらをまとめてあたらしいディレクトリの中においてAssembly-CSharp.dllにビルドさせる。それ以外の今回使っていないスクリプトは消去した。

対処療法的だがとりあえずこれでUnityでビルドが通り、Xcodeプロジェクトが作成された。

Xcodeでビルドできない

次にXcodeでビルドが開始される。まず、iOSのネイティブプログラムを使うために書いたプラグインObjective-C++)のコンパイルはこの段階で行われる。今回は、プラグインのコードは正しいかったが以下のようにCoreMIDIに関してのエラーが出た。

CoreMIDI周りのエラー

ビルドをする際に、「CoreMIDI周りのクラスが未定義である」と言った旨のエラーが出ることがあった。これは、CoreMIDIフレームワークがプロジェクトに追加されていないことが原因である。(なぜ手動で設定しないといけない時とそうでない時があるのか筆者は理解していない。)

これは次の図のようにBundele Settingからフレームワークを手動で追加すれば解決する。 f:id:Tatsupuri:20201129165621p:plain

Xcodeでビルドが通ったのにアプリが開けない

以下の記事に対処法が書かれているが、これを読む限り無料でできる範囲の開発だと、3つまでしかアプリを入れることはできないらしい。確かに、ビルドした時点で4つ目だったのでこれに引っかかったようだ。

iOSアプリBuild時に「Unable to install "アプリ名"」と表示されるがXcodeの設定で解決 - Qiita

結局、自分は以下のようにした。Window > Devices and Simulators から接続しているデバイスの情報を取得。するとそこに入っている開発中のアプリ一覧があるので不要なものをここから削除した。

この上でビルドすると今度は実機にインストールされた。

インストール後に起きた問題

アプリが起動したのにゲームが始まらない

無事、実機に転送されたのでめでたいと思って早速確認したら、アプリが起動するのにゲームが始まらないと言う問題が起こった。

より正確に述べると、スコアなどは正しく表示されているのでゲーム自体は開始され、少なくともStart()関数くらいは読まれているらしい。つまり問題はノートの生成(note generator)がうまくいっていないことになる。

そこで、Xcodeでログを確認すると、「midiファイルが見つからない」旨のエラーが出ていた。今note generatorは、読みこむMIDIファイルはpathの直打ちで指定していた。このパスがiphoneと違うのは当然のことである。そこで正しいパスを設定する。

実際Unityでは様々なプラットフォームに対してパスを指定する方法が用意されており、以下の公式ドキュメントが参考になる。

Unity - Scripting API: Application.dataPath

なので早速その場所を指定してやろうと思ってxcodeのプロジェクト内で検索をかけてみたがMIDIファイルが見当たらなかった。 実は、通常Unityではビルドの際様々なファイルをエンコードしてしまい、今回のように楽譜のデータをその都度読み込みたいと言うように明示的にファイルを指定したい時は都合が悪い。

そこで、StreamingAssetという特別なディレクトリを用いる。これを使うと、基本的にこの中のファイルはそのままアプリに持ち込まれる。この時注意が必要なのは基本的にこの中のファイルはRead Onlyと言うことである。しかし今回はMIDIファイルを読みたいだけなので特に心配しなくてよい。

ストリーミングアセット - Unity マニュアル

今回はAsset/以下にStreamingAssetというディレクトリを作成し、そこにMIDI形式の楽曲データを入れた(この時整理のためMIDIというディレクトリにまとめてから入れた)。

そうすると以下のようなコードでフルパスを取得できる。

fullPath = Application.streamingAssetsPath + "/MIDI/" + file;

ただしfileの部分は、今の場合***.midである。このようにしてStreamingAssetの場所を指定するとUnity Editorで実行するか、iphoneで実行するかなどのプラットフォームの違いに依らずに正しい場所を参照することができる。