今回はすごく大事だけど、ついつい忘れてしまいがちな、World TransformとLocal Transformについて書いておきます。
Transformは空のゲーム・オブジェクトであっても、少なくともこのコンポーネントは持たなければならない、という意味でUnityにおいて最も重要なコンポーネントであると言えます。
位置(Position)と回転(Rotation)、スケール(Scale)の情報を持ち、インスペクター上ではそれぞれVector3(3次元ベクトル)で表されています。
今回、書き記しておきたいことは、このTransformコンポーネントがそのオブジェクトの親子関係やヒエラルキー上のどこに居るかで性質が変わる、ということです。
ヒエラルキーに直接置かれた場合、つまり、親オブジェクトを持たない、あるいは自身が親オブジェクトである場合は、このTransformコンポーネントはWorld Transformとなります。つまり、この時はWorld TransformとLocal Transformの値が一致します。
子オブジェクトになった場合、そのTransformコンポーネントがインスペクター上で表すのはLocal Transformです。親オブジェクトがシーンの原点にいないと、World TransformとLocal Transformはそれぞれ異なる値になります。
今回のケースでは、Parentという箱のオブジェクトの下にChildというボールのオブジェクトを置いています。
ここでParentオブジェクトを横に動かしてみます。当然、Childであるボールは子オブジェクトなので、親である箱と一緒に動きます。
Parent(箱)の元々の座標は(0.0, 0.5, 0.0)だったので3メートルだけ右に動いたことになります。ここで、子オブジェクトのインスペクターを見てみます。
記事の最初に貼ってあるインスペクターの画像は、子オブジェクトの初期位置のモノでした。つまり、この画像を見てわかるように親オブジェクトが動いたのに、ボールの座標が変わっていません。
これはつまり、このTransformコンポーネントがLocal Transformを表しているからです。
ここで実験用のスクリプトを子オブジェクトにアタッチして実行してみます。単にWorld PositionとLocal Positionをコンソールに表示するだけのものです。
これをChild、つまりボールのオブジェクトに付けてプレイモードを実行します。するとコンソールに次のように表示されます。
ご覧のように異なる値が表示され、Local Positionの方は先ほどのインスペクターの画像と一致します。World Positonがシーンの原点(0.0, 0.0, 0.0)を基準とした座標を表しているのに対して、Local Positionは親オブジェクトの位置を基準とした空間(子オブジェクトのローカル空間)の座標を表しているわけです。
transform.localPositionは親オブジェクトの挙動を気にすることなく、そのローカル空間でどの位置に置くか、あるいは移動させるかの処理をする時に使えます。
今回は座標(Position)についてのみで、回転やスケールは省略しましたが、WorldとLocalの関係性は同様です。
今回書いたことは基本中の基本ではあるんですが、特に表示が変わるわけでもないし、つい忘れてしまうんですよね。そしてワールド座標とローカル座標を混同した処理をしてしまって、何かおかしなことになるわけです。
Unityでは複数のオブジェクトを階層を使って組み合わせることは多いですし、あるオブジェクトの階層下にあるオブジェクトを動かしたりする時などに、おかしなことが起きたら、今扱っているTransformはWorldなのかLocalなのかの確認をするといいかもしれません。