Unityの画面のアスペクト比と解像度を自動変換 全スマホ・複数解像度に対応させる

Unity 放置インフレ系クリッカーゲームの作り方 (スマホ化対応)


Unityの本格ゲーム制作講座はこちら
【30日間の全額返金保証付き】

前回で効果音も付けてゲームとしては完成という状態になりました。

前回の記事↓

サウンドマネージャー機能を使って効果音を付ける
前回はコイン取得演出の追加と、セーブ・ロード処理を追加し、ほぼ完成という状態になりました。 前回の記事↓ 今回はサウンドの追加を行い、ゲームとしての完成を目指します。 サウンドの追加にはサウンドマネージャーを使用します。ここまで通...

今回は最終回、スマホ解像度対応をして完成を目指します。

AndroidでもiPhoneでもタブレット端末でも、アスペクト比や解像度を自動対応させるスクリプトを作っていきます。


【無料転職サポート&就職後に授業料を全額返金】

スマホ解像度とアスペクト比の考え方 固定解像度で対応させる方法

さて、今回のゲーム、縦長ですしクリッカーゲームのゲーム性からしてもスマートフォンで動かせると良さそうです。

と、言いましたが、Unityは元よりマルチプラットフォーム開発のためのゲームエンジン。
実は何もしなくても、このままスマートフォン(Android/iOS)へ流し込んで実行することが出来ます。

しかし、一つ問題になるのが「解像度対応」です。

スマートフォンは解像度が非常に多岐に渡ります。そして、「解像度」と言いましたが、特に重要なのは「縦横比(アスペクト比)」です。

ざっと

  • 4:3 (iPad等)
  • 16:9 (ちょっと前のiPhone系)
  • 19.5:9(iPhoneX~)
  • 21:9(XPERIA等)

などなど(もちろんもっともっとあります)

これだけあると、ターゲットをどれか一つに絞って出すわけには行きません。

どうしたものでしょうか・・・。

固定解像度で作る方法 機種変更に対応できない

一番簡単なのは「論理的に解像度を固定」してしまうことです。

例えば、今回はゲームのサイズを480×800で作り始めています。

これはあくまでもUnityEditor上での解像度なので、ここで480×800を指定したからと言ってスマートフォンなどの実機上で480×800になるわけではありません。

では、このドロップダウンから違う解像度のStandalone(1024×768)を選択してみましょう。

どうでしょうか。あっさりと画面構成が崩れてしまいましたね。

画面外で生成しているはずの羊は見えてしまっていますし、UI関係は横に広がってしまっていますね。
あと(ちょっと分かりづらいですが)カゴのすぐ下にあったはずの売却ボタンもちょと隙間が空いてしまっています。

ゲーム画面の解像度対応 カメラ描画範囲を変更する方法と考え方

ではまずゲーム画面(UI以外)の解像度をあわせていきます。

基本的にはカメラは画面全体を使って描画しようとします。
そのため、実行する環境(スマートフォンの画面サイズ)によって差が生まれてしまいます。

そこで、カメラが描画しようとする範囲そのものを変更してしまいましょう。

Main Camera」のInspectorにあるViewport Rect画面に対する描画範囲になります。

今は
X:0 Y:0
W:1 H:1
となっていますね。

この、XYが画面の描画位置W(Width:横幅)とH(Height:縦幅)が画面のどれくらいを描画範囲として使うか、を表しています。

なぜかというと、ViewPortで使用される座標は実ピクセルではなく、0~1正規化されたものを使用するからです。

実際の画面の横幅が800ピクセルだろうと、3840ピクセルだろうと、画面の左端は0で、右端は1丁度真ん中は0.5ということです。

赤で書いてあるのがViewport Rectで使われる座標です

試しに「W」の上でマウスドラッグをして、W(横幅)の値を0~1で変化させてみましょう。

1画面の横幅全てを、0.5で画面の半分を使うことになり、0以下だと描画されないのがわかりますでしょうか。

