PR

【Unity】全てのスマートフォン、アスペクト比、解像度でも同じ画面を再現する方法

Unityで全解像度同じ画面を再現する Unity

Unityで開発するアプリの解像度が変わる時、カメラやキャンバス内の配置が若干変わってしまい思った通りに配置されないことがあったので今回その対策をいれてみました。

今回簡単に解像度対応をできるように記事を書いたのでお困りの方の参考になれば幸いです。

更新履歴

  • 2020/03/24
    スクリプトをダウンロードできるように修正、一部コードの表示の不具合を修正
  • 2020/09/22
    カメラのnull参照を修正、Nanになるケースを修正
  • 2021/06/21
    塗りつぶしについて記述追加
  • 2021/07/30
    解説動画を追加
  • 2022/10/08
    Warningが出力される問題を修正
  • 2023/08/07
    勝手に画面が更新されないように反映ボタンの追加、メニューに全更新の操作を追加
    unitypackageのダウンロードに変更

 

見た目の挙動

画面のサイズを変更するとこのように変化します。
キチッとゲームの画面比率やUIの位置・サイズが変わらず維持できていますね。

この対応を入れておかないと、幅が長いスマホなどで本来カメラ外の見えてはいけないモノが見えてしまったり、端末毎に操作感が変わってしまうので調整に大変苦労します。

もちろん一部画面外が黒く塗りつぶされていて画面を活かしきれてない感はあるのですが、そもそもスマホによっては見えてはいけないもの(例えばイベントが起きる前でキャラが消えてるとか)が見えてるのは論外です。

アスペクト比が違う画面などでも調整不要なこの機能を入れて楽をしてしまいましょう!

 

ダウンロード

ダウンロードはこちら

TedLab_ModifyResolution

 

unitypackageのインストール方法

インストール方法はこちら

 

実装内容

おおまかな流れとしてはスクリプト2種類用意して
各オブジェクトに設定していく流れとなります。

カメラ(Camera)

カメラに対して、下記のスクリプトをアタッチします。
詳細な説明は省きますが、おおまかに説明すると

変更されたアスペクトの縦と横どちらが大きいか判別して
カメラの描画領域を調整しています。

次に紹介するスクリプトをゲームで使っているカメラに「CameraStableAspect.cs」を追加してみてください。

 

スクリプト内容

refCameraに使用するカメラコンポーネント、widthに基本解像度の幅、heightに基本解像度の高さ、pixelPerUnitについてもCanvasなどと統一した値を利用してください。

CameraStableAspect.cs

using UnityEngine;

namespace TedLab
{
   [RequireComponent(typeof(Camera))]
   public class CameraStableAspect : MonoBehaviour
   {
      [SerializeField] private Camera refCamera;
      [SerializeField] private int width = 1920;
      [SerializeField] private int height = 1080;
      [SerializeField] private float pixelPerUnit = 100f;
      
      private int _width = -1;
      private int _height = -1;

      private void Awake()
      {
         if (refCamera == null)
         {
            refCamera = GetComponent<Camera>();
         }
         UpdateCamera();
      }

      private void Update() => UpdateCameraWithCheck();

      public void UpdateCameraWithCheck()
      {
         if (_width == Screen.width && _height == Screen.height){
            return;
         }
         UpdateCamera();
      }

      private void UpdateCamera()
      {
         var screenW = (float)Screen.width;
         var screenH = (float)Screen.height;
         var targetW = (float)width;
         var targetH = (float)height;

         //アスペクト比
         var aspect = screenW / screenH;
         var targetAspect = targetW / targetH;
         var orthographicSize = (targetH / 2f / pixelPerUnit);

         //縦に長い
         if (aspect < targetAspect)
         {
            var bgScaleW = targetW / screenW;
            var camHeight = targetH / (screenH * bgScaleW);
            refCamera.rect = new Rect(0f, (1f - camHeight) * 0.5f, 1f, camHeight);
         }
         // 横に長い
         else
         {
            // カメラのorthographicSizeを横の長さに合わせて設定しなおす
            var bgScale = aspect / targetAspect;
            orthographicSize *= bgScale;

            var bgScaleH = targetH / screenH;
            var camWidth = targetW / (screenW * bgScaleH);
            refCamera.rect = new Rect((1f - camWidth) * 0.5f, 0f, camWidth, 1f);
         }

         refCamera.orthographicSize = orthographicSize;

         _width = Screen.width;
         _height = Screen.height;
      }
   }
}

 

次のページ

次はCanvas側の対応をしていきます。

