Help us understand the problem. What is going on with this article?

【Unity】これ以上セーフエリア対応で消耗しないためのアセットを作った【AutoScreen】

AutoScreen(GitHub)

AutoScreen_01.gif
AutoScreen_02.gif

はじめに

Unityにおけるセーフエリアの対応に関してはScreen.safeAreaというAPIがあるのですが、ビルドして実機で呼ばないと端末ごとの値が取れない=エディタ上ではレイアウトの確認ができないという辛さがあります。

最近だとUnite Tokyo 2019でも紹介されたDevice Simulatorが記憶に新しいところですが、このパッケージはUnity2019.3からでないと使用できず、まだプレビュー版となっています。

個人的な感覚ではUnityはたとえLTS版であってもある程度時間が経つまでは本番で使用するのが怖いので、自分が実際にDevice Simulatorを使えるようになるのは2020年の後半になる気がしています。

そんなに待ってられないよ!ということでUniSafeAreaAdjusterをありがたく使わせてもらってたのですが

  • 解像度に合わせて端末を選択するのが面倒
    • 特に複数のGameObjectSafeAreaAdjusterコンポーネントをつけてるとき
  • デバイスのフレーム表示機能がほしい
  • 手軽に対応端末を追加・拡張できるようにしたい

という気持ちがピークに達して自分でアセットを作ってしまったのでご紹介します。

便宜上「アセット」と書いてますがアセットストアに公開するのはけっこう面倒なのでGitHubでだけ公開しています。

↓↓↓↓↓↓↓
AutoScreen(GitHub)

READMEがまだないのですが、そのうち本記事を元に英語で書くと思います。

機能

  • モバイル実機上でセーフエリアに応じてRectTransformのアンカーを自動調整するコンポーネント
    • SafeArea:セーフエリア用(適用したい方向を上下左右自由に組み合わせ可)
    • UnsafeArea:非セーフエリア用(上下左右どれか選択)
    • RuntimeSafeAreaUpdater:画面の回転を自動検知してSafeArea,UnsafeAreaを更新
  • エディタ上でセーフエリアをリアルタイムプレビュー
    • 既存のGameウィンドウでセーフエリアあり端末の解像度を選択するだけ(追加作業なし)
    • 再生/非再生の状態に関係なく即時反映
  • on/off可能なオプション
    • デバイスのフレームを表示
    • セーフエリアの境界線表示

対応状況

  • Unity2018.3以降対応(Device Simulatorは未対応)
  • iOS:実機・エディタともに対応
    • iPhone X/XS/11 Pro
    • iPhone XS Max/11 Pro Max
    • iPhone XR
    • iPad Pro (第3世代, 11インチ)
    • iPad Pro (第3世代, 12.9インチ)
  • Android:実機のみ対応

Android端末のエディタプレビューは以下の理由でオミットしています。

  • 個人的にAndroid端末にビルドする必要性がない
  • フレーム画像と解像度・セーフエリアデータの収集に手間がかかる
  • 対応が必要な端末数が多そう

端末のマスターデータの追加自体は簡単なので、必要に応じて後述の手順を参考に自分で足してください。

インストール方法

リポジトリ内に*.unitypackageファイルがあるのでこちらを使用してください。

使い方

とりあえず動作を確認してみたい場合はDemoシーンを用意してあるのでいじってみたりビルドしてみてください。

セーフエリアの自動調整機能

Canvas直下のGameObjectSafeArea/UnsafeAreaコンポーネントをAddComponentするとRectTransformAnchorが自動で調整されます。直下じゃなくてもCanvasに至るまでの親GameObjectRectTransformがすべて縦横に完全にストレッチするようにしてあれば正常に動作します。

スクリーンショット 2019-11-24 11.27.57.png
GameObjectが存在する場合のRectTransformの設定

デバイスのフレーム表示/セーフエリアの範囲表示

セーフエリアありの端末解像度を選択するとGameウィンドウの左上に歯車アイコンが表示されるので、そこから表示・非表示を切り替え可能です。

こだわった点

基本的には以下の3点を追求しました。

  • uGUIのオートレイアウトのような簡単で自然な使い心地
  • 使ってて細かい挙動を含めイライラしない
  • シンプルかつ高い拡張性

リアルタイムプレビュー

  • エディタ上で
  • 既存のGameウィンドウの解像度選択を変更するだけで
  • リアルタイムに
  • 再生/非再生の状態を問わず
  • セーフエリアあり端末での見た目が自動で調整

