🧗

SafeAreaなんもわからん

2025/01/13に公開

PlayerLocalUI入れたら勝手についてくるコレ。
あってもなくても実際なんも変わらないよな…?
何者なんだ…SafeAreaァアアア!!!!
という記事です。

SafeAreaが何者であるかを理解して、実際どう使うのか、まで到達したいです。

この記事を2行でまとめる

  • SafeAreaはRectTransformで範囲を指定するだけ。
  • なのでUI要素を0とか1にアンカーして使う。

まずは公式ドキュメントだ

Safe Area コンポーネント

このコンポーネントが追加されたGame Objectは、デバイスごとにシステムUIを考慮した位置になるよう Rect Transform が設定されます。
このコンポーネントが追加されたGame ObjectのRect Transformに対し相対的にUI要素を配置することで、デバイスごとに適した位置に表示できます。

なる、ほど…?????

Player Local UI コンポーネント

Render Mode が ScreenSpaceOverlay の場合、UIを Safe Area コンポーネントのついたオブジェクトの子に配置することでデバイスごとに適した位置に表示できます。

なるほど、UIはSafeAreaの子に配置するのか!!!!!

なんで子に配置するとデバイスごとに適した位置に表示できるんだ…?
いやその前に、デバイスごとに適した位置ってなんだ…???

Safe Area コンポーネント

画像は Scope ごとのセーフエリアの違いを示しています。
それぞれ Legacy(緑)、System(赤)、Device(黄)のオプションに応じてセーフエリアの大きさが変化します(実際には端末によって違います)。


公式より転載

なるほど。そういえばclusterアプリは左右とか下にUIある(あった)な。
デバイスごとの適した位置というのはこの枠(セーフエリア)内のことか!!!

つまりSafeAreaは、UIをこの枠(セーフエリア)内に収めてくれるのか…?

RectTransformから逃げてきた

Safe Area コンポーネント

このコンポーネントが追加されたGame Objectは、デバイスごとにシステムUIを考慮した位置になるよう Rect Transform が設定されます。
このコンポーネントが追加されたGame ObjectのRect Transformに対し相対的にUI要素を配置することで、デバイスごとに適した位置に表示できます。

ああ、公式ドキュメントにそう書いてあったな…。

イヤな文字が見えてきた。RectTransform、コイツは本当によくわからないし、ずっと逃げてきた。しかし、SafeAreaを扱うなら、RectTransformは必須ということか。

しかたない。RectTransformに言及している部分を見るか。

このコンポーネントが追加されたGame Objectは、デバイスごとにシステムUIを考慮した位置になるよう Rect Transform が設定されます

ああ、そういえばRectTransformが自動設定みたいになってたな。
あれはそういうことか!!!

このコンポーネントが追加されたGame ObjectのRect Transformに対し相対的にUI要素を配置することで、デバイスごとに適した位置に表示できます。

相対的…???そういえば、UIはSafeAreaの子に配置しろ、ってあったな。
SafeAreaの子なら、SafeAreaに対して相対的と言っていいんだろうか?

まあ、ともかくやってみよう。

よし、SafeAreaの子に配置したぞ。

これでアップロードして、確認してみるぜ!!

めっちゃはみ出してるやんけ!!!!!!
どうしてなんだよおおおおお!!!!!!!!!!!!!!!

相対的って単純に子にするだけじゃダメなのか…?

雰囲気でAnchorしている

そういえば、SafeAreaに変なボタンがあったな…?

Safe Area コンポーネント

Anchor自動設定ボタンを押すことにより、子オブジェクトの追従位置を自動で設定することもできます。

追従位置を自動で設定とは…?
まあ、公式が用意しているぐらいだから、よく分からないが押す必要があったんだな。

よし、とりあえず押してみた。しかし何か変わったのか…?
まあアップロードしてみるか。

?!?!?!??!?!?!
すげええええええええええええ!!!!!
画面内に収まってるやん!!!!!!!!!!!!!
しかも左下の手の記号(Z)の分ちゃんと隙間が空いてるが…?!?!?
これがSafeAreaのチカラ…!??!?

あのボタン、一体何をしたんだ…?


左が押す前 右が押した後