今回の場合(480×800用に作ったゲーム を 1024×768の画面で描画)は、0.45を指定すると丁度良くなるようです。

ただ、画面表示が左端になってしまっていますね。

それは描画位置を表すX(およびY)が0になっているからです。では「X」の上でマウスドラッグをして、X(描画位置)の値を0~1で変化させてみましょう。

0で左端1だと右端になってしまうので何も描画されません。
そして0.5真ん中というわけではなく0.5の位置を起点として画面が描画されるので、

真ん中に揃えるためには今回の描画横幅W=0.45半分である0.225 を、0.5から引く必要があります。
0.5 – 0.225 = 0.275ですね。

結果、X = 0.275,W = 0.45 にすると、今回の場合(480×800用に作ったゲーム を 1024×768の画面で描画)は余計な所を描画せず、画面の丁度真ん中に描画することが出来ました。

では再生ボタンを押して、実行してみましょう。

ゲーム画面は必要な箇所だけ描画されるようになりましたが、UIがおかしいですね。
入りきっていたはずの羊購入ボタンが下にはみ出してしまっています。

UIの解像度対応 Canvasのfree aspect設定を行う(まだ画面崩れは起きる)

では、次にUIの解像度対応を行いましょう。

Unityの標準UI(uGui)には、最初から解像度対応の機能があるので、UIについてはそちらを使用します。

Hierarchyから「Canvas」を選択し、Inspectorで最初から付いているComponentである「CanvasScaler」のUI Scale Mode を変更します。

最初は Constant Pixel Size (画面の解像度をそのまま使う)となっているので
Scale With Screen Size(画面の解像度に合わせて拡大縮小する)を選択します。

その際の基準となる解像度(Reference Resolution)と、そこで指定した解像度と実機の解像度が異なる場合にどのように差を吸収するか(Screen Match Mode)が指定出来るので

  • Reference Resolution : X 480 Y 800
  • Screen Match Mode : Expand

にしておきましょう。

では、再生ボタンを押して確認してみましょう。

羊購入ボタンも全て入りきって、今まで通りの画面になりましたね!!

しかし、もちろんこの対応はあくまでも

  • 480×800用に作ったゲーム を 1024×768の画面で描画

の専用の対応です。

これはGameビューの解像度ドロップダウンからFree Aspectを選択してみるとよくわかります。
(Free AspectはUnityEditor上でのGameビューのサイズそのものを画面解像度としてくれます)

このFree Aspectの状態でウインドウサイズを変えてみましょう。

画面に入り切らなかったり、また逆に余白が表示されたりしてしまっていますね。

既に書いたように、iPhoneおよびAndroidの解像度は多岐に渡ります。

このようにFree Aspectを指定してウインドウをどのようにサイズ変更したとしても画面構成が崩れないのが理想です。

そのために解像度固定のスクリプトを用意することにしましょう。

解像度固定スクリプトの作成 全スマホの画面サイズに対応させる方法

HierarchyでMain Camera を選択し、Add Component で解像度固定用の 新しいスクリプト AspectKeeper を追加します。

では、早速AspectKeeperスクリプトを修正していきます。

まず、ターゲットとなるカメラ(targetCamera)と、固定したい解像度(aspectVec)をInspectorで指定出来るように、メンバ変数に以下の2つを追加します。

次に、Startメソッドは使わないので削除し、Updateメソッドで、現在の解像度(Screen)と目的とする解像度(aspectVec)から、カメラのViewport Rect(camera.rect)を設定していきます(Camera.Rectに関しての公式リファレンスはこちら)。

まず、現在の解像度の縦横比(以後:アスペクト比)と、目的とする解像度のアスペクト比を求めます。 これは、横幅を縦幅で割るだけです。

なお現在の画面の縦解像度・横解像度Screen.width 及び Screen.heightで取得することが出来ます。

