TransformコンポーネントのInspectorにリセットボタンを追加する方法
この記事では、UnityでTransformコンポーネントのInspectorにリセットボタンを追加するエディタ拡張の作り方について説明します。
作り方
Editorクラスを継承する
Editor
クラスを継承したクラスを作ります。
using UnityEditor;
public sealed class TransformInspector : Editor
{
}
属性を付与する
複数の選択を可能にするCanEditMultipleObjects
属性と、拡張するコンポーネントを指定するCustomEditor
属性を付与します。
using UnityEditor;
using UnityEngine;
[CanEditMultipleObjects]
[CustomEditor( typeof( Transform ) )]
public sealed class TransformInspector : Editor
{
}
メンバ変数と定数を宣言する
関数の実装に必要となるメンバ変数と定数を宣言します。
private static readonly GUIContent PROPERTY_FIELD_LABEL = new GUIContent( string.Empty );
private static readonly GUILayoutOption RESET_BUTTON_WIDTH = GUILayout.Width( 20 );
private static readonly GUILayoutOption VALUE_FIELD_HEIGHT = GUILayout.Height( 16 );
private Transform m_transform;
private SerializedProperty m_position_property;
private SerializedProperty m_scale_property;
OnEnable関数を定義する
必要な値を取得するため、OnEnable
関数を定義します。
private void OnEnable()
{
m_transform = target as Transform;
m_position_property = serializedObject.FindProperty( "m_LocalPosition" );
m_scale_property = serializedObject.FindProperty( "m_LocalScale" );
}
TransformのUIを描画する関数を定義する
ここで新たなusing
ディレクティブが必要となるため、下記のコードを一番上の行に追加します。
using System.Collections.Generic;
using System.Linq;
そして、Transform
のUIを描画する関数をそれぞれ定義します。これらの関数にリセットボタンを追加する( 描画する )処理も含まれています。
座標のUIを描画する関数
private void DrawPositionUI()
{
using ( new EditorGUILayout.HorizontalScope() )
{
var is_pushed_reset_button = GUILayout.Button( "P", RESET_BUTTON_WIDTH );
if ( is_pushed_reset_button ) m_position_property.vector3Value = Vector3.zero;
EditorGUILayout.PropertyField( m_position_property, PROPERTY_FIELD_LABEL, VALUE_FIELD_HEIGHT );
}
}
回転のUIを描画する関数
private void DrawRotationUI()
{
var new_value = Vector3.zero;
var transforms = targets.Cast<Transform>().ToList();
EditorGUI.BeginChangeCheck();
using ( new EditorGUILayout.HorizontalScope() )
{
var current_value = TransformUtils.GetInspectorRotation( m_transform );
var is_pushed_reset_button = GUILayout.Button( "R", RESET_BUTTON_WIDTH );
var contain_difference_rotations = containDifferenceRotationsInSelectedObjects( transforms, current_value );
if ( contain_difference_rotations ) EditorGUI.showMixedValue = true;
var field_value = EditorGUILayout.Vector3Field( string.Empty, current_value, VALUE_FIELD_HEIGHT );
if ( contain_difference_rotations ) EditorGUI.showMixedValue = false;
new_value = is_pushed_reset_button ? Vector3.zero : field_value;
}
if ( EditorGUI.EndChangeCheck() )
{
Undo.RecordObjects( targets, "Inspector" );
transforms.ForEach( transform => TransformUtils.SetInspectorRotation( transform, new_value ) );
}
}
private bool containDifferenceRotationsInSelectedObjects( IList<Transform> transforms, Vector3 current_value )
{
if ( transforms.Count <= 1 ) return false;
return transforms.Any( transform => current_value != TransformUtils.GetInspectorRotation( transform ) );
}
大きさのUIを描画する関数
private void DrawScaleUI()
{
using ( new EditorGUILayout.HorizontalScope() )
{
var is_pushed_reset_button = GUILayout.Button( "S", RESET_BUTTON_WIDTH );
if ( is_pushed_reset_button ) m_scale_property.vector3Value = Vector3.one;
EditorGUILayout.PropertyField( m_scale_property, PROPERTY_FIELD_LABEL, VALUE_FIELD_HEIGHT );
}
}
Transform
のUIを表示する3つの関数の中で、回転の関数( DrawRotationUI
)のみコードが長いです。これは回転のSerializedProperty
の値をQuaternion
型で保持しているためです。
それにより、回転の関数は、座標( DrawPositionUI
)や大きさ( DrawScaleUI
)の関数と同じようにEditorGUILayout.PropertyField
関数を使用して実装することが難しくなります。そのため、その部分をEditorGUILayout.Vector3Field
関数を用いて実装する形に変えており、結果としてコードが長くなっています。
OnInspectorGUI関数を定義する
Inspectorの描画を上書きするため、OnInspectorGUI
を定義します。これでエディタ拡張のプログラムは完成です。
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawPositionUI();
DrawRotationUI();
DrawScaleUI();
serializedObject.ApplyModifiedProperties();
}
使い方
上記のプログラムを作成すると、Transformの各項目( 座標・回転・大きさ )に対する入力欄の左側にボタンが表示されます。
このボタンを押すと、押した項目の値をリセットできます( 項目が座標か回転であればX・Y・Zの値を「0」に。大きさであればX・Y・Zの値を「1」にします )。