さっきは気づかなかったが、インスペクタを比較してみると差があるな…?

  • 位置X、位置Y(Pos X、Pox Y)
    なんかすごい動いてる。シーンビュー上だと変わってないように見えるが…?
  • アンカー(Anchor)
    0.5だったのが0とか1になってる。左上の十字マークのアイコン?も変化してる。

さっき押したボタンは「Anchor自動設定」ボタンだったな。
つまりセーフエリア内に収めるのに重要なのはアンカーの方…?!

いつも0.5のままにしてたわ…変更しても位置の数字が変わるだけで差がなかったしな…。
これRectTransformで一番意味が分からないやつなんだよな…。

Safe Area コンポーネント

Unity UIの配置については基本的なレイアウトも参照してください。

ということで、Unity公式を見てみる。

基本的なレイアウト

Rect Transform には アンカー というレイアウトの概念があります。
子の Rect Transform はさまざまな方法で親の Rect Transform に固定することができます。例えば、子は親の中心か、角の一つに固定することができます。

な、なんだと?!?!??!?!
アンカーってそういう機能だったのか!!!!!!!!

なるほど、つまりこの文を読み替えると、

「Anchor自動設定」ボタンを押すと、UI(子の Rect Transform)をSafeArea(親の Rect Transform)に固定することができます。

ということか!!!!!!

そういえば、SafeAreaはデバイスごとの表示に適した枠のことだったな。
つまりその枠(SafeArea)にUIを固定することで、デバイスごとに適した位置に表示できるということか!!!!

大体わかった気がする。改めてSafeAreaのドキュメントを確認してみるか。

Safe Area コンポーネント

このコンポーネントが追加されたGame Objectは、デバイスごとにシステムUIを考慮した位置になるよう Rect Transform が設定されます。
このコンポーネントが追加されたGame ObjectのRect Transformに対し相対的にUI要素を配置することで、デバイスごとに適した位置に表示できます。

なるほどな!!!!!

SafeAreaはつまりRectTransformを設定する機能で、
そのSafeAreaに設定されたRectTransformの子に、
UI要素を配置してアンカーで固定。
という使い方になるわけか。

相対的というのは、子に配置した上でアンカーを使えということか!!!
完全に理解した!!!!!!!!!

まあ、RectTransformの詳しい使い方はまだ分からないままだが…。

RectTransformに向き合う

既に世にある記事が最強だ!!!

SafeAreaは実際何をしているのか

幸いにしてCCKで公開されている部分なので確認してみる。
https://github.com/ClusterVR/ClusterCreatorKit/blob/master/Runtime/World/Implements/PlayerLocalUI/SafeArea.cs#L22-L34
https://github.com/ClusterVR/ClusterCreatorKit/blob/master/Runtime/World/Implements/PlayerLocalUI/SafeArea.cs#L48-L59
ドキュメントの通り、決められた範囲になるようにRectTransformを設定しているだけのようだ。

「Anchor自動設定」ボタンの方も確認してみる。
https://github.com/ClusterVR/ClusterCreatorKit/blob/master/Editor/Custom/SafeAreaEditor.cs#L40-L57
画面を3x3に分割して、左側にあるなら左側にアンカー、右側にあるなら右側にアンカー、という処理のようだ(あと上下も)。
特殊な処理をしているわけではなさそうだから、アンカーの理屈が分かれば手動でアンカーしてもよさそう。

SafeArea完全に理解した!!!

よきCCKライフを!!!!!!!!!

おまけ

その1:SafeAreaの先にある罠

https://github.com/ClusterVR/ClusterCreatorKit/blob/master/Runtime/World/Implements/PlayerLocalUI/PlayerLocalUI.cs#L64-L72

CanvasScalerscreenMatchModematchWidthOrHeightが固定されてるってマジか…。

このあたりはこちらの記事のように使います。
https://light11.hatenadiary.com/entry/2019/04/21/222337

その2:Screen Match ModeのExpandを再現するスクリプト(宣伝)

変更できないならスクリプトで制御したるわ!というアセットです。
https://vkao.booth.pm/items/6476762

固定アスペクト比レイアウトの場合は、AspectRatioFitterという手もあります。

Discussion