Heliodor 2018/10/20 15:35

ゲームデータの自動ビルドについて

全然需要ないかな?と思ったら意外と見ている人がいるみたいなので、またプログラムの話でも(長文です)。
今回は、ゲーム用の画像とか各種ファイルの扱いが意外と面倒だよね、みたいな話をします。

ゲームで使う画像には主にpngを使用しているのですが、pngは思いのほか展開に時間がかかるため、何十枚もあるpngをそのまま素直に使うと、ロードに結構な時間がかかってしまいます。

ところで意外と知らない方も多いのですが、png画像は圧縮レベルを0から9までの間で指定することができます。レベル0は無圧縮、レベル1が最低圧、レベル9が最高圧縮になります。レベルが高いほど高圧縮でサイズが小さくなりますが、展開には時間がかかります。逆にレベルが低いほど低圧縮でサイズは大きくなりますが、そのぶん高速に処理できます。(ちなみに圧縮レベルが指定できないツールを使った場合、レベル5で処理される事が多いみたいです)。ということは、全てのpng画像を圧縮レベル1(低圧縮、高速)で保存してあればロードも早くなるという事ですが、保存時にpngの圧縮レベルを指定できるものは意外と少ないですし、そもそも画像を保存するたびに圧縮レベルを指定する(デフォルト設定だとレベル5になっている場合が多い)のも面倒な話です。

このように、編集時とは別に、ゲームに最適な形になるようファイルを加工して使いたいというのは、なにも画像に限った事ではありません。

例えば音楽や効果音は、編集時はwavで扱う事が多いのですが、ゲームではサウンドファイルをogg形式で扱っているため、全てのwavファイルをoggに変換しておく必要がありますし、セリフなどのテキストデータを暗号化したり、プレーンテキストで書いてあるスクリプトを事前コンパイルしてバイナリ形式に変換しておいたりなど、ゲーム専用のファイルに変換しておきたいものはたくさんあります。

しかし、これらの作業をその都度手動で行うのはかなり面倒ですので、編集用ファイル(生ファイル)からゲームアプリにとって都合の良いファイル(ゲームファイル)に自動的に作成するためのツール「ゲームデータビルダー」を作りました。

このツールは、生ファイルの入っているフォルダを指定すると、フォルダ内のさまざまなファイルに対して必要な変換を施し、それらをゲームファイルとして出力フォルダに書き出すというものです。生ファイルを編集したときは、このツールを起動すれば勝手にファイルをビルドしてゲームファイルを作ってくれるというわけです。

ところが、ただツールを起動するだけのビルド作業、意外と忘れる事があるんですね。画像ファイルを修正したあとにビルドし忘れたままゲームを起動し、変更箇所がゲームに全く反映されず混乱するという事故が多発しました。

そこでヴィータ大脱出を開発するとき、ゲームアプリ本体にデータのビルドツールを組み込んでしまい、ゲーム起動時に自動的にデータビルドも実行してしまうことにしました(もちろん製品版として世に出すときは、このビルド機能を削除しておきます)。

とは言え、さすがにゲームを起動するたびに全ファイルに対してビルド処理が入ったのでは起動に時間がかかってイライラします。そこで、ビルド時間を短くするために、無駄なビルドをしないように工夫することにしました。

ビルドが必要なのは生ファイルが変更された時だけです。無変更なファイルはわざわざビルドしなおす必要がありません。前回のビルド結果をそのまま使えば良いからです。そのためにはビルド時にファイル情報を記録しておき、次回起動時にその記録と実際のファイルを比較し、ファイルに変化があれば再ビルドし、変化がなければスキップすれば良いことになります。

さて、肝心なのは「ファイルが変化したかどうか」をどうやって調べるかです。それならハッシュを記録しておいて前回と今回のハッシュを比較すれば楽勝です、と言いたいところですが、それはちょっと問題ありです。ハッシュを比較するためにはファイルの最新のハッシュを知る必要がありますが、ハッシュを計算するにはファイルのバイナリを最初から最後までスキャンしないといけません。どのファイルが変化したかを予め知ることはできない(というかそれを知るのが目的)なので、結局のところ全ての生ファイルのハッシュを再計算しないといけません。生ファイルが数百MBあったりするとハッシュ取得だけで時間がかかってしまいます。

そこで、単純にファイルのタイムスタンプだけを比較するようにします。ビルドした時にファイル名と最終更新日時のタイムスタンプを記録しておき、それと実際のタイムスタンプを比較して「異なっていたら」変更ありとみなします。ちなみに、前回と比べてタイムスタンプが「新しく」なっていたら変更ありとみなすのはダメです。なぜかというと、バックアップなどからファイルを取り出して復元した場合にはタイムスタンプが古くなってしまう場合があるからです。なので、1秒でも異なっていたらファイルが変更されたと判断します。

まとめるとこういう事です。

まずゲーム起動時に前回のビルド情報をロードします。ビルド情報がなければ初回ビルドだという事なので、無条件に全ファイルをビルドします。ビルド情報があれば、全ての生ファイルについて前回ビルド時のタイムスタンプと、現在のタイムスタンプを比較し、完全に一致するものはスキップし、そうでなければその生ファイルを再ビルドしてゲームファイルを作り直します。

これでカンペキですね!
...と言いたいことろですが、これだとうまくいかない場合があるのです。


(長くなったので今回はここまで、後編に続きます)

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

記事のタグから探す

月別アーカイブ

限定特典から探す

記事を検索