sh1’s diary

プログラミング、読んだ本、資格試験、ゲームとか私を記録するところ

Unity Canvas を使った2Dゲーム画面設計と Reference Resolution のプラクティス

過去の記事では、通常どおりのカメラ空間で2Dゲームの構成を作成しました。その後、「スマートフォン(複雑なアスペクト比)対応とレスポンシブ UI の基本」の記事を書いたとおり、2Dをやるなら Canvas と付き合うようにしたほうが都合よいこともありそうです。

Canvas を使うとき、画面に映る画像の大きさを決める要素として重要なのは

  • 画像をインポートしたスプライトデータの設定 pixels per unit
  • キャンバスの Reference Resolution のパラメーター

両者の関係を整理して、画面にどう映るようになるのか確認していきます。画面の端から端まで、ちゃんと制御して表示できるようになろうという記事です。


Canvas(画面サイズ)の設定

まず、前準備からはじめます。

Canvas の設定値の Render ModeScreen Space - Camera にすると、カメラと Canvas を指定した距離だけ空けてキャンバスを表示してくれます。よくやる設定だと思いますので次に進みます。

カメラに映る(ウィンドウに見える)Canvas の領域は、Canvas Scaler の設定値 UI Scale ModeScale With Screen Size であるとき、CanvasReference Resolution の値で制御します。

Canvas Scaler の設定値 Reference Pixels Per Unit の値は影響しません。勘違いしないように!

ここでのサンプルは、画面の縦横比を16:9と仮定することにします。画面にあわせるためには、Reference Resolution の値を 320x180 のようにします。両者の縦横比が異なると、最初は混乱すると思うので、とりあえずあわせておいたほうがよいと思います。

最適化の観点からだと、Canvas は要素に変更があると Canvas 全体に再解析の処理は走るため 1 最適なドローコールになりません。つまり、ルートが Canvas だとドローコールのコストが大きい可能性があります。対策として、キャンバスをネストする(親 Canvas と子 Canvas の関係を持つ)ことでコンテンツを分離して、独自のジオメトリ、バッチ処理を実行できます。

f:id:shikaku_sh:20200828171514p:plain:w600
ざっくりとこんな感じ


画面サイズの確認

Canvas のサイズ (Reference Resolution) が 320x180 なら、20x20 のブロックを 16x9 個配置できるはずです。まず、これを確認してみます。

20x20 のブロックの画像を作成して、横に連続して並べることにします。2色のブロックを用意して、めり込んだりしないように画像の端をわかりやすくしました。

f:id:shikaku_sh:20200828171622p:plainf:id:shikaku_sh:20200828171626p:plainf:id:shikaku_sh:20200828171628p:plain
サンプル 20x20 ピクセルの画像

画像を Unity の Assets にインポートするとき、画面比率に影響する重要なパラメーターが Pixels Per Unit です。デフォルトでは 100 に設定されています。この設定の意味は、この画像は1ユニットの幅に対して 100 pixel 詰め込んでください、というようなことになります。

ユニットというのは、最小単位です。ここでは CanvasReference Resolution の単位になります。

Canvas の 320x180 のサイズに、320 個と 180 個ずつドットを詰め込めるようにするには1ユニットの幅に対して 1 pixel とすればよいので、Pixels Per Unit の設定値は1になります。

f:id:shikaku_sh:20200828171752p:plain:w600
画像を並べた図

この状態でスプライトを Canvas に追加して、インスペクターから Trasform の Scale を x, y ともに1で設定して画面に詰め込んでいくと、縦横比がとれているのを確認できます。

f:id:shikaku_sh:20200828171854p:plain:w600 f:id:shikaku_sh:20200828171824p:plain:w600 f:id:shikaku_sh:20200828171841p:plain:w600


Pixels Per Unit を1にしない例(1)

仮に、Assets に追加したスプライトの Pixels Per Unit をデフォルトの 100 のまま Canvasコンポーネントとして追加してみます。インスペクターから Trasform の Scale を x, y ともに1で設定すると、とても小さなスプライトになってしまうのが確認できます。

これは、どういう状態なのか考えてみます。

元々の画像サイズは 20x20 でした。それを1ユニットに対して 100 ピクセル詰め込む設定になっています。つまり1ユニットに 20/100 = 1/5 だけ表示されている状態だと思われます。

さっそく Canvas 上のコンポーネントの Scale を x, y ともに5倍してみます。おそらくこれで、1ユニットのサイズ(1ピクセルサイズ)になったはずです……が、わかりづらいですね。

さらに20倍すると、ちょうど20ユニットのサイズとなり、つまり1ユニット1 pixel としたコンポーネントと同じサイズになりました。(つまり Scale 100倍です)

{
\begin{equation}
20 unit = 0.2 unit \times 5 \times 20
\end{equation}
}

f:id:shikaku_sh:20200828171951p:plain:w600
100倍


Pixels Per Unit を1にしない例(2)

仮に 128x128 の画像を Assets にインポートして、同じく Pixels Per Unit をデフォルトの 100 のまま Canvasコンポーネントとして追加してみます。

(1)の説明のとおりだと、Canvas に追加したコンポーネントは、1ユニットに対して 1.28 ユニットの大きさで表示されていることになります。

画面に対して、Scale が1のとき 1.28 ユニットの大きさなので、Scale が x のとき1ユニットの大きさなので

{
\begin{equation}
1:1.28=x:1
\end{equation}
}


これにより、Scale が 0.78125 のとき1ユニットだとわかりました。一応確かめるために20倍して表示してみます。

{
\begin{equation}
1unit = 0.78125 * 20 = 15.625
\end{equation}
}


f:id:shikaku_sh:20200828172031p:plain:w600
128 ピクセルの画像を調整する例

ブロックと同じサイズになりました。


応用編

たとえば、Canvas のサイズを 32x18 にしてみるパターンを考えてみます。縦横比はあわせてありますが、かなり小さいサイズにも思います。

逆にいえば Canvas の1ユニットを大きく見えるように設計していますので、20x20 の画像を読み込む際は1ユニットの Pixel Per Unit は 20 にするとよいでしょう。

シンプルに取り回せるように、1 タイル = 1 ユニットになるようスケールを設定するのがいいでしょう。

この内容は、「Unity Blog - 2D アートアセットの解像度選択」のとおりですね。

ゲームのメイン部分にあわせた設定にするためにこうしたプロパティがあるのだと思いますが、今までの開発で Windows APIDirectX を使って素直にコードを書いていたなら、1unitは1Pixel というのが自然かもしれません。


参考

楽しく学ぶ Unity2D超入門講座

楽しく学ぶ Unity2D超入門講座


  1. 詳細は長くなるので Unity UI の最適化に関するヒント を参照してみてください。