[Unity]スクリプトにおけるpublicとSerializeFieldの違い
去年のGW頃からUnityエンジンを利用したゲーム制作を、実はちまちまとやっていました。
その上でスクリプトを書く機会がほとんどなのですが、その際に一つ疑問がありました。
それは、publicなフィールドと[SerializeField]なフィールドでは両者ともにインスペクター上で自由に弄ることができる変数となりますが、違いが分からなかったんですよね。
それについて調べてみましたので、まとめておきます。
(Unityバージョンが2019.4時点での話になります)
Unityのシリアライズについて
まずはUnityにおけるシリアライズが何を示しているか、今回の例では[SerializeFiled]を付けると何が起こるかについてを最初に簡単にまとめます。
シリアライズとは、Unityのスクリプトリファレンス(https://docs.unity3d.com/ja/current/Manual/script-Serialization.html)ではこう書かれています。
シリアル化は、データ構造やオブジェクトの状態を Unity が保存して後で再構成できる形式に変換する自動プロセスです。
Unity – Manual: Script Serialization
噛み砕いて言えば、一度決定したデータ構造やオブジェクトの中身を後で変更できる様な形に変換するものと言えます。
このシリアライズをする事によって、インスペクター上でも変数の値を変更できたり、ゲームの実行中にも一時的にゲームオブジェクトを操作できたりする訳です。
Unityの機能ではこのシリアライズをベースに構築されているものが多いので、シリアライズなくしてUnityを操作する、なんてことは無いという事ですね。
publicと[SerializeField]では動作が異なる
まず前提として、この両者はインスペクター上では同じふるまいをします。
例えば以下のコードは、両方共インスペクター上で扱うには変わりがありません。
public class TestClassA : MonoBehaviour {
public string text;
}
public class TestClassB : MonoBehaviour {
[SerializeField]
private string text;
}
どちらもtext変数をインスペクターで変更できます。
しかし、スクリプトの中では話が異なってきます。
今回の例ですと、TestClassAはpublic修飾子で宣言しているので、他のクラスからでもこの変数を自由に変更できてしまいます。
一方TestClassBではprivate修飾子で宣言しているので、他のクラスからではこの変数を見ることも変更することも不可能になります。
この辺りは一般的なC#と同じですね。
つまり、ざっくり言ってしまえば、他のクラスからも参照できる変数を宣言したいのであればpublic、インスペクター上のみに表示して他のクラスからは参照できない様にしたいのであれば[SerializeField]を使えばまあ良いでしょう。
もしプログラムを嗜んでいる人であれば、カプセル化のお話が一番わかり易いですかね。
インスペクター上に表示できる変数
インスペクターに表示できる変数、言い換えればシリアライズできる変数には可能なものと不可能なものがあります。
・Is public, or has a SerializeField attribute
・Is not static
・Is not const
・Is not readonly
・Has a fieldtype that can be serialized. (See Simple field types that can be serialized, below.)
Unity – Manual: Script Serialization
public、もしくはSerializeField属性でstatic,const,readonly修飾子を付与していない、またシリアライズ可能なフィールドタイプを持っている事が条件となっています。
フィールドタイプについてはintやstring等の一般的な型が当てはまりますが、他にもありますので、知りたい方はページを見て下さい。
なんとなく気になって調べた疑問点でしたが、思いの外深い話になっていました。