一枚絵をそこそこどの端末でもきれいに出したい【解像度対応】

今回やりたいこと。

一枚絵をどの端末でもある程度綺麗に表示したい。

  • 一枚絵のうち真ん中からの一定範囲(下の絵だと16:9領域)はどの画面比の端末でも表示したい。
  • 一定範囲よりも縦幅や横幅が広い端末(下の絵だとiPhoneXやipad)では、その分広く表示したい。

f:id:snoopopo:20180424103256p:plain

世の中にはどういう画面比の端末があるのか

こちらのサイトを参考にさせていただきます。

www.livejapantokyo.com

iPhoneとiPadの画面サイズと画素数、解像度、そしてアスペクト比のまとめ【更新中】 | wtpmj.com

上記より傾向としては以下のようなかんじでしょうか。

  • 16:9 … 2018年4月現在一番多いであろう比率。
  • 3:2iPhone 4S系までのiphone
  • 4:3ipad系。
  • 19.5:9 … iPhoneX。画面サイズは2436px × 1125pxなので、だいたい19.5:9になる。
  • 18.5:9Galaxy S8
  • 5:3 … 少ないけど存在する。

まずはこの6種類で考えていきます。

16:9が一番出回っているようなので、その範囲はどの端末でも表示したいですね。

どういう一枚絵を用意すればいいのか

16:9を基準にそれより縦長、または横長の端末はその分広く表示したいと思います。

それではどのような一枚絵を用意すればいいのでしょうか。

一番表示範囲が広い=一番縦長、一番横長なサイズに合わせて一枚絵を用意すれば網羅できそうです。

この6種類のうち、どれが一番縦長横長なのかをみていきましょう。

16:9の高さに対しての横幅の長さは、16/9=1.777f。横幅に対しての高さは9/16=0.5625f

端末 画面比 横長比 縦長比
今一番多いやつ 16 : 9 1.777f 0.5625f
iPhone4Sまでのiphone 3 : 2 1.5f 0.66f
iPad 4 : 3 1.333f 0.75f
iPhoneX 19.5 : 9 2.166f 0.461f
Galaxy S8 18.5:9 2.055f 0.486f
少ないけどある 5 : 3 1.666f 0.6f

これにより、一番横長は、iPhoneX(19.5:9)、縦長はipad系(4:3)ということがわかるので、 基準の16:9とあわせてこの3つの画面比で表示の確認ができればよいということがわかります。

次にこれを元に用意する一枚絵の比はどうなるのかを考えていきます。

まずは横幅から考えてみましょう。

横幅が一番長い、iPhoneXの19.5:9と基準比の16:9でみてみましょう。

f:id:snoopopo:20180424105947p:plain

縦幅が9で同じなので、一枚絵の横幅が19.5なるのは当然ですね。

次に縦幅も同じように考えてみます。

縦幅が一番長い、ipadの4:3と基準比の16:9でみてみます。

f:id:snoopopo:20180424105944p:plain

4:3は横幅を16:9の16と合わせて16:12に変換できるので、 一枚絵の縦幅は12となります。

よって、19.5:12の比率となる一枚絵を用意すれば良さそうですね。

この比率を保った一枚絵であればどのようなものでも表示できるようにしたいと思いますが、 まずはわかりやすいように、1950px × 1200px の画像を用意して動作を確認していきたいと思います。(比の100倍)

同じアスペクト比で解像度の違う端末に対応する

一枚絵をどのくらい拡大(or縮小)すれば良いかscale値を返してくれるメソッドを実装することにします。 これで計算されたscale値を一枚絵のSpriteがアタッチされたTransform#localScaleに設定する、という想定です。

private float GetScale(float width, float height){
    float scale = 1f;  //ここの値を出して
    // 〜scaleだす計算〜
    return scale; //拡大率を返す
}

まずは他の画面比率は考えずに16:9だけを考えてみましょう。

Gameタブのここで画面サイズを指定できます。 f:id:snoopopo:20180423170240p:plain

画面サイズは Screen.widthScreen.heightで取れます。

16:9の画面サイズの場合、1950x1200のうち中心に1600x900の部分だけ表示されればいいということになります。

16:9の端末ならなんでもいいですが、1136x640を例に考えていきます。

一枚絵の一部分1600x900のサイズを、1136x640の画面サイズに合わせるためのscaleを出すには割り算すればいいですね。

(横幅)1136 / 1600 = 0.71f
(縦幅)640 / 900 = 0.71f

画面比が同じ16:9なので、横幅・縦幅どちらもだいたい((1136x640は完璧な16:9ではないので微妙に誤差が出ています))同じ数になるはずです。

