Unity4には新機能としてPropertyDrawerというものがあります。みなさんは普段スクリプトに
using UnityEngine;
using System.Collections;
public class SampleScript : MonoBehaviour {
public float hp;
void Update()
{
Debug.Log( hp );
}
}
とpublic float hp;
を記述し、インスペクタ上で自由に編集を行なっていると思います。
例えばこのhp
ですが、仮に自キャラのHPだとしましょう。
自キャラのHPがマイナスになって良いでしょうか?HPの上限を設定しなくて良いでしょうか?(そのようなゲームなら構いませんが…)
- 自キャラのHPがマイナスになってはいけない
- HPの上限は決まっている
上記の設定がすでにあるのであれば、開発の時点で考慮しておくべきです。
その考慮の1つとしてPropertyDrawerを使用しましょう。
PropertyDrawerはAttributeがあることによって成り立つ機能になっています。
##Attributeを使う
上記のHP
の話、つまりHPの下限と上限を設定する
ということです。
結論から言うと
using UnityEngine;
public class SampleScript : MonoBehaviour
{
[Range2( 0f, 100f )]
public float hp;
}
で実装が可能です。
Range( float min , float max )
で下限と上限を決めているわけです。理解はすぐ出来ます。
これはUnityが事前に用意しているRangeAttributeです。
今回はこのRangeAttributeを自作してみましょう。
##Attributeを作る
Attributeを作るには2つのファイルが必要です。
- Attibuteを定義するスクリプトファイル
- Propertyを描画するスクリプトファイル
まずはAttibuteを定義するスクリプトファイル
を作成しましょう
###Attibuteを定義するスクリプトファイルの作成
早速、作成して行きましょう。RangeAttributeだと被ってしまうのでRange2Attributeとします。
using UnityEngine;
public class Range2Attribute : PropertyAttribute
{
public float min;
public float max;
public Range2Attribute (float min, float max)
{
this.min = min;
this.max = max;
}
}
PropertyAttribute
を継承したRange2Attribute.cs
を作成します。
引数としてminとmaxを書くだけでなく、
public float min;
public float max;
も必ず記述するようにしましょう。これは次のPropertyを描画するスクリプトファイル
で使用します。
###Propertyを描画するスクリプトファイル
さて、Attributeの定義が終わったら、次はインスペクターに描画するためのPropertyDrawer
を作成しましょう
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer( typeof ( Range2Attribute ) )]
public class Range2Drawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
Range2Attribute range2Attribute = (Range2Attribute)attribute;
if (property.propertyType == SerializedPropertyType.Float) {
EditorGUI.Slider (position, property, range2Attribute.min, range2Attribute.max, label);
}
}
}
[CustomPropertyDrawer( typeof ( Range2Attribute ) )]
をつけ、PropertyDrawerを継承して下さい。そしてOnGUI
をオーバーライドします。OnGUI
で描画するものがインスペクターに表示されます。
変数としてattribute
があるのでこれをRange2Attribute
にキャストします。
次にOnGUI
の引数としてproperty
が取得できます。これはAttributeをつけているプロパティがシリアライズ化されたものです。
using UnityEngine;
public class Range2AttributeExample : MonoBehaviour
{
[Range2( 0f, 100f )]
public float hp;
}
上記のコードだとhp
がシリアライズ化されたプロパティとなります。
...話はRange2Drawer.cs
に戻りますが、position
が通常の描画で使用される(はずだった)Rect情報です。通常はこのpositionをそのまま使用して下さい。
label
はプロパティ名や場合により画像が含まれています。今回はHp
の文字がlabel
の中に格納されています。
そして、今回RangeAttribute
で定義したmin
とmax
も上記の通りに使用することができます。
さて、これで必要な情報が揃いました。文字にすると大変ですね。
今回はEditorGUI
クラスのSlider
を使用してスライダーを描画します。詳しい使い方はドキュメントを見ていただくとして...
以上で完成です。お疲れ様でした。
さて、次は動作を確認してみましょう。
###作ったAttributeを試す
using UnityEngine;
public class Range2AttributeExample : MonoBehaviour
{
[Range2( 0f, 100f )]
public float hp;
}
Range2AttributeExample.cs
を適当なGameObjectにアタッチして下さい。
すると、以下の画像のようなスライダーが表示されるはずです。
おめでとうございます。これであなたはエディタ拡張(プロパティ拡張?)を行いました。
エディタ拡張の世界へようこそ!
##TIPS
今回作ったようなRange2Attribute
なら別にいいのですが、アイデアによって
- 処理時間のかかるAttributeを作成したい
という場合があると思います。良いですね。処理がかかるけど素晴らしいAttributeを作成しているんでしょうね。
処理時間のかかるAttributeを作成する注意点として、
-
PropertyDrawer
の処理はインスペクターの描画処理と同時に行われるため、PropertyDrawer
の描画処理が終わるまでインスペクターは描画されない。
という点に注意して下さい。
3秒かかる処理だとインスペクターは3秒間表示されずユーザーは待つ必要があります。
これで困ることは、Transform
や他のコンポーネントの情報を見たいのに待たないと見れない。という点です。
なので
using UnityEngine;
public class SampleAttribute : PropertyAttribute
{
public bool init = false;
public SampleAttribute ()
{
}
}
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(SampleAttribute))]
public class SampleDrawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
if (sampleAttribute.init == false) {
sampleAttribute.init = true;
return;
}
...
}
public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
{
if (sampleAttribute.init == false) {
return 0;
}
return base.GetPropertyHeight (property, label);
}
}
Attributeにbool属性のプロパティを追加して初回のみすぐreturnさせるようにします。
これで、とりあえず、インスペクターが表示されます。
Attributeの実際の処理は2回目以降行われるということですね。
GetPropertyHeight
はインスペクターで確保するGUIの高さです。
以上、**自分だけのAttributeを作ろう!**でした!