UnityのAttribute(属性)についてまとめてメモる。
Unityの属性について紹介します。
目次
- 目次
- 属性(Attribute)とは
- 属性の表記ルール
- Unity標準の属性
- 属性を自作する
- 関連資料
属性(Attribute)とは
Unityを利用するC#は、クラス定義や変数定義に属性(Attribute)を付与する事で他の変数と区別したり、特別な挙動を設定することが出来ます。*1
例えば変数に[SerializeField]属性を追加すれば、privateな変数であってもシリアライズされシーン上に表示されるようになります。
[SerializeField]
int count;
シリアライズは、とりあえずは「シーンやプレハブに値が保存される」と認識しておけばOKです。シーンやプレハブとったメタデータに値が保存されるため、ゲームを再生せずともInspectorで値を設定する事が出来る訳です。
また、[RequireComponent]をクラスに追加すれば、記述したコンポーネント*2がアタッチされているオブジェクトに指定したコンポーネント*3を強制する事が出来ます。
[RequireComponent(typeof(Rigidbody))]
public class AttributeSample : MonoBehaviour {}
属性を利用することで、命名規則以外で変数に特別な挙動を設定することが出来ます。Unityは属性を利用して、エディタやメソッド等に特別な挙動を設定しています。
属性の表記ルール
属性は変数やクラスの定義前に [***] のような形で記述します。複数の属性を設定したい場合、[***, ***] のようにカンマで区切り記述します。
例えばSerializeFieldかつRangeの属性を設定したい場合、以下のように記述します。
[SerializeField, Range(0, 5)]
int count;
属性は直後に定義した変数全てに適応されます。例えば一つの宣言で複数の変数を定義するような場合、そのどちらにも適応されます。
[SerializeField, Range(0, 5)]
int count3, count4;
同様に配列に対して適当した場合、内包する全ての変数に適応されます。
[SerializeField, Range(0, 5)]
int[] counts;
Unity標準の属性
Inspectorを拡張する属性
フィールドに設定することでInspectorの挙動を拡張します。
-
SerializeField
privateやprotectedの値をシリアライズします。
シーンビューで編集したい場合に有効です。
[SerializeField]
int count;
-
TooltipAttribute
マウスカーソルがフィールドの上にある場合に説明文を表示します。
[SerializeField, TooltipAttribute("説明文")]
int count5;
-
SpaceAttribute
フィールドとフィールドの間にスペースを設定します。
[SerializeField, Space(15)]
int count6;
-
HeaderAttribute
フィールドの頭にタイトルを設定します。リストにHeaderAttributeを追加すると全項目にタイトルが付与されるので注意が必要です
[SerializeField, HeaderAttribute ("Title")]
int count7;
-
MultilineAttribute
複数行の入力が可能なテキストフィールドを設定します。
[SerializeField, MultilineAttribute (2)]
string message1;
-
TextAreaAttribute
複数行の入力が可能なテキストフィールドを設定します。行数の最小値・最大値を設定することができます。
[SerializeField, TextAreaAttribute(2, 5)]
string message2;
-
HideInInspector
public等のシリアライズするフィールドをInspectorから隠します。エディタ拡張で参照関係やパラメータを構築した状態で、パラメータを隠したい場合等に便利です。
Unityはシーンを構築する際にシリアライズした値を優先して使用するため、HideInInspectorで隠すとInspectorから編集出来ず、フィールド変数宣言時の初期化も無視される点に注意して下さい。
純粋にシリアライズしたくない場合はNonSerializableを利用します。
[HideInInspector]
public int count8;
-
NonSerializable
シリアライズしないように設定し、Inspectorから表示されなくします。
[System.NonSerialized]
public int count9;
-
FormerlySerializedAs
- 変数名を変更した際に破棄される情報を保持します。
Unityはフィールドの情報をフィールド名で保持するため、フィールド名が変更されると値が破棄されます。その際、FormerlySerializedAsを指定しておくことで移行先の変数名にこの情報が引き継がれるようになります。
public float first;
[FormerlySerializedAs("first")]
public float second;これで変数名firstで設定した値は変数名secondに変更した後も破棄されず残ります。移行後はFormerlySerializedAsは削除して構いませんが、他のシーンで使っていた場合に色々面倒かもしれないので注意して下さい。
コンポーネントの動作に関連する属性
-
RequireComponentAttribute
コンポーネントの動作に必要なコンポーネントがオブジェクトにアタッチされていなければ追加します。例えばRigidbody等。
[RequireComponent(typeof(Rigidbody))]
public class AttributeSample : MonoBehaviour {
}
-
DisallowMultipleComponent
同一オブジェクトに複数のコンポーネントを追加出来ないようにします。
[DisallowMultipleComponent]
public class AttributeSample : MonoBehaviour {
}
-
ContextMenuAttribute
コンポーネントのコンテキストメニュー(右上のマーク)からメソッドを呼び出せるようにします。例えばセットアップをランタイムではなく事前に行う場合に便利です。
[ContextMenu("Init")]
void Init(){
}
ゲームの動作に影響する属性
-
RPC
RPCを行う時に使うやつです。NetworkViewで通信したりPhotonで通信する際に使います。この属性があるメソッドは、ネットワーク越しに呼ばれます。
[RPC]
void Damage(){
}
-
ImageEffectOpaque
OnRenderImageに付与すると透明より前にレンダリングします。
[ImageEffectOpaque]
void OnRenderImage (RenderTexture source, RenderTexture destination){
}
-
DLLImport
C++(アンマネージドコード)のメソッドをC#から呼び出せるようにします。
[DllImport("DLL Name")]
private static extern void MethodName();
エディタの動作に関連する属性
エディタの上からシーンに影響を与える事のできる属性です。
-
AddComponentMenu
メニューバーのComponentやAddComponentボタンから指定する際のパスを設定します。これを行わない場合、Script/Namespace/コンポーネント名が設定されます。
[AddComponentMenu("Sample/TestCode")]
public class AttributeSample : MonoBehaviour{}
-
ExecuteInEditMode
コンポーネントのUpdateやStartといったイベントを、ゲームを再生しない状態でも動作するようにします。ランタイムで動作する挙動を確認する際に便利です。
[ExecuteInEditMode]
public class AttributeSample : MonoBehaviour {}
ExecuteInEditMode はホットスポットのような形で動作し、コードが変更になった際にシリアライズ出来る値はシリアライズ→コンパイル→再注入となり、出来ない値は破棄されま す。このため、Start等で初期化しているコードやstaticに依存するコードはシーンを再生する必要が出たりするので注意が必要です。
例えば以下のコードはコード変更前は3を出力し、コード変更しコンパイルが走ると0を出力します。static int sCount = 0;
void Start(){
sCount = 3;
}
void Update(){
Debug.Log("export:" + sCount);
}
- SelectionBaseAttribute
シーンビューで選択した際にこの属性を持つコンポーネントを選択するようにします。
[SelectionBase]
public class AttributeSample : MonoBehaviour {}例えばモデルがシーンビューにあった場合、シーンビューで選択するとモデルのRendererが選択されますが、親オブジェクトにSelectionBaseAttributeを付与したコンポーネントを付与すると、選択時に親オブジェクトが選択されます。
上がGameObjectオブジェクトにSelectionBaseを付与した際の動作、下が付与していない場合の動作です。付与していない物はSphereを取得しますが、付与しているとGameObjectオブジェクトを取得します。
-
CreateAssetMenu
メニューバーにScriptableObjectのアセットを生成するメニューを追加します。
[CreateAssetMenu()]
public class Data : ScriptableObjec{}
エディタ関連はまた後日まとめます多分。
属性を自作する
Inspectorで描画を行う属性や、通常の属性は自作することが出来ます。
この記事が参考になります。
Unity3D - 自分だけのPropertyDrawerを作ろう! - Qiita
結構な量のサンプルがココにあるので、自作する前に見ておくと良さそうです。anchan828/property-drawer-collection · GitHub
また、単純に属性を使用する場合もそこそこ役立つケースが有ります。
例えばエディタでゲーム再生中に変更した値を停止しても消さない その2 では属性を持った変数を識別し、値を一時保存する事でシーン終了時に破棄されるパラメータを保持するのに使ったり、シーンのビルド時にプラットフォーム毎に値を変更するのに使用したりといった活用が出来ます。
関連資料
PanzerSoftのブログ Unityのスクリプトで利用する属性(アトリビュート)
An Overview of Unity Attributes
Extending Unity Container to Support DefaultValue Attribute - CodeProject
Unity3D - 自分だけのPropertyDrawerを作ろう! - Qiita
HeaderとSpaceを使ってInspectorを整理する - テラシュールブログ
NativePluginsにC#デリゲートを登録する - テラシュールブログ
エディタでゲーム再生中に変更した値を停止しても消さない その2 - テラシュールブログ
サンプル
anchan828/property-drawer-collection · GitHub