Developer

【初心者Unity】Transformのスクリプト操作まとめ(移動、回転、スケール)
2021.12.23
Lv1

【初心者Unity】Transformのスクリプト操作まとめ(移動、回転、スケール)

1.はじめに

Transformコンポーネントはゲームオブジェクトの位置・回転・大きさを管理するコンポーネントです。
ほとんどのゲームオブジェクトにも必須で付属しているコンポーネントですから、スクリプトで操作する機会も当然に多くなります。
ですが、一部紛らわしい項目などもあり、何を使えば良いのか迷ってしまうこともあるのではないでしょうか。

そこで本記事では、Transformコンポーネントをスクリプトで扱う方法についてまとめてみました。
とは言え、Transformコンポーネントに関連する機能は非常に多く、それら全てを取り上げていると切りが無いため、
Position・Rotation・Scaleに関する代表的なものをピックアップしています。
これらをマスターすれば一通りの動きは実現できるかと思いますので、是非習得してみてください!

2.Position

TransformコンポーネントのPositionはゲームオブジェクトの位置を表すパラメータです。
スクリプトではVector3型の値として扱われます。

値の取得
transform.positionで値を取得することができます。

void Start()
{
    Debug.Log("(x, y, z) = " + transform.position);
    Debug.Log("x = " + transform.position.x);
    Debug.Log("y = " + transform.position.y);
    Debug.Log("z = " + transform.position.z);
}

なお、ゲームオブジェクトが他のゲームオブジェクトの子オブジェクトになっている場合は、上記のスクリプトの結果とInspectorに表示されている値が一致しないことがあります。
これは、Inspectorに表示される値が親オブジェクトからの相対位置であるためです。

Inspectorに表示されている値を取得する場合はtransform.localPositionを使用します。

void Start()
{
    Debug.Log("(x, y, z) = " + transform.localPosition);
    Debug.Log("x = " + transform.localPosition.x);
    Debug.Log("y = " + transform.localPosition.y);
    Debug.Log("z = " + transform.localPosition.z);
}

値の代入
Positionを変化させることで、ゲームオブジェクトを移動させることができます。

void Start()
{
    transform.position = new Vector3(5, 5, 5); // (5, 5, 5)に移動
}

注意したいのは、以下のような書き方はできない点です。

void Start()
{
    transform.position.x = 5; // コンパイルエラー
}

参考:コンパイラ エラー CS1612

X座標のみを書き換えたい場合は、以下のように記述する必要があります。

void Start()
{
    Vector3 position = transform.position; // ローカル変数に格納
    position.x = 5; // ローカル変数に格納した値を上書き
    transform.position = position; // ローカル変数を代入
}

Translateメソッド
移動を専門的に行うTranslateメソッドが用意されています。

void Update()
{
    transform.Translate(1, 0, 0); // (ローカルの)X軸方向に1移動
    transform.Translate(1, 0, 0, Space.World); // ワールドのX軸方向に1移動
    transform.Translate(1, 0, 0, Space.Self); // ローカルのX軸方向に1移動
}

引数にSpace.Worldを指定するとワールド座標での移動となります。
反対に、Space.Selfを指定するとローカル座標での移動となります。
省略した場合は、Space.Selfが補完されます。

3.Rotation

TransformコンポーネントのRotationはゲームオブジェクトの回転角を表すパラメータです。
例えば、Rotation Xの値が90であることは、X軸を中心に90°回転したことを意味します。
スクリプトではQuaternion型またはVector3型の値として扱われます。
ここでは、Vector3型での操作方法を説明します。

値の取得
transform.eulerAnglesで値を取得することができます。
読み方は「オイラーアングルス」です。

void Start()
{
    Debug.Log("(x, y, z) = " + transform.eulerAngles);
    Debug.Log("x = " + transform.eulerAngles.x);
    Debug.Log("y = " + transform.eulerAngles.y);
    Debug.Log("z = " + transform.eulerAngles.z);
}

Positionと同様、子オブジェクトにおいては、スクリプトの結果とInspectorに表示されている値が一致しないことがあります。
これは、Inspectorに表示される値が親オブジェクトからの相対的な回転角であるためです。
Inspectorに表示されている値を取得する場合はlocalEulerAnglesを使用します。

void Start()
{
    Debug.Log("(x, y, z) = " + transform.localEulerAngles);
    Debug.Log("x = " + transform.localEulerAngles.x);
    Debug.Log("y = " + transform.localEulerAngles.y);
    Debug.Log("z = " + transform.localEulerAngles.z);
}

値の代入
Rotationを変化させることで、ゲームオブジェクトを回転させることができます。

void Start()
{
    transform.eulerAngles = new Vector3(45, 0, 0); // X軸を中心に45°回転、Y軸Z軸は初期値
}

Positionと同様、以下のような書き方はできないことに注意してください。

void Start()
{
    transform.eulerAngles.x = 45; // コンパイルエラー
}

X軸の回転角単体を書き換えたい場合は、以下のように記述する必要があります。

void Start()
{
    Vector3 eulerAngles = transform.eulerAngles; // ローカル変数に格納
    eulerAngles.x = 5; // ローカル変数に格納した値を上書き
    transform.eulerAngles = eulerAngles; // ローカル変数を代入
}

Rotateメソッド
回転を専門的に行うRotateメソッドが用意されています。

void Update()
{
    transform.Rotate(1, 0, 0); // (ローカルの)X軸を中心に1°回転
    transform.Rotate(1, 0, 0, Space.World); // ワールドのX軸を中心に1°回転
    transform.Rotate(1, 0, 0, Space.Self); // ローカルのX軸を中心に1°回転
}

