プログラミング系のネタをまとめていきます。

概要


Unityエディタはユーザーからのカスタムメニューを簡単に作ることができます。

例として、シーン上で選択したオブジェクトを、
Projectに登録されているプレハブで置き換えるツールを作ってみます。

カスタムメニューとEditorWIndow

メインメニューに追加する


メインメニューへのアイテムの追加はメソッドに属性MenuItem()を設定することで行います。

public class ReplaceGameObject : EditorWindow
{
	[MenuItem("Custom/Tools/Replace GameObject")]	// Unityのメインメニューに追加される
	public static void Open()
	{
		// カスタムのウィンドウ(EditorWindow継承クラス)を開く
		ReplaceGameObject window = EditorWindow.GetWindow<ReplaceGameObject>();
		window.Show();
	}

※注意点
Unityのルールで、カスタムメニュー系のスクリプト(UnityEditorを使うもの?)は、
  Assets/Editor
に置かないとダメっぽいです。
一応動作するものもあるんですが、カスタムインスペクタはそのフォルダに配置しないと動作しませんでした。

メニューにはこんな感じで追加されます。



ソースは後に書きますが、こんな感じでウィンドウが開かれます。



ゲームオブジェクト置換ツール


ReplaceGameObjectウィンドウのトップにある枠(ObjectField)に、
置換後のオブジェクトをProjectウィンドウからドラッグ、
さらに、Hierarchy内の置換したいオブジェクトを選択すると、
次のように "replace" ボタンが表示されます。



その後、replaceボタンを押すと、シーン上のアイテムが置換されます。

実行結果


シーン上の "Sphere" 6個を "Capsule" に置き換えています。

Before


After

ソースコード


using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class ReplaceGameObject : EditorWindow
{
	// 置換オブジェクト
	private Object m_replaceObject = null;

	/// <summary>
	/// ウィンドウを開く
	/// </summary>
	[MenuItem("Custom/Tools/Replace GameObject")]
	public static void Open()
	{
		ReplaceGameObject window = EditorWindow.GetWindow<ReplaceGameObject>();
		window.Init();
		window.Show();
	}

	/// <summary>
	/// 初期化
	/// </summary>
	public void Init()
	{
		m_replaceObject = null;
	}

	void OnGUI()
	{
		// 置換オブジェクト
		GameObject replaceObj = EditorGUILayout.ObjectField(m_replaceObject, typeof(GameObject), true) as GameObject;
		if (replaceObj != null)
		{
			if (PrefabUtility.GetPrefabType(replaceObj) == PrefabType.Prefab)
			{
				// プレハブがドラッグされた時だけ、置換オブジェクトを更新
				m_replaceObject = replaceObj;
			}
		}
		// 置換実行ボタン
		GameObject[] selection = Selection.gameObjects;
		if ( (m_replaceObject != null) &&					// 置換オブジェクトが設定されている
			 (selection != null && selection.Length > 0) )	// ヒエラルキー上のアイテムが1つ以上選択されている
		{
			if (GUILayout.Button("replace"))
			{
				List<GameObject> delList = new List<GameObject>();
				foreach (GameObject selObj in selection)
				{
					// プレハブを複製して座標と姿勢をコピーする
					GameObject newObj = PrefabUtility.InstantiatePrefab(m_replaceObject) as GameObject;
					if (newObj != null)
					{
						newObj.transform.parent = selObj.transform.parent;
						newObj.transform.position = selObj.transform.position;
						newObj.transform.rotation = selObj.transform.rotation;
						delList.Add(selObj);
					}
				}
				// 元のオブジェクトをは全て削除
				foreach (GameObject obj in delList) DestroyImmediate(obj);
			}
		}
	}
}

カスタムインスペクタ


Unityエディタの Inspectorウィンドウもカスタマイズできます。

例として、キャラクタデータみたいなクラスを作ってみます。
ソース。

using UnityEngine;
using System.Collections;

public class CharaData : MonoBehaviour
{
	// 名前
	public string m_name = "name";
	// 体力
	public int m_stamina = 100;
	// 攻撃力
	public float m_attack = 10.0f;
	// 素早さ
	public float m_agility = 20.0f;
}

通常、インスペクタの表示はこんな感じです。


体力、攻撃力、素早さなどのパラメータをスライダーで調整できるようにしてみます。
特に意味はないですが、体力は int、他は float にしてます。


スライダーの利点は、視覚的にわかりやすくなること、設定しやすいこと、
また、スライダーの最大値、最小値を設定できるので、値の範囲チェックも同時に行われます。

カスタムインスペクタを作成する時は、上記の CharaData クラスとは別のクラスで実装します。
今回は CharaDataInspector というクラスを作って、アセットの Editor フォルダに置きました。

ソースコード


using UnityEngine;
using System.Collections;
using UnityEditor;

[CanEditMultipleObjects]	// 指定すると、複数のインスタンスの編集に対応できるらしい
[CustomEditor(typeof(CharaData))]	// CharaDataクラスを対象とする
public class CharaDataInspector : Editor
{
	// CharaDataクラスの各メンバををシリアライズ(カスタムメニューでの利用、Undoの対象)
	private SerializedProperty m_nameProp;
	private SerializedProperty m_staminaProp;
	private SerializedProperty m_attackProp;
	private SerializedProperty m_agilityProp;

	// CharaDataのインスペクタが開かれた時に呼ばれる
	void OnEnable()
	{
		// serializedObject:現在インスペクタが参照しているインスタンス
		m_nameProp = serializedObject.FindProperty("m_name");
		m_staminaProp = serializedObject.FindProperty("m_stamina");
		m_attackProp = serializedObject.FindProperty("m_attack");
		m_agilityProp = serializedObject.FindProperty("m_agility");
	}

	// インスペクタGUI処理
	public override void OnInspectorGUI()
	{
		serializedObject.Update();

		if (m_nameProp != null)
		{
			EditorGUILayout.PropertyField(m_nameProp);
		}
		EditorGUILayout.Space();	// 見やすくするために一行開ける
		EditorGUILayout.PrefixLabel("Parameter");	// ラベル
		if (m_staminaProp != null)
		{
			EditorGUILayout.IntSlider(m_staminaProp, 0, 1000, "Stamina");	// intスライダー
		}
		if (m_attackProp != null)
		{
			EditorGUILayout.Slider(m_attackProp, 0, 100.0f, "Attack");	// スライダー
		}
		if (m_agilityProp != null)
		{
			EditorGUILayout.Slider(m_agilityProp, 0, 100.0f, "Agility");	// スライダー
		}

		// 編集を適用する
		serializedObject.ApplyModifiedProperties();
	}
}

Editorフォルダ


Assets/Editor
というフォルダ以下に置く必要があると思っていましたが、

Assets/Scripts/Editor
でも動作しました。

UnityのAssets以下は、Editor, Resources等、幾つかルールがあるようです。
タグ

Menu

メインコンテンツ

プログラミング

機器

Macツール

各種情報

Wiki内検索

おまかせリンク

Androidアプリ

AdSense

技術書


管理人/副管理人のみ編集できます