【Unity】アスペクト比維持してUIのimageをCanvasにFitさせる

2021年4月25日日曜日

C# Unity Unity2D

この記事をシェアする
  • B!


なんだか長いタイトルになってしまいましたが、そのままです。

Unityで、UIのimageをもとの画像のアスペクト(aspect)比そのままで、かつ画面いっぱいだったり、Canvasいっぱいにフィットさせたりして表示する方法をご紹介します。スクリプトを一枚アタッチするだけなので、比較的便利ではないかと(個人的には)思ってます。



ブログランキング・にほんブログ村へ にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ Unityへ にほんブログ村 IT技術ブログ C#へ


環境について

Unityバージョン:2019.4.18f1
Visual Studio Community 2019バージョン:16.9.1

前提:Unityはアスペクト比を維持したまま拡大・縮小ができる

Unityのimageに、普通に画像を挿入すると、こんな感じになるはず。

↑手元にあった横長の画像が夜景の写真しかなかった…

imageはRect Transformとか、何も弄ってない状態だと正方形なので、元が横長の画像も正方形に圧縮されてしまいます。

もちろん、Rect Transformの幅とか高さを上手に弄ればいいのですが、それよりももっと簡単かつ確実に縦横比そのままにできる機能を、Unityが最初から用意してくれています。

上の画像のインスペクターウィンドウ、imageコンポーネントの下のほうにある、「アスペクト比を保存」ってやつですね。

これにチェックマークをいれれば、縦横の比率は元の画像と同じものになります。


はい、こんな感じですね。
チェックマークつけるだけでいいのでとても便利な機能ではあるのですが、しかしこれ、よく見たらうっすらと白い正方形の輪郭が見えますね…?

これはimageのUIの境界線で、画像をアスペクト比にしたところでimageそのもののサイズは変わっていないということです。インスペクターにあるとおり、幅・高さともに変わっていません。そのまま拡大・縮小させるだけでは、決まった枠の中「ピッタリ」にサイズ調整、というのは難しい…。

まぁ、あまり細かいことを気にしないのなら、これで拡大・縮小で使うのもありなのですが
 ――ちなみにツールバーの短形ツール(右から三つ目のチョボ四点正方形のマーク)でここから普通に拡大・縮小すると比率が維持できないのでShift押しながらやる必要があったり――、
今回はキッチリカッチリ、正確にフィットさせたいので、もう一工夫こらす必要が出てきます。

imageのサイズを「フィットさせる」とは


散々、「フィットさせる」とか「ピッタリ」とか書いてますが、この言葉の定義も曖昧なもので、おそらく三種類のケースが考えられます。

わかりやすい表でまとめられているものを見つけましたので、共有させていただきます。


この記事の通り、imageを枠いっぱいに、となると伸縮・内接・外接の三つがあって、そのうち元の画像のアスペクト比を維持しているものは後の二つです。今回の記事で扱うのは、このうちの内接にあたります。

それでまぁ、この記事にも「内接」の方法が紹介されています。やり方は簡単で、先述した「アスペクト比を保存」にチェックマークをつけたうえで、Rect Transformのアンカープリセット(十字のマークのようなやつ)を"stretch×stretch"に設定、そのうえでアンカープリセットの右にある「左・上・位置Z・右・下」の数値をすべて0にする、というものです。


たしかに、この方法でやると、簡単にCanvasぴったりにimageサイズを調整することができました。

まぁ一つのimageをCanvasいっぱいに、ということであれば、これで解決できます。
しかし、例えばこんな事例であれば、どうでしょうか…?


これで伝わるかはわかりませんが…よくあるRPGのステータスウィンドウですね。
右か左にイラストがあって、隣に情報が表示されている…というようなものを想像してくださると幸いです。

こういうものを作るとなると…先述の方法では難しいのがおわかりでしょうか。

先に紹介した方法では、imageのサイズをCanvasいっぱいにしていますので、情報を表示するTextのUIはimageの上に被せる、という感じになりますよね。それで実際にビルドしたときにきちんとバランスよく表示されるかは、ユーザー側の画面サイズ次第となってしまいます。

imageをCanvasにフィットさせる方法

先行研究(?)の例をあげつつ、実際にしたいことが明確になったところで、この問題の解決策を提案していこうと思います。

スクリプトを一つ書いてアタッチする(だけ)ですが、スクリプト自体は我ながら汎用性の高いと自画自賛できるものを作ることができましたので、皆さんのお役に立てたら幸いです。

なお、スクリプトを書く以外の方法では、アセットストアで便利アセットを求めるというのも一つの手かと思います。


私はスクリプトで解決しましたが、このアセットを使うのであれば、わざわざゲームを実行しなくてもエディタ上で弄って目的を達成できそうですね!ほしい…!

