UnityのTransform.positionの各値(x,y,z)を直接変更できない理由

Unityを始めた初心者がなぜこれが出来ないのかというのを疑問に思うのでほんの少しでも手助けになれば。

前提

positoinを表すVector3はstructです。
struct同士を代入、引数としてメソッドに渡す場合はclassと違い、参照渡しではなく値渡しとなります。

Unityのコードを見てみよう

Unityの一部のコードがGitHubで公開されているので見てみましょう
https://github.com/Unity-Technologies/UnityCsReference

残念ながらTransform自体のコードの殆どは公開されていない

見てみようと言いながらそのコードの殆どは公開されていません。コアの殆どをC/C++で書かれているか、単純に公開していないかのどちらかです。ただし、幸いにもTransformへのアクセス箇所は見ることができるのでその処理を見ることができます。

TransformBinding.gen.cs

gen てことは何らかのツールなどを用いて自動生成されている!(ここはどうでも良い)
では、そのコードを見てみましょう。

public Vector3 position
{
    get { Vector3 tmp; INTERNAL_get_position(out tmp); return tmp;  }
    set { INTERNAL_set_position(ref value); }
}

こうなっています。
この時点で値渡し、参照渡しということが理解できている人は気づくのではないでしょうか。
(ごめんなさい、これがわからないという人向けにまで説明する余力がありません...)

こうなっていなくても、getterが宣言された時点で、structの各メンバへの代入は意味をなしません。
そのためコンパイル時点でエラーとして弾かれます。

例えば、こうするとより簡潔になるかもしれないです。

private Vector3 m_position;
public Vector3 position { get { return m_position; } set { m_position = value; } }

こうなると、positionにアクセスした時点で、structのコピーが行われ、
m_positionとは全く別の実体が生成されます。
そのため、Transform.position.x = 1 とやっても、大本のm_positionには 何の影響もないんです
宣言を、public Vector3 position { get; } とだけ書いても↑と同じです。

( public Vector3 position; とだけ書いた場合は構造体の各メンバも編集できます )

なぜこうなっているのか

理由は、大本のコードのとおりに隠蔽された箇所にアクセスする必要があるので、こうせざるを得なかったのだと思います。
ただし、昨今のECS/JobSystemで見る通り、Unityはstructの負荷の軽さを有効活用していこうというのがよくわかります。
(struct自体はclassに比べて高速、且つ、GCの世話にならない場合が多いなど)
本当の理由は開発者に聞かないとわかりませんが、色々なことを考慮した上でこうなっているのではないでしょうか。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.