Unityで「コードではprivateにしたいけれど、Inspectorから数値を調整したい」という場合は、フィールドにSerializeFieldを付けます。外部のコードへ公開する範囲と、Unityが保存する値を分けて設計できます。
ただし、SerializeFieldはあらゆる変数を表示するための指定ではありません。フィールドの種類や型によって保存対象になる条件があるため、付けても表示されないときは順に確認します。
privateフィールドをInspectorへ表示する基本形
MovementConfigExample.csとして保存し、GameObjectに追加する例です。移動処理自体は含めず、設定値の持たせ方だけを示しています。
using UnityEngine;
public class MovementConfigExample : MonoBehaviour
{
[SerializeField] private float moveSpeed = 3f;
[SerializeField] private Transform destination;
public float MoveSpeed => moveSpeed;
public Transform Destination => destination;
}
InspectorではMove SpeedとDestinationを設定できます。ほかのスクリプトはMoveSpeedを読めますが、通常の代入で値を直接変更するためのsetterは公開していません。
SerializeFieldの働きと対象条件はUnity 6のSerializeFieldリファレンスで確認できます。privateというC#のアクセス制御をpublicへ変える属性ではありません。
publicにする方法との違い
| 書き方 | 外部コードからの直接アクセス | Inspectorでの扱い |
|---|---|---|
| public float speed; | 読み書きできる | 対応する型なら保存・表示対象 |
| [SerializeField] private float speed; | クラス外から直接アクセスできない | 保存・表示対象にできる |
| private float speed; | クラス外から直接アクセスできない | 通常は保存・表示対象にならない |
数値をInspectorに出すためだけにpublicを選ぶ必要はありません。設定値はprivateのフィールドで持ち、外部へ必要な操作だけをメソッドやプロパティで公開する構成にすると、どこから値が変わるかを追いやすくなります。
表示されない場合はフィールドか確認する
Unityの通常のシリアライズはフィールドが基本です。getやsetを持つプロパティと、フィールドは同じものではありません。先ほどの例でも、保存するのはmoveSpeedで、MoveSpeedはそれを読むための窓口です。
static、const、readonlyのフィールドは、通常のInspector用シリアライズの対象として考えないようにします。まずprivate floatのような単純なフィールドで表示を確かめると、属性の付け方と型の問題を分けられます。
標準のInspectorでは、Dictionaryや多次元配列など、そのまま保存できない型もあります。SerializeFieldを付ければすべて解決するわけではないため、Unityが対応する型かを公式のシリアライズ規則で確認してください。
自作クラスを表示したいとき
関連する設定をまとめる小さなクラスなら、Serializableを付け、そのインスタンスをフィールドとして持つ方法があります。次のコードは別ファイルのAudioConfigExample.csとして保存する例です。
using UnityEngine;
[System.Serializable]
public class VolumeSettings
{
public float music = 0.8f;
public float effects = 1f;
}
public class AudioConfigExample : MonoBehaviour
{
[SerializeField] private VolumeSettings volumes = new VolumeSettings();
}
GameObjectへAudioConfigExampleを追加し、InspectorのVolumesを展開して確認します。この例も音量変更の実処理ではなく、設定の入れ物を表示するものです。オブジェクト参照や多態性を持つ複雑な構造へ広げる場合は、通常の値の保存とSerializeReferenceなどの仕組みを区別して設計します。
コードの初期値を変えてもInspectorが変わらない理由
スクリプトのmoveSpeedを3から5へ書き換えても、すでにシーンやPrefabに保存されている値が3のまま残る場合があります。コードの初期値と、既存のコンポーネントへ保存された値は別に扱われるためです。
確認したいコンポーネントのInspectorで値を変更するか、新しく追加したコンポーネントと比較してください。Resetはほかの設定まで初期化する可能性があるので、必要な値を確認せずに実行しないようにします。Prefabのインスタンスなら、オーバーライドが残っていないかも確認対象です。
Play中の調整と保存を分けて考える
Playモード中にシーン上のコンポーネントの値を変えても、停止後にそのまま編集状態へ保存されるとは限りません。調整した値を残したいなら、値を記録し、停止後に改めて設定します。アセットそのものの編集は別の挙動になるため、同じ感覚で扱わないようにします。
- 対象のGameObjectにスクリプトを追加しているか。
- Consoleにコンパイルエラーがないか。
- プロパティではなくフィールドを指定しているか。
- staticなど、対象外の指定がないか。
- カスタムInspectorが表示を制御していないか。
SerializeFieldは、調整する設定と内部の処理を整理するための入口です。表示できるかだけでなく、誰が値を書き換えるのか、どこへ保存されるのかまで意識すると、後から扱いやすいコンポーネントになります。