ただ1点要注意なのは、Screenwidth 及び heightint(整数型)なので、そのまま計算をすると計算結果もintになってしまい、小数点以下が消えてしまいます。
そのため、widthまたはheightの少なくともどちらかを(float)でfloat型にキャストする必要があります。

次に、この screenAspecttargetAspect で割って、現在アスペクト比から目的アスペクト比にするための倍率(magRate)を計算します。

さて、このscreenAspecttargetAspectmagRateをわかりやすくするために、

  • 480×800用に作ったゲーム を 1024×768の画面で描画

を割り当てて考えていきます。

すると

  • screenAspect = 1024 / 768 = 1.33333333333…
  • targetAspect = 480 / 800 = 0.6
  • magRate = 0.6 / 1.33333333333 = 0.45

になりました。 この0.45という数字。見覚えがありますね。
これは、先程Viewport Rect の W に設定した値でした。

このmagRateの値をそのままViewportWにセットすると良さそうです。

では、Viewport で使われている Rect 型の変数 viewportRect を作り、W(width)にmagRateの値をセットしてから、実際にターゲットとしているカメラ(targetCamera)のViewport Rect(rect)にセットするようにします。

さて、この時点で一度スクリプトを保存して、UnityEditorで確認をしてみたいと思います。

Inspectorで、TargetCameraに自身のCameraを、Aspect Vecにはターゲットとする解像度480と800を入れます。

では、再生ボタンを押して確認してみましょう。

どうでしょうか。Gameビューのサイズを変更すると、動的にCameraのViewportRectが変更されているのがわかると思います。
また、縦幅に伸ばしたり縮めたりする分には画面構成が崩れなくなりました!

ただ、横幅を縮めた時に、Wの値が1を超えてしまって画面内に入り切らなくなってしまっているのがわかります。

これはどういう時に起きるかというと、極端に言うと

  • 480×800用に作ったゲーム を 240×800の画面で描画

のような、ゲーム画面を縦幅いっぱいに広げた時に横がはみ出てしまうパターンです。

これもまた、具体的に先程の計算式に当てはめていくと

  • screenAspect = 240 / 800 = 0.33333333333…
  • targetAspect = 480 / 800 = 0.6
  • magRate = 0.6 / 0.33333333333 = 1.8

となり、現在アスペクト比から目的アスペクト比にするための倍率(magRate)を求めたら、1を超えてしまっています。

このような場合はどうなって欲しいかと言うと、Viewportwidth1(すべて使う)としておいて、使用する縦幅であるheightの方を減らす(1/magRate)必要があります。

これをそのままプログラムに落とし込むとこのようになります。

さて、またスクリプトを保存して、UnityEditorで確認をしてみましょう。

縦幅だけではなくて、横幅を縮めた時も画面構成が崩れなくなりました!

ただ、またViewportのwidthまたheightを変更しているだけなので、横幅を縮めた場合は左端に、縦幅を縮めた場合は下端に画面が表示されています。これを中央にするには、描画横幅(縦幅)の半分 を、0.5から引く必要があるんでしたね

では、スクリプトをそのように修正しましょう。応用的に縦も対応してしまいます。

そして最後に、このスクリプトは実行中だけではなく、UnityEditorで操作している間にも動いてくれたほうが都合が良いのでclassの宣言の前に [ExecuteAlways] という属性(Attribute)を記述しておきます。

AspectKeeperスクリプト全体は以下のようになります。

スクリプトを保存してUnityEditorで確認をしてみましょう。[ExecuteAlways] が付いているので、再生ボタンを押さない状態でも、動的にViewportが変更されるようになっているのが確認出来ると思います。

描画範囲外の対応 ゲーム画面外を隠す枠の作り方

以上でスクリプトによる対応は全てなのですが、実はまだ問題があります。

カメラのViewportを変更することで、画面の一部だけを使用するようにしたわけですが、では使用していない部分はどうなるでしょうか。