private float GetScale(float width, float height){
    int screenWidth = Screen.width;
    int screenHeight = Screen.height;

    Vector2 viewSize = new Vector2(1600, 900); //画面比によってここのサイズが変わる

    float scaleX =  screenWidth / viewSize.x;
    float scaleY =  screenHeight / viewSize.y;
    float scale = scaleX < scaleY ? scaleY : scaleX; //今回は大きい方に合わせる

    return scale;
}

画面サイズを1136x640 にして、1600x900と同じように表示されているか確認しましょう。

次に同じようにiPhoneXサイズについても考えてみます。

iPhoneXの画面比は、19.5:9だったので、16:9の時とは表示したい範囲のサイズが変わります。

private float GetScale(float width, float height){
    int screenWidth = Screen.width;
    int screenHeight = Screen.height;

    Vector2 viewSize = new Vector2(1950, 900); //iPhoneX比率で表示させたいサイズ

    float scaleX =  screenWidth / viewSize.x;
    float scaleY =  screenHeight / viewSize.y;
    float scale = scaleX < scaleY ? scaleY : scaleX; //今回は大きい方に合わせる

    return scale;
}

iPhoneXの実際のサイズ2436px × 1125pxでも問題ないか確認してみましょう。

16:9範囲よりも横に長い部分の範囲まで表示されていることが確認できます。

縦長のipad系についても同様なのでソースは省略しますが、同じように表示したい範囲のサイズが変わります。

   Vector2 viewSize = new Vector2(1600, 1200); //ipad比率で表示させたいサイズ

このように、それぞれの比ごとの表示したい範囲のサイズがわかれば他の比率でも計算ができそうです。

それぞれの画面比で表示したい範囲を計算でだす

これまで書いてきた通り、表示したい範囲のサイズは画面比によって変わります。

この表示したい範囲のサイズは計算で出せないでしょうか。

1600x900 → 1950x900 (iPhoneXの場合)

が出せないかということですね。

16:9アスペクト比に対して、19.5:9が何倍されるかがわかればわかりそうです。

以下のような感じになると思います。

//19.5:12を1950:1200とした場合の、16:9のサイズ。これを基準にする。この範囲はどの端末でも表示される。
private static readonly Vector2 BASE_SIZE = new Vector2(1600, 900); 
private static readonly float ASPECT_WIDTH = BASE_SIZE.x / BASE_SIZE.y; //基準サイズの横幅アスペクト比
private static readonly float ASPECT_HEIGHT = BASE_SIZE.y / BASE_SIZE.x; //基準サイズの高さアスペクト比

private float GetScale(float width, float height){
    int screenWidth = Screen.width;
    int screenHeight = Screen.height;

    Vector2 viewSize;

    float ratioX = (float)screenWidth / (float)screenHeight;
    float ratioY = (float)screenHeight / (float)screenWidth;

    if(ratioX <= ASPECT_WIDTH && ratioY <= ASPECT_HEIGHT){
        viewSize = BASE_SIZE; //16:9よりも縦横どちらも小さいものは基準サイズ
    } else {
        float w = BASE_SIZE.x;
        float y = BASE_SIZE.y;
        if(ASPECT_WIDTH < ratioX){ //基準サイズよりも横が長い
            w *= ratioX / ASPECT_WIDTH;
        }
        if(ASPECT_HEIGHT < ratioY){ //16:9よりも縦が長い
            y *= ratioY / ASPECT_HEIGHT;
        }
        viewSize = new Vector2(w,y);
    }

    float scaleX =  screenWidth / viewSize.x;
    float scaleY =  screenHeight / viewSize.y;
    float scale = scaleX < scaleY ? scaleY : scaleX; //大きい方に合わせる
    
    return scale;
}

19.5:12の一枚絵ならどんなサイズでもいいようにする

ここまでは、19.5:12の一枚絵をわかりやすいように1950px x 1200px でやってきましたが、 19.5:12の比を保っていればどのようなサイズでもいいようにしたいと思います。

private Vector2 GetBaseSize(int imageWidth, int imageHeight){
    Vector2 IMAGE_ASPECT = new Vector2(19.5f, 12f);
    Vector2 VIEW_ASPECT = new Vector2(16f, 9f);

    Vector2 result = new Vector2();

    if(imageWidth < IMAGE_ASPECT.x || imageHeight < IMAGE_ASPECT.y){
        Debug.Log("うまくいかないかも!!");
    }

    result.x = (imageWidth / IMAGE_ASPECT.x) * VIEW_ASPECT.x;
    result.y = (imageHeight / IMAGE_ASPECT.y) * VIEW_ASPECT.y;

    return result;
}