Unityで transform.position.x += 3 がエラーになる理由
–– struct を返すプロパティとフィールドの違いを徹底解説 ––
対象読者
- C#/Unity 初~中級者
- CS1612(「戻り値を変更できない」)エラーで詰まった人
- このテーマをブログや講義で分かりやすく伝えたい人
目次
1. 再現コードとエラーメッセージ
Transform t = new Transform();
t.position = new Vector3(1, 2, 3);
t.position.x += 3; // ★ CS1612 発生
error CS1612:
Cannot modify the return value of 'Transform.position'
because it is not a variable
同じロジックでも position をフィールドにした場合はビルド成功 します。違いはどこに?
2. 核心:値型(struct) + プロパティ = 毎回コピー
プロパティ実装(エラーになる)
class Transform
{
float x, y, z;
public Vector3 position
{
get => new Vector3(x, y, z); // ← 毎回コピー生成
set { x = value.x; y = value.y; z = value.z; }
}
}
- t.position を読むたび 一時的な Vector3 が生成
- そのコピーの x を書き換えようとする → 一時値は変数でない
- C# 規則により CS1612 で拒否
フィールド実装(エラーにならない)
class Transform
{
public Vector3 position; // 実体そのもの
}
t.position は Transform インスタンス内の実体。x += 3 が成立します。
3. Unity が mutable struct + プロパティを採用する理由
目的 | 詳細 |
---|---|
ネイティブ側と同期 | C++ エンジンに即通知する必要がある |
副作用フック | set 時にコライダーや親子階層を更新 |
GC 負荷回避 | class にすると大量ヒープ確保 → フレーム落ち |
ゲームでは リアルタイム性能が最優先。.NET ガイドラインより速度を取った設計です。
4. 正しい書き方:コピー → 変更 → 再代入
Vector3 pos = transform.position; // ① コピー
pos.x += 3; // ② 変更
transform.position = pos; // ③ 再代入
ありがちな落とし穴
NG 例 | 原因 |
---|---|
foreach (var p in points) p.x += 1; | p はコピー。元リストに反映されない |
transform.position.y++; | コピー上で ++ しているだけで CS1612 |
5. パフォーマンスチューニングのヒント
テクニック | 効果・注意 |
---|---|
ref / in パラメータ | コピー削減。ただし Unity 組み込み API は ref 戻り値を持たない |
Burst + Mathematics パッケージ | SIMD 化された float3 構造体で高速演算 |
ジョブシステム | 大量ベクトル演算をマルチスレッド化 |
6. 付録:完全版サンプルコード
using UnityEngine;
public class PositionDemo : MonoBehaviour
{
void Start()
{
Vector3 pos = transform.position; // コピー
pos.x += 3; // 変更
transform.position = pos; // 再代入
Debug.Log(transform.position); // (4.0, 2.0, 3.0)
}
}
まとめ
- プロパティが struct を返す=コピー扱い
- コピーのサブメンバーは直接書き換え不可 → CS1612
- Unity の Transform は性能最優先設計。正しくは「コピー→変更→再代入」
- 高速化が必要なら ref / in や Burst, ジョブシステムの活用も検討しよう。
訪問数 4 回, 今日の訪問数 4回
ディスカッション
コメント一覧
まだ、コメントがありません