こんな便利なものを紹介してしまうと自分のやり方を説明するのは恐縮の至りですが…、以下、泥臭い方法として、imageを右端に寄せかつimageをCanvasにフィットさせる手順を解説します。

①imageのUIを作成、Imageコンポーネントのソース画像(Source Image)に画像をドラッグ&ドロップする

至って普通のImageの使い方ですね。特に説明はいらないと思います。

②Imageのインスペクター、Rect Transformコンポーネントをいじる

これは右端に寄せるための工程ですね。この記事の本題から外れるところなので軽く書き連ねるだけにとどめますが、

1.左上のアンカープリセットを"Top×Right"


2.アンカープリセット右の数値はすべて0


3.少し下のピボット(Pivot)の数値を、(1,1)にする



こんな感じでできていたら大丈夫です!!

③下記のスクリプトを対象となるImageにアタッチする

お疲れ様でした、もうあとはこれだけです。
難しいスクリプトではないのですが、最悪わからなくてもアタッチすれば大丈夫です(笑)
アタッチした後、ゲームを起動させれば、ちゃんとサイズピッタリにImageが伸び縮みする…はずです…!

気になるスクリプトはこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ImageSizeManager : MonoBehaviour
{
    private float scaleRate;
    // Start is called before the first frame update
    void Start()
    {
        this.GetComponent().preserveAspect = true;
        this.GetComponent().SetNativeSize();
        Vector2 CanvasSize = transform.root.GetComponent().sizeDelta;
        Vector2 ThisImageSize = this.GetComponent().sizeDelta;
        if(CanvasSize.x<CanvasSize.y)
        {
            scaleRate = CanvasSize.x / ThisImageSize.x;
        }
        else
        {
            scaleRate = CanvasSize.y / ThisImageSize.y;
        }
        this.GetComponent<RectTransform>().localScale = new Vector3(scaleRate, scaleRate, 1);
    }
}
はい、こんな感じです!

応用的な活用方法

ここからは少し、さきほど書いたスクリプトの応用的な使い方として、考えられるものについて記しておこうと思います。

①間にPanelを挟む場合

今まではCanvasの子オブジェクトとしてImageのUIを配置することを前提として話を進めてきましたが、Panelをその関係の間に挟むとどうなるのか、という話ですね。

Canvas→Image ではなく、 Canvas→Panel→Image の場合、といったほうがよいでしょうか。

このケースの場合、スクリプトは特に何の変更もなく使うことができます。
"transform.root"を使って直接、一番上位の親オブジェクトであるCanvasを参照しているからなのですが、もし"transform.root"に興味がある方がいましたら、こちらの記事をみていただけるといいかと思います。


②Canvasピッタリ、から少し余裕を作りたい場合

Canvasピッタリにする、というのはここまでずっと紹介してきたのですが、少しそこから余裕を作る場合はどうでしょうか。


上の画像は、Canvasの上下左右に10ずつ離したPanelです。まぁキッチリカッチリではなく少し離す、というのは想定される事例です。

これに対応させる場合、若干スクリプトを弄らなければなりません。とはいえ、そこまで苦でもないのですが。

一つ前の項目で少し書いた通り、このスクリプトはCanvasの縦横サイズを参照するのが基本となってます。

よって、Canvasの縦横サイズから少しずらすのならば、ずらした分だけ調整すればいいだけです。具体的にはこんな感じ。

Vector2 CanvasSize = transform.root.GetComponent().sizeDelta+new Vector2(-20,-20);

スクリプトの12行目のココ。

これがCanvasを参照している部分なので、ここからずれる分を引き算なり足し算すれば大丈夫です。

画像の例だと、私は上下左右に10ずつ余白を作ったので、縦と横、一片の長さをもとのCanvasと比較すると、(ローカル座標で)20短くなっていることがわかります。

それを引き算してスクリプトを保存、完成形はこちら。


ゲームを実行させたうえで、シーンビューから見てみました。
うまくできてますね。

最後に


ここまで読んでくださりありがとうございました。
どうかご自由にスクリプト使ってください~。


ブログランキング・にほんブログ村へ にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ Unityへ にほんブログ村 IT技術ブログ C#へ


自己紹介

自分の写真
大学では文学部日本文学科出身という生粋の文系。チャットゲームの運営の在宅業務に携わったことでプログラミングに興味を持ち、2020年末、SAMURAI ENGINEERに入塾。2021年4月末に卒塾。 ※お問い合わせある方は、ブログのお問い合わせページからどうぞ~

ページビューの合計

応援をお願いします!

もしよかったらTwitterのフォローと応援ポチをよろしくです~
PVアクセスランキング にほんブログ村
ブログランキング・にほんブログ村へにほんブログ村 IT技術ブログへにほんブログ村 IT技術ブログ Unityへ
にほんブログ村 IT技術ブログ C#へ

QooQ