されるので、ビルドしなくてもセーフエリアありの場合のレイアウトを手軽に確認できます。

設定変更がGameウィンドウから可能

通常アセットやエディタの拡張の設定は[MenuItem]を使用してグローバルメニュー(+ショートカットキー)から行えるようにするのですが、Gameウィンドウ上に設定のUIを配置することでon/off切り替えの煩雑さを軽減しました。

ちなみにUIの配置にはUIElementsを使用しています。

高い拡張性

端末解像度とセーフエリアの情報はScriptableObjectを継承したアセットとして保持しているので、追加・拡張が簡単にできます。

SafeArea,UnsafeAreaコンポーネントで満たせない複雑な要件の場合も、SafeAreaBaseクラスを継承することでエディタ上でのリアルタイムプレビューの機能が簡単に実装できます。

Gitフレンドリー

セーフエリアの対応はRectTransformのアンカーを自動調整することで実現していますが、シーンやプレハブの保存前に必ずアンカーをリセットしています。

これにより「Gameウィンドウで異なる解像度を選択して保存 → Gitでdiffが出る」ということが起きません。

実装の詳細

Gameウィンドウの情報を利用するにあたり、Gameウィンドウの実態であるGameViewクラスが公開されていないため、リフレクションを用いてそのデータにアクセスしています。

実際にリフレクションを用いているのはGameViewProxyクラスのみで、値の変更についてはGameViewEventクラスが監視・イベント化しています。

実機のフレーム表示は前もって用意したフレーム画像を描画していて、セーフエリアの大きさは事前にシミュレータビルドで収集した値をScriptableObjectを継承したGameViewScreenアセットに保存・使用しています。

デバイスのフレーム表示とセーフエリアの境界線表示はそれぞれDeviceFrameDrawerコンポーネントとSafeAreaDrawerコンポーネントが行っていて、それらのコンポーネントがアタッチされたAutoScreenManagerプレハブが自動的にHierarchyに配置されるようになっています。このプレハブインスタンスはシーンやビルドには含まれず、Hierarchyにも表示されません。

対応端末追加の手順

エディタ上でのプレビューはマスターデータを追加するだけで簡単に対応機種を増やすことが可能です。

  1. Gameウィンドウから手作業で解像度を追加します。自動化したい場合はGameViewSizeHelperを使うと良いです。
  2. Projectウィンドウで右クリックし、Create -> ScriptableObjects -> GameViewScreenからマスターデータを保持するためのアセットを作成します。
  3. 2.で作成したアセットの各値をInspectorウィンドウから設定します。
    • 解像度やセーフエリアの値はDemoシーンをシミュレータや実機にビルドして確認すると楽です。
    • Base Textは1.で追加した解像度のLabelと同じ文字列にしてください。
    • 必要であればデバイスのフレーム画像を追加し、アセットのFrameにセットしてください。
  4. 解像度を適当に変更すると反映されます。Unityを再起動する必要はありません。

Tips

  • 自動で追加されるRuntimeSafeAreaUpdaterコンポーネントは画面の回転を許可していないアプリの場合は不要
  • 11インチのiPadはGameウィンドウから解像度を登録するとプレビュー可能
    • デフォルトだとUnityに解像度が登録されてない
    • ラベル名は「iPadPro 2388x1668 Landscape」「iPadPro 2388x1668 Portrait」で登録する
  • 12インチのiPadの解像度を選択するとセーフエリアあり(第3世代)としてプレビュー表示される
    • 第1〜2世代のセーフエリアなしレイアウトを確認したい場合は適当なラベル名で別途解像度を追加すればOK
  • セーフエリア境界線の太さ・色はAutoScreenManagerプレハブから調整可能
  • SafeAreaDrawerコンポーネントは単体で実機でも動作可能

ライセンス

MIT

参考

最後に

やりたいことや細かい挙動の調整を全部やろうとしたら結果的に

  • 新しいプレハブAPIの使い方
  • UIElements
  • [ExecuteAlways]
  • HideFlags

等々Unityのよく知らなかった様々な機能について詳しく知る良い機会になりました。個別の知見についてはアドベントカレンダーのときにでもまとめたいと思います。

コードにコメント書かないマンなのですがコード自体はシンプルで読みやすいと思うので、わからないことがあったらとりあえずコードを読んでみてください。

実は実践未投入なので、何か不具合があればPRかTwitterへ → @su10_dev

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away