Property Drawer を利用すると、スクリプトの属性を使用したり、特定の Serializable
クラスの外観を操作することによって、インスペクターウィンドウ の一部の GUI をカスタマイズできます。
Property Drawer には 2 つの使い方があります。
カスタム Serializable のクラスを持つ場合、それが Inspector にどのように見えるかを制御する Property Drawer を使用することができます。以下のスクリプト内の Serializable クラスの Ingredient (成分) を考慮してください。:
JavaScript (例):
enum IngredientUnit { Spoon, Cup, Bowl, Piece }
// Custom serializable class
class Ingredient extends System.Object {
var name : String;
var amount : int = 1;
var unit : IngredientUnit;
}
var potionResult : Ingredient;
var potionIngredients : Ingredient[];
function Update () {
// Update logic here...
}
C# (例)
using UnityEngine;
using System.Collections;
public enum IngredientUnit { Spoon, Cup, Bowl, Piece }
// Custom serializable class
[System.Serializable]
public class Ingredient : System.Object {
string name;
int amount = 1;
IngredientUnit unit;
}
public class Recipe : MonoBehaviour {
Ingredient potionResult;
Ingredient[] potionIngredients;
void Update() {
// Update logic here...
}
}
using UnityEngine;
using System.IO;
class Testing : MonoBehaviour{
enum IngredientUnit { Spoon, Cup, Bowl, Piece }
// Custom serializable class
[System.Serializable]
class Ingredient{
string name;
int amount = 1;
IngredientUnit unit;
}
Ingredient potionResult;
Ingredient[] potionIngredients;
void Update () {
// Update logic here...
}
}
カスタム Property Drawer を使用して、インスペクターの Ingredient クラスのすべての外観を変更することができます。インスペクターの Ingredient プロパティーで、カスタム Property Drawer の有無の場合の外観を比較してみてください:
CustomPropertyDrawer を使用して Serializable クラスに Property Drawer を付け、そのための引き出しの Serializable クラスの型を渡すことができます。
JavaScript (例):
@CustomPropertyDrawer(Ingredient)
class IngredientDrawer extends PropertyDrawer {
// Draw the property inside the given rect
function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty (position, label, property);
// Draw label
position = EditorGUI.PrefixLabel (position, GUIUtility.GetControlID (FocusType.Passive), label);
// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Calculate rects
var amountRect = new Rect (position.x, position.y, 30, position.height);
var unitRect = new Rect (position.x+35, position.y, 50, position.height);
var nameRect = new Rect (position.x+90, position.y, position.width-90, position.height);
// Draw fields - passs GUIContent.none to each so they are drawn without labels
EditorGUI.PropertyField (amountRect, property.FindPropertyRelative ("amount"), GUIContent.none);
EditorGUI.PropertyField (unitRect, property.FindPropertyRelative ("unit"), GUIContent.none);
EditorGUI.PropertyField (nameRect, property.FindPropertyRelative ("name"), GUIContent.none);
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty ();
}
}
C# (例):
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomPropertyDrawer(typeof(Ingredient))]
public class IngredientDrawer : PropertyDrawer {
// Draw the property inside the given rect
void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
// Draw label
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
// Don't make child fields be indented
int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Calculate rects
Rect amountRect = new Rect(position.x, position.y, 30, position.height);
Rect unitRect = new Rect(position.x+35, position.y, 50, position.height);
Rect nameRect = new Rect(position.x+90, position.y, position.width-90, position.height);
// Draw fields - passs GUIContent.none to each so they are drawn without labels
EditorGUI.PropertyField(amountRect, property.FindPropertyRelative ("amount"), GUIContent.none);
EditorGUI.PropertyField(unitRect, property.FindPropertyRelative ("unit"), GUIContent.none);
EditorGUI.PropertyField(nameRect, property.FindPropertyRelative ("name"), GUIContent.none);
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomPropertyDrawer (Ingredient)]
class IngredientDrawer : PropertyDrawer {
// Draw the property inside the given rect
void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty (position, label, property);
// Draw label
position = EditorGUI.PrefixLabel (position, GUIUtility.GetControlID (FocusType.Passive), label);
// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Calculate rects
Rect amountRect = new Rect (position.x, position.y, 30, position.height);
Rect unitRect = new Rect (position.x+35, position.y, 50, position.height);
Rect nameRect = new Rect (position.x+90, position.y, position.width-90, position.height);
// Draw fields - passs GUIContent.none to each so they are drawn without labels
EditorGUI.PropertyField (amountRect, property.FindPropertyRelative ("amount"), GUIContent.none);
EditorGUI.PropertyField (unitRect, property.FindPropertyRelative ("unit"), GUIContent.none);
EditorGUI.PropertyField (nameRect, property.FindPropertyRelative ("name"), GUIContent.none);
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty ();
}
}
Property Drawer の他の使い道は、カスタム Property Attributes を持っているスクリプト内のメンバーの外観を変更することです。特定の範囲にスクリプトでフロート型か整数型を制限し、Inspector のスライダーとしてそれらを表示したいと言ってください。RangeAttribute と呼ぶビルトインされている PropertyAttribute を使って、以下に示すことができます:
JavaScript (例):
// Show this float in the Inspector as a slider between 0 and 10
@Range (0.0, 10.0)
var myFloat = 0.0;
//C# example.
[Range(0.0f, 10.0f)]
public float myFloat = 0.0f;
C# (例)
// Show this float in the Inspector as a slider between 0 and 10
[Range(0.0f, 10.0f)]
float myFloat = 0.0f;
同様に、あなた自身の PropertyAttribute を作ることができます。例として RangeAttribute のコードを使用します。属性は PropertyAttribute クラスを拡張する必要があります。望むならば、プロパティーはパラメータを取り、パブリックメンバ変数としてそれらを保存できます。
JavaScript (例):
class RangeAttribute extends PropertyAttribute {
var min : float;
var max : float;
function RangeAttribute (min : float, max : float) {
this.min = min;
this.max = max;
}
}
C# (例):
using UnityEngine;
using System.Collections;
public class RangeAttribute : PropertyAttribute {
public float min;
public float max;
public RangeAttribute (float min, float max) {
this.min = min;
this.max = max;
}
}
using UnityEngine;
using System.Collections;
public class Testing : PropertyAttribute
{
float min;
float max;
void RangeAttribute (float min, float max) {
this.min = min;
this.max = max;
}
}
属性がある今、その属性を持つプロパティーを描く Property Drawer を作成する必要があります。drawer は PropertyDrawer を拡張する必要があり、そのためには 引き出した属性にそれを伝えるために CustomPropertyDrawer 属性を持っている必要があります。
Property drawer クラスは Editor と呼ばれるフォルダー内のエディタースクリプトに置きます。
JavaScript (例):
// Tell the RangeDrawer that it is a drawer for properties with the RangeAttribute.
@CustomPropertyDrawer (RangeAttribute)
class RangeDrawer extends PropertyDrawer {
// Draw the property inside the given rect
function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
// First get the attribute since it contains the range for the slider
var range : RangeAttribute = attribute as RangeAttribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider (position, property, range.min, range.max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider (position, property, range.min, range.max, label);
else
EditorGUI.LabelField (position, label.text, "Use Range with float or int.");
}
}
C# (例):
using UnityEngine;
using UnityEditor;
using System.Collections;
// Tell the RangeDrawer that it is a drawer for properties with the RangeAttribute.
[CustomPropertyDrawer(typeof(RangeAttribute))]
public class RangeDrawer : PropertyDrawer {
// Draw the property inside the given rect
void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
// First get the attribute since it contains the range for the slider
RangeAttribute range = attribute as RangeAttribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider(position, property, range.min, range.max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider(position, property, (int) range.min, (int) range.max, label);
else
EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
}
}
パフォーマンス上の理由から、EditorGUILayout 機能を Property Drawers では使用できないことを注意してください。