Unityにおいて、本来画面を消す(1回きれいにする)のはカメラの役割です。
しかし、そのカメラはViewportで使用画面範囲を狭めているため、使用されていない部分はクリア処理が走らない場所ということになります。

これは非常によろしくない状態で、UnityEditor上ではキレイに黒で塗りつぶされていますが、実端末で試してみると

  • 直前で実行していた画面が表示される
  • ノイズのようなゴミが表示される
  • 画面内の部分が何故か表示される

といった、謎の不具合が頻発することになります。(たまたまキレイになんらかの色で塗りつぶされることもあります)

この対処法としては、今ある(最初からある)カメラとは別に、画面全体をクリアする用のカメラを別途用意してしまうことです。

画面外を隠すクリア用カメラの追加

Hierarchyを右クリックし、メニューから「Camera」を選択して、もう一つカメラを追加します。
名前はわかりやすいように「ClearCamera」とでもしておきましょう。
TransformもReset(PositionとRotationは全て0 Scaleは全て1)にしておきます。

さて、ゲーム画面は、というとが真っ青(初期の青い色)になってしまいましたね。

これは、カメラの描画順によるものです。

MainCamera→ClearCameraの順番で描画処理が行われてしまっているため、MainCameraでせっかく描画したUIや羊の画像などが、ClearCamera全て消えてしまっています。

カメラの描画順は Depth という項目の小さい順に描画処理が行われる仕組みになっています。(MainCameraDepth=-1, ClearCameraは初期値のDepth=0)

なので、ClearCameraDepthの値をMainCameraよりももっと小さい値にしてあげればOKです。-2にしてしまいましょう。

また、あくまでも「画面のクリア用」で、何かを描画する必要はないため、 Culling Mask(何を描画するためのカメラか)という項目もNothingに変更します。

そして、AudioListenerは2つあるとログに警告が出続けてしまうので、ClearCameraの方のAudioListenerは消してしまいましょう。

これにより、Camera同士の処理順も正しくなり、先程まで真っ暗(不定)だった箇所がClearCameraBackgroundで指定した色で塗りつぶされるようになりました!

外枠を装飾するレターボックス(ピラーボックス)の作り方

さて、Androidならこの対応だけでも良いのですが、iOSはこの塗りつぶし処理だけではリジェクト(申請却下)されることがあります。

では、どうするかというと、画像によるレターボックス(ピラーボックス)を置きます。

レターボックス(ピラーボックス)とは、地デジ化前の古いアニメなんかを今放送しようとした時に、画面の左右に表示されるの事です。TVでもを置くことで解像度の差を吸収しているわけですね。

このレターボックスと言ったり、ピラーボックスと言ったり、帯と言ったりしますが、ゲーム会社によってさらに呼び方が違ったりします。 僕が居たゲーム会社では「目隠し」とか「カーテン」と呼ばれていました。
リジェクト回避の意味もありますが、そうじゃなくてもただ単色で塗りつぶされているよりもゲーム・世界観に合った帯の画像を置いたほうがユーザーからすると好意的に受け取られますよね。
 

では早速作っていきましょう。

レターボックス用Canvasを追加

HierarchyにCanvasを新しく作成し、名前は「LetterBoxCanvas」とでもしておきます。その他設定は以下の通りに

  • Canvas Scaler
    • UI Scale Mode は Scale WIth Screen Size
    • Reference Resolution は 目的解像度である 480 x 800
    • Screen Match Mode は Expand を指定
  • Graphic Raycaster は使わないので削除

ゲーム画面サイズPanel作成

次に、この作ったLetterBoxCanvasに、ゲーム画面サイズのアンカー用に、空のGameObjectを作ります(ALT+SHIFT+N または、右クリックして「Create Empty」)名前はGameViewAnchor とでもしておきます。その他は以下の用に設定します

  • AnchorやPivotが中心になっている事を確認
  • Width , Height に ゲーム解像度(今回の場合は Width:480 Height:800) をセット

