お米 is ライス

C#やらUnityやらを勉強していて、これはメモっといたほうがええやろ、ということを書くつもりです

Unityの新しいGUI機能(uGUI)で実装されたRect Transformの仕様メモ

(初めの10行ぐらいはしょうもないので読まなくていいです)
今年の夏ぐらいにリリースされたUnity4.6のβ版で、前々から告知されていた新しいGUIがやっとこさ使えるようになった。
Unityさん、実はこれまで、GUIを実装するにはAssetに頼らないとスクリプトをごりごり書くしかなかったのだが、実装されたuGUIのおかげでグラフィカルにGUIを作れるようになった。

このuGUIのオブジェクトはほかのUnityのオブジェクトとは違い、「Transform」コンポーネントではなく、これを(多分)継承した「Rect Transform」というコンポーネントがついていて、これでGUIの見た目をいろいろいじるのだけれど、こいつの仕様がちょっとだけわかりにくい(説明動画が英語版しかない)ので動画の英語を頑張って聴いたり、自分でいろいろいじってみてわかったことをメモしておく。(ので信憑性はないです)


(本題こっから)
知っておいてもらいたいことは、

  • uGUIのオブジェクトはGameObjectの中で、CubeやSphereが「3D Object」に分類されているのに対し、「UI」に分類されている。
  • Canvas以外のすべてのUIオブジェクトは、根っこにCanvasがいなければならない。
  • すべてのUIオブジェクトは「Rect Transform」コンポーネントを持っている。
  • Sceneビューに表示されるUIオブジェクトは「1ピクセル=1Unity」の関係になっている。
  • インスペクタ上の値はほとんどピクセル単位である。

という点である。

Rect Transform

f:id:spi_8823:20141026234540p:plain

Anchors

「Rect Transform」は「Transform」とは違い、Positionは単純なVector3では表されていない。
特に、親のUIオブジェクトとの位置関係が単純ではなくなっている。これは画面の大きさが変わった際に、UIの位置や大きさも柔軟に変わる必要があるためである。
uGUIでは、これをAnchorsというものを使って解決している。

Anchorsには、図のようにMin、Maxという2つのVector2変数を持っている。それぞれの値は、0から1までの値をとる。

Min、Maxの値の意味

これが何を表しているかというと、親となっているUIオブジェクトのどの位置を自分の位置の基準にするか、ということである。
それぞれのX、Yの値は、親オブジェクトの幅、高さに対する割合を表している。
つまり、自分が占める領域の規定値(図のA、以下規定領域と呼ぶ)は親に対して「X座標がMin.X~Max.X、Y座標がMin.Y~Max.Y」の四角形領域となる。
f:id:spi_8823:20141027024807p:plain
そして、自分の領域は主にこの規定の領域に対して、左辺は左辺の位置の差、底辺は底辺の位置の差を指定して決定するのである。

しかし、ここでXもしくはYについて、Minの値とMaxの値が一致している場合、例えばMin.X=Max.Xの場合、規定の領域の左辺と右辺が一致してしまうため、この2つの辺を区別する必要はなくなる。したがって最終的な領域の決定の際に決めることが異なってしまうのである。
ここが個人的にややこしい場面だった。
このへんについては後述する。

「PosX ,PosY ,PosZ」, 「Width, Height」, 「Left, Right, Top, Bottom」

これを書きながら調べてたけどすごいややこしい感じで「うっ・・・」ってなった。

まずはじめに言っておくと、Pos○以外の変数は、スクリプトからは直接はいじれない。だって変数が無いんだもの。
じゃあどうなってるの?というのを書いていく。

PosX, PosY, PosZ

こいつらは素直に、RectTransform.Positionの値と一致している。
これは、まあいい(よくない)。
(追記:2021/8/22)
こいつらはRectTransform.anchoredPosition3Dの値と一致しているようです。
初めにこの記事書いた時点ではpositionと一致してたような気がするけど……、仕様変わったんだろうか?
コメントで指摘くださった方ありがとうございます。

Width, Height

