【Unity】モバイルゲームを全画面で全機種対応させる

# ○はじめに
前回、**固定解像度で各機種対応**させましたが、**黒い帯だったり狭いゲーム画面だったり**、ちょっとダサいので、**今回は全解像度に対応させて、全画面かつ全機種でプレイできるようにします**。


前回の記事↓

https://qiita.com/kiku09020/items/3b324a1d956f757f974c





# ○実行結果
こんな感じになります。
**UIは機種に応じて場所を変化し、ゲームオブジェクトは画面内に収まるようにしています。**
**また、UIがiPhone12などの上部分のやつ(ノッチ)に隠れないような設定もしています。**

![mobile_aspect_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/f21b5f29-a816-377c-be05-5cfa0222ef02.gif)


また、実機で試してみると、**ちゃんとノッチを避けてUIが配置されています。**(色々あって上のGifとは構成が異なってます。ややこしくてすいません)

![android_全画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/d4779bb6-d030-a842-b7e0-57416506948b.jpeg)

## ●リポジトリ
リポジトリです。Androidを持っている方は、ぜひ実機テストしてみてください。
**※Unityバージョンは2021.3.8f1です。**
インストールするのが面倒な方は、DeviceSimulatorを別途でインポートしてください。

https://github.com/kiku09020/MobileCameraTest



# ○説明
## ●範囲内に収めるカメラ
Cameraコンポーネントの`orthographicSize`を機種の解像度に合わせて動的に変更しています。
現在の画面のアスペクト比と目標のアスペクト比から、`orthographicSize`を求めます。

**`目標のアスペクト比：目標アス比のときのカメラサイズ = 現在のアスペクト比：orthographicSize`**

アスペクト比は、**`縦の解像度/横の解像度`** で求まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/23edee93-2fbb-9829-f89e-8d3058edb8f5.png)


## ●UI
**`RectTransform`の`anchor`を、解像度と`DeviceSimulatorのSafeArea`から求めます。**
(**※`DeviceSimulator`をインポートする必要があります。**)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/dd4c3c69-e955-2002-1d7a-d567f57e7324.png)


## ●Canvas

:::note alert


**※`Canvas`コンポーネントの`RenderType`を`ScreenSpace - Camera`にして、Unityを再起動すると、`SafeArea`の`anchoredPosition`(LeftとかRight)がすべて`NaN`と表示されてしまいます。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/2604e37f-1d33-a138-0785-6dc228a0f3d2.png)

※**シーン切り替えによって解消します**。随時バグ修正します。
(原因や対処法があればぜひコメントくださいませ…！！)




:::

また、`CanvasScaler`コンポーネントは、`ScaleWitfhScreenSize`に設定して、`ReferenceResolution`に目的の解像度を設定してください。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/87eaae05-9f2f-aa03-b601-f61a0aec59a6.png)



# ○コード
## ●CameraResizer
機種に合わせて`orthographicSize`を変更します。

```C#
[ExecuteAlways]
public class CameraResizer : MonoBehaviour
{
    [SerializeField] Vector2 targetResolution;
    [SerializeField] float targetOrthographicSize = 5;

    Camera camera;

    private void Start()
    {
        camera = GetComponent<Camera>();
    }

    private void Update()
    {
        ResizeCameraOrthographicSize();
    }

    void ResizeCameraOrthographicSize()
    {
        var currentResolution = new Vector2(Screen.width, Screen.height);
        var targetAspect = targetResolution.x / targetResolution.y;
        var currentAspect = currentResolution.x / currentResolution.y;

        if (currentAspect >= targetAspect) {
            camera.orthographicSize = targetOrthographicSize;
            return;
        }

        var orthoGraphicSize = targetOrthographicSize * (targetAspect / currentAspect);
        camera.orthographicSize = orthoGraphicSize;
    }
}

```



:::note
**Point💡**
- `[ExecuteAlways]`属性で、再生していなくても更新処理をします。
- **`targetRatio:targetCameraSize = currentRatio:size`(比例式)で`orthographicSize`を求めます。(ここ↓)**
```.cs
var size = (targetCameraSize * currentRatio) / targetRatio;
```

:::



## ●SetSafeArea
**`RectTramsform`の`anchor`を変更します**

```SetSafeArea.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteAlways,RequireComponent(typeof(RectTransform))]
public class SetSafeArea : MonoBehaviour
{
	RectTransform rect;

	private void Awake()
	{
		rect = GetComponent<RectTransform>();
	}

	private void Update()
	{
		if (UnityEngine.Device.SystemInfo.deviceType == DeviceType.Handheld) {
			var area = Screen.safeArea;
			var resolution = Screen.currentResolution;

			rect.sizeDelta = Vector2.zero;
			rect.anchorMin = new Vector2(area.xMin / resolution.width, area.yMin / resolution.height);
			rect.anchorMax = new Vector2(area.xMax / resolution.width, area.yMax / resolution.height);
		}

		else {
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
		}
	}
}

```

:::note
**Point💡**
- if文の箇所で、デバイスの種類がスマホだったら(Simulatorビューがアクティブだったら)実装するようにしています。(**ゲームビューでもセーフエリアを適用すると、UI表示がおかしくなるため。**)
    - その際、**`SystemInfo`の`namespace`を`UnityEngine.Device`にしないと、Editor上では正常に判定されません。**([詳細](https://issuetracker.unity3d.com/issues/device-simulator-systeminfo-dot-devicetype-returns-desktop-when-the-simulator-is-active))
- **`SafeArea/解像度`で`anchor`を求めます。**

:::



# ○さいごに
Device Simulator、すごい便利です。
モバイルゲーム開発では必須といっても過言ではないかもですね！！！

また、**UIについては、Androidに備わっている画面分割という機能にも対応しています。↓**

![HiroshiAbe.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/98a920d2-2128-466b-b661-7312a9cbffe4.gif)


折り畳みスマホの普及などで、画面分割機能は今後頻繁に使われそうなので、カメラについても画面分割に対応していきたいです。




<!-- 次回の記事
次回の記事→[次回の記事]()
-->


## ●参考サイト
https://tech.pjin.jp/blog/2021/07/30/unity_break-the-box-25/

https://tsubakit1.hateblo.jp/entry/2019/10/30/235150

https://issuetracker.unity3d.com/issues/device-simulator-systeminfo-dot-devicetype-returns-desktop-when-the-simulator-is-active

https://docs.unity3d.com/2021.2/Documentation/Manual/device-simulator-simulated-classes.html

<!---------------------->

<!-- テンプレ
# ○見出し1
## ●見出し2
### ・見出し3

-->