画像(Image)で帯を4方向に追加

では、作ったGameViewAnchorの子要素として、上下左右4方向に帯画像(Image)を置いていきます。

まず、一つImageを追加し、

CTRL+Dキーで3つ複製して、計4つにします。

分かりづらいので、名前をそれぞれ

  • Left
  • Right
  • Up
  • Down

に変更しておきます。

では、まずLeftからやっていきましょう。 左側の帯なので、縦幅はゲーム画面サイズいっぱいにしたいため、AnchorPresets 左端縦方向にStretchするように設定します。

Gameビューを見ると帯画像は内側(ゲーム画面側)に入り込んでしまっています。

この帯画像を外側に向けるには、Pivotを変更します。

X:0 になっていますので、X:1に変更しましょう。

帯の向きが外側を向きましたね。

 

指数表示(e)
AnchorPresetsを変更していると、Pos XやPos Yに 「1.525879e-05」 のような、eの付いた謎の数字(?)になることがあります。(↑の画像のPos Xの値参照)
これは、指数表示というもので

「ベースとなる数e指数」

で表され、実際の値としては

「ベースとなる数 * 10 の 指数乗」

 になります。

先程の「1.525879e-05」で言うと

ベースとなる数:1.525879
指数:-5

となり、実際の値は

1.525879e-05 = 1.525879 * 10の-5乗 = 0.0000152588 になります。

みての通り、すごく小さい値ですね。
これは、Unityが自動で行う位置合わせの計算上、本来は0の所計算の誤差で出てしまったすごく小さい値が入ってしまっている。 ということです。

そのままでも基本的には問題がない(ほぼ0なので)ので、そのままでも良いですし、気になる方は手で0に書き換えても構いません。

 

この要領で、残りのRight,Up,Down全て設定をしていきます。

Imge Anchor Min (X,Y) Anchor Max (X,Y) Pivot (X,Y)
LEFT ( 0 , 0 ) ( 0 , 1 ) ( 1 , 0.5 )
RIGHT ( 1 , 0 ) ( 1 , 1 ) ( 0 , 0.5 )
UP ( 0 , 1 ) ( 1 , 1 ) ( 0.5 , 0 )
DOWN ( 0 , 0 ) ( 1 , 0 ) ( 0.5 , 1 )

(※講座上では画像は指定していませんが、わかりやすいように色分けをし、幅は300にしてあります)

全て設定できましたら、Gameビューの解像度をFree Aspectにして確認してみましょう。

上下左右にそれぞれ違う色の帯を置くことが出来ました!

おさらい

今回はスマホ解像度対応を作り上げることができました。

ここまでくれば、あなたももうスマホゲームを作れるようになっているはず!

今回のクリッカーゲームだけでなく、どんな機種でも対応できるあなたオリジナルゲのスマホゲーム作りにチャレンジしてみてください^^

講座全体としては全12回に加え、サウンドマネージャー作成も途中で入っているため非常に長い講座となってしまいました。

あなたのUnityゲーム制作のお役に立てていれば幸いです。

ここまでお付き合い頂き誠にありがとうございました。

次回講座の準備も進めているのでお楽しみに!

 

放置インフレ系クリッカーゲームの作り方講座に戻る↓

Unity 放置インフレ系クリッカーゲームの作り方 (スマホ化対応)
今回のunityゲーム開発講座では2DUnityを用いたインフレ系クリッカーゲームシステムの制作を行っていきます! 講座は現在全部で10回に分かれており、初めてunityを使ってゲームを作る人でもサクサク進められる講座になっています。 「Unityでクリッカーゲームを作ってみたい!」 「Unityでインフレ系タップゲームを作ってみたい!」 そんなあなたのためにインフレ系クリッカーゲームの作り方講座です!

コメント

タイトルとURLをコピーしました