2012年1月25日水曜日

Unity iOSにおけるGUIのiPhoneディスプレイ対応




Unittyはマルチプラットフォーム向けのゲームエンジン。Unity1つでIPhone、iPad、Android、それにWebブラウザといった様々なプラットフォームで動作するゲームが作れるのが売り。



ところで、3Dゲームであっても2Dで描画すべき箇所はある。GameLoftはリッチな3Dゲームを開発するゲームスタジオとして有名。かれらの代表作、スパイダーマンにも2Dが使われている。3Dの世界をスパイダーマンが動きまわって、敵を倒しまくっている一方で、画面の右上には大量ゲージ、左下にはジョイスティックがぽんと置かれている。これらは2Dで描画されるもの。そしてこれは、iPhoneでは同じサイズを指定した場合、3GのディスプレイとRetinaディスプレイで見え方が異なってしまう。


これら2Dコンポーネントはマルチプラットフォーム開発に置いて、非常に面倒な存在であることはなかなか気づかないと思う。Unityにおける3D空間というのはプラットフォームのディスプレイサイズに依存しないから ((ディスプレイサイズにおける1ピクセルが3Dの1単位をそのまま反映する訳ではないという意味))、そのままの移植が必要なのだけど2Dはそれぞれのディスプレイサイズに対応して描画しなければいけない。iOS向けの3Dゲームを開発するなかで、僕はこの仕様がとても面倒なことに気づいた。



1. GUI

たとえば、iPhoneのディスプレイは、機種によって異なる。3GSだったら「320×480」、4だったら「640×960」。Unityは対応していないが、iOS、特にUIKit、CoreGraphicsといった便利なフレームワークがこの解像度の違いを吸収してくれる。フレームとして、CGRect(10.0f, 20.0f, 300.0f, 440.0f)を指定した場合、3Gであればそのままのフレーム(1ポイント1ピクセル)で表示し、4や4SのようなRetinaディスプレイであれば、 3Gのディスプレイの解像度を2等倍したフレーム(1ポイント2ピクセル)で表示される。


当たり前のことだけれどUIKitの描画機能、つまりCoreGraphicsはディスプレイのスケールを判断し、その分描画サイズを変えているのでしょう。同じような処理をUnityできればずいぶん楽になるはず。サンプルコードは下記の通り。iPhoneScreen.Scale()は僕が作った独自クラスのメソッドで、内部はシンプル、ただScreen.width / 320.0fでスケールを値として返しているだけ。



当たりをつけてから調査するのに時間がかかってしまったが、結論GUI.matrixに与えるScaleの値を変えれば良い。このコードをOnGUI()内に書いたクラスを継承し、親クラスのOnGUI()を常に呼び出してあげれば、子クラスではiPhoneの用に勝手にディスプレイサイズの違いを吸収してくれるようになる。


このコードはあくまでiPhone向けだから、iPadやAndroid版をリリースする場合にはディスプレイサイズの認識、デザインの調整の2点を踏んだ上で実装することになる。動作しているプラットフォームはApplicationクラスで取得できるから、それぞれに応じてScaleの値を変えればディスプレイに合わせてきれいに描画しやすくなる。



2. テクスチャのインポート

問題はもう1つある。テクスチャの扱い。同じテクスチャを読み込んでレンダリングする場合、割れてしまったり、ぼやっとしてしまったりする。こちらも描画サイズに応じて、インポートする画像も振り分けなければいけない。



これもiOSだとうまくやってくれる。イメージファイルを読み込むという点で、UIkitのUIImage便利なメソッドがある。



これらはディスプレイサイズによりインポートする画像をスイッチしてくれる。そのための命名規則も存在し、Retina向けの画像に関しては拡張子文字列直前に「@2x」を挿入すれば良い。これだけで勝手に適切な画像をローディングしてくれる。


Unityではこのようなルール、仕様は存在しないため、自前で作るしかない。インポート用のクラスを1つ作ることにした。つまり、プラットフォームとディスプレイサイズを判別して、画像を振り分けてロードするクラスとメソッド。



例えば、Application.platformでプラットフォームを振り分け、iPhoneであれば、Screen.width / 320.0fによってスケールを算出する。そのスケールが1か2かによって、3G向けディスプレイであるか、Retinaであるかを判断し、命名規則に基づいて画像をインポートすればいい。




3Dゲームであっても、メニュー画面やGUI、それにプレイ画面やポーズ画面などあらゆることろで2Dの描画をつかう。今回はAndroidには触れなかったが、基本的には同じ発想で対応することができると思う。Androidの場合も、大きく分けても4、5とディスプレイにバリエーションがあるから、こういった簡単な処理を作っておくと便利だと思う。

0 件のコメント:

コメントを投稿