名古屋でアプリ・VR開発を行っています
ワクワクできるゲームをガンガン開発リリース中!

UnityのInspector上のTransformをちょっとだけ機能を拡張する

みなさん、こんにちは!SAT-BOXのツバメです。

今回はUnityのInspector上のTransformをちょっとだけ機能を拡張するお話になります。
Transformの座標や角度を初期化する際はほとんどの人は手作業でやると思います。X,Y,Zをそれぞれ選択して0を記入…。座標、角度、スケールすべての値を手作業でやるにはちょっと面倒ですよね。
その面倒をちょっとだけ緩和する機能を実装してみようと思います。今回はボタン1つで座標のX,Y,Zをすべて0に初期化するものを作成してみようと思います。

1.コードを書いていきましょう
まずはスクリプトを作成しましょう(スクリプト名は何でも良いです)
作成したスクリプトに以下のコードを貼り付けてください

using UnityEngine;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(Transform))] // <- この処理でエディター拡張の指定をTransformにしています
public class スクリプト名 : Editor 
{
	private Vector3 tmpLocalPosition;
	private Vector3 tmpLocalRotation;
	private Vector3 tmpLocalScale;

	private const float BUTTON_WIDTH = 20.0f;
	private const float GUILAYOUT_WIDTH = 50.0f;
	private const float GUILAYOUT_HEIGHT = 20.0f;

	public override void OnInspectorGUI()
	{
		Transform targetTransform = (Transform)target;

		EditorGUI.BeginChangeCheck();
                {
			// Positionの表示
			EditorGUILayout.BeginHorizontal();
			{
				EditorGUI.BeginChangeCheck();
				{
					// XYZすべての値が0の場合はボタンを押せないようにする
					EditorGUI.BeginDisabledGroup((targetTransform.localPosition.x == 0 && targetTransform.localPosition.y == 0 && targetTransform.localPosition.z == 0) ? true : false);
					{
						// 初期化ボタンを表示
						if (GUILayout.Button("R", GUILayout.Width(BUTTON_WIDTH))) tmpLocalPosition = Vector3.zero;
					}
					EditorGUI.EndDisabledGroup();
				}
				if (EditorGUI.EndChangeCheck())
				{
					Undo.RecordObject(target, "Undo CustomTransform");
					targetTransform.localPosition = tmpLocalPosition;
				}

				EditorGUILayout.LabelField("Position", GUILayout.Width(GUILAYOUT_WIDTH), GUILayout.Height(GUILAYOUT_HEIGHT));
				tmpLocalPosition = EditorGUILayout.Vector3Field("", targetTransform.localPosition, GUILayout.Height(GUILAYOUT_HEIGHT));
			}
			EditorGUILayout.EndHorizontal();

			// Rotationの表示
			EditorGUILayout.BeginHorizontal();
			{
				EditorGUILayout.LabelField("Rotation", GUILayout.Width(GUILAYOUT_WIDTH), GUILayout.Height(GUILAYOUT_HEIGHT));

				tmpLocalRotation = EditorGUILayout.Vector3Field("", targetTransform.localEulerAngles, GUILayout.Height(GUILAYOUT_HEIGHT));
			}
			EditorGUILayout.EndHorizontal();

			// Scaleの表示
			EditorGUILayout.BeginHorizontal();
			{
				EditorGUILayout.LabelField("Scale", GUILayout.Width(GUILAYOUT_WIDTH), GUILayout.Height(GUILAYOUT_HEIGHT));
				tmpLocalScale = EditorGUILayout.Vector3Field("", targetTransform.localScale, GUILayout.Height(GUILAYOUT_HEIGHT));
			}
			EditorGUILayout.EndHorizontal();
		}
		if (EditorGUI.EndChangeCheck())
		{
			Undo.RecordObject(target, "Undo CustomTransform");
			targetTransform.localPosition = tmpLocalPosition;
			targetTransform.localEulerAngles = tmpLocalRotation;
			targetTransform.localScale = tmpLocalScale;
		}
	}
}

貼り付け終わったら保存をしてエディター上で何かを選択してInspectorを確認してみてください。以下の画像のような表示になると思います。
f:id:sat-box:20210514131315p:plain
座標に適当に値を入力してRのボタンを押してみてください。XYZすべてが0にリセットされると思います(Undo・Redoにも対応しています)

2.コードのざっくり説明
ボタンの表示と初期化を行っている処理は以下の部分です

// XYZすべての値が0の場合はボタンを押せないようにする
EditorGUI.BeginDisabledGroup((targetTransform.localPosition.x == 0 && targetTransform.localPosition.y == 0 && targetTransform.localPosition.z == 0) ? true : false);
{
	// 初期化ボタンを表示
	if (GUILayout.Button("R", GUILayout.Width(BUTTON_WIDTH))) tmpLocalPosition = Vector3.zero;
}
EditorGUI.EndDisabledGroup();

「EditorGUI.BeginDisabledGroup()」では対象のTransformの座標の値どれかが0以外だとボタンを押せるようにしています(すべて0だったら押せないです)
中には「GUILayout.Button()」を表示しており、ボタンが押されたらTransformの座標すべてを0にするだけの処理です

3.注意点
今回はTransformのInspector上の表示を変えるものですので、座標だけの表示を行ってしまうと角度やスケールが表示されなくなってしまいます。
角度やスケールの表示もコード内に書く必要があるので、注意してください。
また、複数選択時にはボタンが押せないです。これは改良の必要あり!な所なので、改良できたらまた記事にしようと思います(出来る方はぜひ実装してみてください!)

4.最後に
今回は座標だけを初期化する機能を実装しましたが、角度やスケールも座標と同じようにコードを書けば初期化出来ますので、興味のある方はぜひ実践してみてください!
また、Transformのこれ以上の改造も可能ですので今後も紹介できそうな機能があれば紹介しようと思います。

以上、ツバメでした!