【コピペでUnity】ややこしいTransform(トランスフォーム)を爆速で理解する

Unity
Unity

ゲームオブジェクトのTransformを操作したい人

unityのtransformにまつわるコードの書き方を知りたい。
Transformの意味を詳しく知りたい、Rigidbodyとかとは何が違うんだろう?

こういった疑問に答えます。

 

本記事の内容

●Transformのサンプルコード、コピペOK
●UnityでのTransfromの役割
●Transformサンプルコードの詳細

この記事を書いている私は12才からフルスクラッチでゲームを作っています。
またコンパイラを専門として情報理工学の博士まで進学、中退をしており、プログラミング言語の文法にも関わる論文を書いていました。

 

本記事ではサクっと使える実行済みのコードを紹介しつつ、応用のための知識にも触れていきたいと思います。

※実行環境:Unity2021.3.1f1

 

Transformのサンプルコード、コピペOK

必要な名前を埋めるだけで使えるサンプルコードです。
挙動の確認はとりあえずDebug.Log(_transform.各種取得関数)などがオススメ。

 

インスタンス取得

//関数GetComponent<Transform>:Transformコンポーネントのインスタンスを取得
//学習用、Transformがコンポーネントであるという意識をする
Transform _transform = GetComponent<Transform>();

//変数transform:実用的にはこっち
Transform _transform = transform;

//変数parent:親オブジェクトを取得
Transform _transform = transform.parent;

 

座標取得

//変数position:ワールド座標
_transform.position;

//変数position:ローカル座標
_transform.localPosition;

 

座標更新

//Vector3インスタンス:代入で座標を更新
_transform.position = _vector3;
_transform.localPosition = _vector3;

//関数Translate:ローカルx,y,z座標における移動量を指定
_transform.Translate (1.0f, 1.0f, 1.0f);

//Space.Worldを第4引数に指定:ワールドx,y,z座標における移動量を指定
_transform.Translate (1.0f, 1.0f, 1.0f, Space.World);

 

回転値取得

//変数eulerAngles:ワールド回転値
_transform.eulerAngles;

//変数eulerAngles:ローカル回転値
_transform.localEulerAngles;

 

回転座標更新

//Vector3インスタンス:代入で回転値を更新
_transform.eulerAngles = _vector3;
_transform.localEulerAngles = _vector3;

//関数Translate:ローカルx,y,z座標における回転量を指定
_transform.Rotate(1.0f, 1.0f, 1.0f);

//関数Translate:ワールドx,y,z座標における回転量を指定
_transform.Rotate(1.0f, 1.0f, 1.0f, Space.World);

//関数LookAt:ワールド座標の1点をTransformインスタンスで指定
//その点に向けて回転値が設定される
_transform.LookAt(_vector3)

 

拡大率関連

//変数lossyScale:ワールド拡大率
_transform.lossyScale;

//変数localScale:ローカル拡大率
_transform.localScale;

//Vector3インスタンス:代入で拡大率を更新
_transform.localScale = _vector3;

 

●_transform
Transformコンポーネントのインスタンスを保存したい変数名

●_vector3
Vector3インスタンスの変数名
new Vector3(x, y, z)で新しく作成してもよい

 

UnityでのTransfromの役割

ゲームオブジェクトにアタッチできる、コンポーネントのひとつです。
参考:【コピペでUnity】コンポーネント(Component)の基礎【完全に理解する】

 

座標、回転量、拡大率を管理する

インスペクタで編集できるのはオブジェクトの、

●ローカル座標
●ローカル回転量
●ローカル拡大率

です。

 

unityのスクリプトは[SerializeField]などで編集可能になるので、

[SerializeField] float _localposition_vector3_x;
[SerializeField] float _localposition_vector3_y;
[SerializeField] float _localposition_vector3_z;

のようなコードだとイメージすると分かりやすいと思います。

 

はじめの内に混同しがちなのはRigidbodyやColliderとの違いですが、
Transformには物理演算や当たり判定の機能は存在していません。
純粋に座標を管理しているだけです。

だからこそRigidbodyやColliderなどのコンポーネントをアタッチすることで、
ゲームの実装を進めることが出来るようになるワケです。

 

オブジェクトの親子関係を管理する

ヒエラルキーウィンドウにて、
ゲームオブジェクトは他のゲームオブジェクトを内包することが出来ます。
これが親子関係そのものです。

_transform.parentを書きかえると、
ヒエラルキーウィンドウも書き換わることが確認できます。

 

例えば、

_transform.parent = null;

これを実行すると、シーン直下にゲームオブジェクトが移動します。

 

 

Transformサンプルコードの詳細

インスタンス取得

関数GetComponentで他のコンポーネント同様コンポーネント取得が出来ます。

ただしMonoBehaviourから継承した変数transformがあるので、
動作速度という意味でもtransformの使用をオススメします。

 

座標関連

ワールド座標、ローカル座標ともにインスタンス変数として取得、更新が出来ます。
代入の場合はVector3インスタンスが必要になるのでそこだけ気を付けましょう。

とはいえVector3のコンストラクタにfloat型の数値を並べればいいだけなので、
感覚的にもインスペクタを操作していることと変わらないと思います。

 

またTranslateの第4引数だけ少しトリッキーですが、
例えばオブジェクトが回転した際は、ローカル座標とワールド座標の角度が変わります。
よって平行移動で進む方向も変わると考えれば使い分ける必要性も納得できるでしょう。

 

回転値関連

座標同様、ワールド回転値、ローカル回転値ともにインスタンス変数として取得、更新が出来ます。
代入の場合はVector3インスタンスが必要になのも同じです。

関数Rotateも関数Translateと理屈は同じですが、
ローカルとワールドの違いが直感的には分かりづらい気がします。

 

回転の場合は、xyzいずれかの軸で回転させたときに、
別の軸の向きが変わってしまう、というところがミソです。

仮に初期状態からy軸で10度回転させた場合、
初期状態と現在のx軸の向きは異なります。

ここでx軸を中心に回転させることにします。
ローカル座標で10度回転させることと、
ワールド座標で10度回転させることは異なることが分かると思います。

 

ゲーム中で複雑な向きを扱うのであれば、順調に関数LookAtを使えば良いと思います。
Vector3インスタンスだけでなくTransformインスタンスも扱えますが、
結局Transform.positionが座標を表すのでVector3が分かりやすいでしょう。

 

拡大率関連

インスタンス変数を介してワールド拡大率は取得のみ、ローカル拡大率は取得更新が出来ます。

ワールド方向の拡大も面白そうなものですが、
例えば以下のような変形を考えてみましょう。

①ワールド座標x軸方向に2倍拡大
②y軸を中心に20度回転
③ワールド座標x軸方向に2倍拡大

さて、次に①の拡大を元に戻すにはどうすればいいですか?

 

もうお分かりの通り、ワールド座標での拡大は他の操作と違い、
操作の順番によって質が変わってきてしまうのです。

ユーザー側としても操作しやすいので、
大人しくlocalScaleを操作してあげてください。

 

本日はこんなところで。

直感とは異なりがちな3Dの操作について、
意外と説明している記事が少なかったので詳しく書いてみました。

Unityはいいぞ。

コメント

タイトルとURLをコピーしました