ややこしい・・・。
まず知っておかなければならないのが、sizeDeltaという変数である。
sizeDeltaはインスペクタには出てこないものの、こいつらと直接かかわってくるVector2変数である。
この値は、Anchorsで定められた規定領域の幅、高さに対して、実際の領域にどれくらい差があるかを表している。
つまり、規定領域の幅、高さを「W, H」、実際の幅、高さを「w, h」とすると、次の関係が成り立つ。

w = W + sizeDelta.X
h = H + sizeDelta.Y
Left, Right, Top, Bottom

ややこしさMax有頂天エクスカリバー
まず、LeftとBottomについてはそれぞれ、単純に

Left = PosX
Bottom = PosY

なのであるが、
Right、Topについては、こいつらを直接表す変数は無く、PosX、PosYやsizeDeltaなどから、規定領域の辺との距離を求めた値が表示される。
つまりは、ひとつ前で用いたw, W, h, Hを用いて、

Right = -((PosX + w) - W)
Top = -((PosY + h) - H)

となっている。
ここでマイナスの符号がついているのは、RightやTopの値が、領域の内側に対して正の値をとるからである。つまり、規定領域からはみだした分はマイナスなのである。


ここまで読んだらわかったかもしれないが、Pos○と「Width, Height」で表せる情報と、「Left, Right, Bottom, Top」で表せる情報はおんなじである。したがって、インスペクタに表示するのはどちらか一方だけでよい。
これが、Anchorsの項で後述するといった内容である。
要は

  • AnchorsのMin.XとMax.Xが一致しないとき → Left, Rightが表示される

 AnchorsのMin.XとMax.Xが一致するとき  → PosX, Widthが表示される

  • AnchorsのMin.YとMax.Yが一致しないとき → Bottom, Topが表示される

 AnchorsのMin.YとMax.Yが一致するとき  → PosY, Heightが表示される

のである。

Pivot

今まで述べてきたAnchorsやLeft(etc...)によって、UIオブジェクトの大きさがいい感じに決まった。
あとは位置を決めるだけである。
といっても、位置はAnchorsで大体決まっているのだが、Anchorsで決めるのはどうやら親に対する相対的な大きさが主なようで、位置を決めるのに、別にPivotという変数がある。
なので、あとはこいつの値を変えて平行移動するだけだな、と思いきや、こいつの値を変えても見た目が変わらないことがある。
ちょっと試してみたらわかったことだが、

  • Left, Rightがともに0のとき、Pivot.Xは設定しても意味がない
  • Bottom, Topがともに0のとき、Pivot.Yは設定しても意味がない

らしい。

「b」、「F」とかいうボタン

wakewakame

「b」

これを押しておくと、Scene上で位置や大きさをいじるとき、自分の傾きや大きさに依存しなくなるらしい。
実際にやってみると、なるほど、位置を変えるときの座標軸がRotationに応じて傾いていたのが、傾かなくなった。
大きさの座標軸についても同じだったのだが、これを押した状態で大きさを変えると、変な変わり方をして大変煩わしいので、基本押さないでおくのが正解なんじゃないかと思ってしまった。
しかし、押さなかったら例えばY軸の大きさを変えた時、PosXが変わってしまったりして「うーん・・・」って感じ。
位置はともかく、大きさを変えるときは離しておくのが吉っぽい。

「F」

RawEditModeになるらしい。
これを押しておくと、Anchorsの値を変えた時に、形を変えまいとしてLeftやPosYなどの値が勝手に変わってしまうのを無効にしてくれる。
逆に言うと、形が出来上がってからAnchorsの値を変えたくなった時にこれを押したままだと、形が勝手に変わってしまうので、適宜使い分けていきたい。



さて、これでRect Transformのインスペクタに表示されている分に関してはすべて書き終わったのではなかろうか。
結局、慣れないとお話にならないっポイので積極的に使って、慣れていきたいなぁ、と思いましたまる。
図とか使わないとわかりにくかろうなのでそのうち気が向けば追加したいと思います。
間違ってるところとか追加すべきところとかがあったらコメントください。
感想よろしくお願いします。