コメント

  1. うなぎ より:

    神スクリプトをありがとうございます!
    とっっっても助かりました!

  2. Tomo より:

    とても助かります!
    ありがとうございました!
    RectScalerWithViewport.csをアタッチする場所がよく分からなかったのですが、キャンバス内に空のゲームオブジェクトを作成してそこにアタッチすればいいんですか?

    • Tadapy Tadashi より:

      助けになったようで良かったです!
      下記回答となります。

      はい、RectScalerWithViewport.csはゲーム上でお使いのCanvasを親として
      その一つ下の階層にゲームオブジェクト(記事で説明しているPanel)を追加し、そこにRectScalerWithViewportスクリプトをアタッチします。

      その追加したゲームオブジェクトはRectTransformと呼ばれるCanvasの子どもになるためのオブジェクトとして作成されますので、そのRectTransformプロパティはCanvasのサイズに連動するように中心を原点とした完全フィット設定にしてください(上下左右のサイズは完全連動、原点を中心にする設定です)。

      そしてPanelで追加すると不要なImageコンポーネントが付いてきますのでこれを削除してください。

      最後にこれまでCanvas直下にあったUIなどのゲームオブジェクトをその追加したPanel(改名推奨、例:ScalerPanelなど)に全てドラッグ&ドロップで移動させます。

      少々初歩的な部分などを端折っている点もありますので
      気になることなどありましたらお気軽にご連絡ください~!

      追伸:ゲーム上でCanvasが複数ある場合、毎回対応入れないといけないのでPrefabしておくと便利です。

  3. にゃんぱす より:

    コメント失礼します。
    とてもいいスクリプトを提供していただきありがとうございます。自分のゲームでも採用してみたいと思います。

    質問なのですが、キャンバスやパネル側の設定はデフォルトの設定のままでしょうか?
    それともCanvas Scaler や Render Mode などの設定も任意のものに変更する必要がありますか?

  4. にゃんぱす より:

    とても良いスクリプトを提供していただきありがとうございます。自分のゲームでもこの機能を実装してみようと思います。

    質問なのですが、CanvasやCamera側の設定で変更しなければならない箇所はありますでしょうか。Canvas Scaler や Render Modeなどの設定は任意のものに変更しなければなりませんか?

    • Tadapy Tadashi より:

      コメントありがとうございます!

      記事に書けておらず申し訳ないのですが、CanvasScalarは利用しない前提の実装となっています。
      なので利用する場合はコンポーネントを削除してご利用してみてください。

      またよくミスをしそうなのは利用しているカメラに「MainCamera」タグを設定していない場合に必要なカメラがスクリプト上で参照できないため
      正常に動かないケースもありそうです。

      Render Modeについては特に意識していなかったのですが、私の環境のCanvasでは「Screen Space – Overlay」となっています。
      こちらも設定して検証してみていただけると幸いです。

  5. 灯火 より:

    このスクリプトに凄く助けられました!unity初心者の者です
    ありがとうございます。

    android端末で試すと、画面サイズは適用するのですが、
    左右の画面外に映る物を消すことが出来ず、困っています。

    『ただ画面引き伸ばされていない場所は見えては行けないモノが見えるのでキャンバスの縁辺りは何か塗りつぶす、パネルなどを置いて隠す必要があります。』

    と書いて頂いている部分になると思うのですが、Panelを置いてみても、消すことが出来ませんでした。

    ご回答頂けると幸いです。

    • Tadapy Tadashi より:

      本記事が参考になったようで幸いです!

      下記回答となります。
      見えては行けない部分はUIのImageコンポーネントでその部分を上塗りするような形で配置する必要があります。

      方法としては端末によっては上下左右どちらに余白が来るかわからないため
      伸び縮みした場合に備えて、上下左右を覆うために4つのImageパネルを用意します。

      そしてあくまで私の例となりますが

      ・パネルはCanvas直下に配置し、Canvas内で一番最後に描画されるようにHierarchy上で一番最後に配置します(Canvas上の描画はHierarchy上で上から順に描画されます)
      ・左右2つのパネルはRectTransformで上下のストレッチ(左は左寄せ、右は右寄せ)にし、Widthを1000にしておきます
      ・上下2つのパネルも同様にRectTransformで左右のストレッチ(上は上寄せ、下は下寄せ)にしてHeightを1000にしておきます
      ・4つのImageコンポーネントの「SourceImage」はNoneにし、色も自分が塗りつぶしたい色に設定しておきます

      上記の方法で私のアプリは実装しています。
      参考になれば幸いです。

  6. 灯火 より:

    お忙しい所、本当にありがとうございますm(_ _)m

    試してみます!

    • Tadapy Tadashi より:

      いえいえ!また気になる点がありましたらコメントください

      ちなみにさきほどのコメントで書き忘れていたのですが
      「上下右左の寄せ」設定についてはRectTransformのpivotで寄せる部分に合わせて変更してあげる必要ありますのでご注意ください~

  7. 灯火 より:

    何度もすみません。

    現在ブロック崩しのandroidアプリを作っています。
    こちらのスクリプトを使わせていただき、画面が端末毎に反映されるようになりました!ですが、

    上下のサイズは正常なのですが、
    左右の両端に切れ目があり、切れ目の外側に、鏡の様にゲーム内のブロックオブジェクト等が映っています。

    先日回答して頂いた、canvas直下へPanel作り、pivotで調節等試してみたのですが、
    解決できず、コメントさせていただきました。

    何度も申し訳ないです。
    解決策ありますでしょうか。

    • Tadapy Tadashi より:

      いえいえ、もしかしたらお互いなにか勘違いしてるのかもしれませんね・・・

      こちらのゲームは縦画面のものとなりますでしょうか?
      また気になるのは「Canvas直下」という点なのですが、塗りつぶしのImageを一番最後に描画するためにはCanvasの最後に配置する必要があります。

      この画像は私のPrefabの構成です

      ・RootPanelの下にUIなどを配置
      ・FramePanelの下に上下左右のパネルを配置

      という構成になっています。
      Prefabの階層表示で上にあるものほど優先されて表示されるので
      ゲームUIなどを表示したあとにImageパネルで上書きするためにFramePanelという階層はゲームUI(RootPanel)よりも下側に配置しています。

      こちらの画像を参考に今一度PrefabやCanvasを確認していただけると幸いです。

  8. 灯火 より:

    ありがとうございます!
    回答して頂いた画像どうりにすると出来ました。
    お時間かけてしまい、すみませんでした。

  9. ゴルドメ より:

    2週間前にUnityを触り始めて、試行錯誤の末、ようやくウンコアプリが完成しました
    さっそくストアにリリースしてみようとしましたが
    スマホやタブレットではPCのようにキャンバスが表示されずに困っていました・・
    この神スクリプトを見つけた時は舞い上がりました!
    素晴らしいスクリプト!!
    もう感謝しかありませんッ!!!

    • Tadapy Tadapy より:

      おお、アプリのリリースに貢献できたようで幸いです!
      稀にうまくいかない方もいるようなのでうまく動作されたようでよかったです^_^

  10. Atsushi より:

    久しぶりにUnityで携帯アプリ作成に挑戦することになり
    この画面サイズ調整を使わせてもらうことにしました。

    実際に実装してみて、動作はするのですが、
    ビルド後に下のようなエラーが発生します。

    MissingReferenceException: The object of type ‘RectTransform’ has been destroyed but you are still trying to access it.
    Your script should either check if it is null or you should not destroy the object.

    エラー情報には
    RectScalerWithViewport.UpdateRect () (at Assets/PlugIn/RectScalerWithViewport.cs:87)
    RectScalerWithViewport.OnValidateImpl () (at Assets/PlugIn/RectScalerWithViewport.cs:47)
    とあるので、ここでエラーが発生しているようなのですが、解決法がわかりません。

    バージョンは2021.3.18f1ですが、皆さんも発生しているエラーなのでしょうか?

    • Tadapy Tadapy より:

      こちらおそらくDestroyされているオブジェクトに対して何かしらの処理をしていると思われます。
      RectScalerWithViewportのプロパティ「refRect」に設定しているオブジェクトが削除されているのではないでしょうか?

      本来「refRect」に設定するのはスクリプトを設定されているゲームオブジェクトのRectTransformや
      子ゲームオブジェクトのものが設定されることを想定されているため「refRect」だけ削除されることはない想定となりますので
      設定しているRectTransformが問題ないか一度確認していただけると幸いです。

  11. むっちゃん より:

    Unityを独学で勉強しており、エディタ上では問題無いのに、実機に移すと画面が崩れたり、変なところに飛んだり、問題だらけの状態に陥っていましたが、こちらの記事のおかげで、その問題も解決できました。
    そして何とかAppStoreで脱出ゲームをリリースすることができました。
    本当に感謝しております。
    ありがとうございました。

    • Tadapy Tadapy より:

      ご連絡ありがとうございます!本記事が参考になったようで幸いです。
      また何か不具合や要望などありましたらぜひご連絡いただければと思います。

スポンサーリンク
Ads Blocker Image Powered by Code Help Pro

広告ブロッカーが検出されました

広告をブロックする拡張機能を使用していることがわかりました。これらの広告ブロックを無効にして、私たちをサポートしてください。

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