【Unity】iPhoneX対応の罠 なぜかCanvasのAnchorがずれる問題の解決策
概要
遅ればせながら、今開発中の新作ゲームでiPhoneX対応を行うことになりました。
ネットを検索するといろんな情報が溢れていますが、まずは公式情報を・・・ということでUnity公式のサンプルを元に対応を進めた結果、見事に地雷を踏んだので共有しておきます。
Unity公式情報
iPhoneXの画面問題は業界的にもかなり迷惑なものでした。
Unityもいち早くこの問題に向き合い、パッチリリースを経て正式にSafeAreaに対応しています。
helpdesk.unity3d.co.jp
Unity - Scripting API: Screen.safeArea
一つ目のリンクからUnityのサンプルをみることができます。
そのサンプルの内容は、要約すると以下の通りです。
void ApplySafeArea()
{
var area = Screen.safeArea;
var anchorMin = area.position;
var anchorMax = area.position + area.size;
anchorMin.x /= Screen.width;
anchorMin.y /= Screen.height;
anchorMax.x /= Screen.width;
anchorMax.y /= Screen.height;
panel.anchorMin = anchorMin;
panel.anchorMax = anchorMax;
}
サンプルの罠
上記のサンプルですが、特定の状況下で不具合を引き起こします。
私が遭遇した不具合は、以下のようなものです。
- CanvasのAnchorが右上にずれる
- 一部のUIが明滅を繰り返すようになる
原因
上記に書いた不具合は、Screen.SetResolutionで画面解像度を変更している場合に発生します。
原因は、anchorMin/anchorMaxの各要素をScreen.width/heightで正規化している部分です。
Screen.width/heightは、SetResolution以降は指定した解像度を返すようになります。
しかし、Screen.safeAreaで返される値はディスプレイの解像度のため、正規化の計算が狂い、CanvasのAnchorが右上にずれてしまうわけです。
対応
デバイスのディスプレイ解像度をDisplayクラスから取得し、その値で正規化することで問題を解決することができます。
void ApplySafeArea() { var area = Screen.safeArea; var display = Display.displays[0]; var screenSize = new Vector2Int(display.systemWidth, display.systemHeght); var anchorMin = area.position; var anchorMax = area.position + area.size; anchorMin.x /= screenSize.x; anchorMin.y /= screenSize.y; anchorMax.x /= screenSize.x; anchorMax.y /= screenSize.y; panel.anchorMin = anchorMin; panel.anchorMax = anchorMax; }