引数にSpace.Worldを指定するとワールド座標での移動となります。
反対に、Space.Selfを指定するとローカル座標での移動となります。
省略した場合は、Space.Selfが補完されます。

LookAtメソッド
単にある方向を向かせたい場合にはLookAtメソッドを使用します。

void Start()
{
    Vector3 target = new Vector3(0, 0, 0);
    transform.LookAt(target); // (0, 0, 0)の方向を向く
}

transform.rotationっていうのがあるけど?
transformのプロパティには、eulerAnglesとは別にrotationというものもあります。
名前からすると、こちらがRotationパラメータに対応するプロパティのように思えますが、実際には値が大きく異なります。

例として、Rotationパラメータの値が ( x, y, z ) = ( 90, 0, 0 ) であるゲームオブジェクトに対して、transform.rotationの値を出力してみます。

void Start()
{
    Debug.Log(transform.rotation);
}

結果は、( 0.7, 0.0, 0.0, 0.7 ) と表示されます。
一体どういうことでしょうか?

実は、Unity内部ではゲームオブジェクトの回転を四元数(Quaternion)を用いて計算しています。
四元数の詳細な説明は割愛しますが、これは我々が普段慣れ親しんでいる角度とは全く異なる表現方法で、
先ほど示したtransform.rotationの出力値である、( 0.7, 0.0, 0.0, 0.7 ) がその例となります。
(上で少し触れましたが、transform.rotationはQuaternion型の値となります。)

一方で、Inspectorの表示で採用されているのは、オイラー角と呼ばれる表現方法になります。
オイラー角では、3つの軸に沿った回転角を度数法の値で指定し、3D空間での回転を表しています。

それでは何故、内部の処理とInspectorの表示とで表現方法を分けているのでしょうか?

まず、Inspectorの表示にオイラー角を採用している理由は、単に人間が(直感的に)理解しやすいためです。
先ほど見たように、四元数の表現は馴染みが薄く、値をどう変えたらよいのかイメージが付きにくいですよね。

一方、内部の処理に四元数を採用している理由は、ジンバルロックと呼ばれる制限の影響を受けないためです。
ジンバルロックは、2つの回転軸が同じ向きになってしまう、という現象のことです。
(例えば、X軸を90°回転させたとき、Y軸とZ軸は同じ回転軸になってしまいます。)
オイラー角では、このジンバルロックが発生してしまう可能性があります。

上記の理由により、Rotationはややこしいパラメータとなっていますが、初めの内はオイラー角による操作のみできれば十分かと思います。
オイラー角で操作した場合も、Unity側で自動的に四元数への変換を行ってくれます。

何らかの理由でtransform.rotationを使いたい場合は、オイラー角を四元数に変換するQuaternion.Eulerメソッドを使用すると良いでしょう。

void Start()
{
    transform.rotation = Quaternion.Euler(45, 0, 0); // // X軸を中心に45°回転
}

4.Scale

TransformコンポーネントのScaleはゲームオブジェクトの大きさを表すパラメータです。
単位は現実世界における1mです(細かい物理演算等が伴わない場合はあまり気にすることはないかもしれません)。
スクリプトではVector3型の値として扱われます。

値の取得
transform.lossyScaleで値を取得することができます。

void Start()
{
    Debug.Log("(x, y, z) = " + transform.lossyScale);
    Debug.Log("x = " + transform.lossyScale.x);
    Debug.Log("y = " + transform.lossyScale.y);
    Debug.Log("z = " + transform.lossyScale.z);
}

PositionやRotationと同様、子オブジェクトにおいては、スクリプトの結果とInspectorに表示されている値が一致しないことがあります。
これは、Inspectorに表示される値が親オブジェクトからの相対的な拡大率であるためです。
Inspectorに表示されている値を取得する場合はtransform.localScaleを使用します。

void Start()
{
    Debug.Log("(x, y, z) = " + transform.localScale);
    Debug.Log("x = " + transform.localScale.x);
    Debug.Log("y = " + transform.localScale.y);
    Debug.Log("z = " + transform.localScale.z);
}

値の代入
Scaleを変化させることで、ゲームオブジェクトを拡大・縮小することができます。
ここで注意したいのは、transform.lossyScaleには値の代入ができない点です。
transform.lossyScaleは読み取り専用のプロパティであるため、値の代入はtransform.localScaleで行います。

void Start()
{
    transform.localScale = new Vector3(2, 1, 1); // X軸方向に2倍に拡大
}

PositionやRotationと同様、以下のような書き方はできません。

void Start()
{
    transform.localScale.x = 2; // コンパイルエラー
}

X軸方向のスケール単体を書き換えたい場合は、以下のように記述する必要があります。

void Start()
{
    Vector3 localScale = transform.localScale; // ローカル変数に格納
    localScale.x = 2; // ローカル変数に格納した値を上書き
    transform.localScale = localScale; // ローカル変数を代入
}

5.おわりに

transform.rotationが使いづらかったり、transform.scaleがなかったりと、紛らわしいところもありましたが、整理できましたでしょうか?
今回、覚えることができなくても、「ここはちょっと注意が必要な部分だな」という認識が得られれば、スクリプトが思った通りに動かない!といった事故を未然に防ぐことができるのではないでしょうか。
何度も書いてみて、徐々に使いこなせるようになっていただければと思います!

 

連載目次リンク

「初心者のための」Unityゲーム制作 目次
 

Unity実践編 - 目次リンク

実践Unityゲームプログラミング 連載目次