子同士の関係にあるメンバ変数の値をコピーするエディタ拡張。
ContextMenuにあるPaste Componentでは異なるクラス間の値のコピーができない。
例え同じ親を継承していても...。親クラスのメンバ変数部は同じ値やコンポーネントにしたいことがある。
一々Inspectorで編集するのが面倒なのでエディタ拡張でコピーする機能を作った。
使い方
- メニューのWindow/ComponentFieldCopyerを選択
- コピー元とコピー先のコンポーネントをドラッグ・アンド・ドロップ
- Copyを押す
- 実行される
コード
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
/// <summary>
/// メンバ変数のコピーを行う
/// EditorWindowでコピー元とコピー先のコンポーネントを指定する
/// </summary>
public class UniCopyField : EditorWindow
{
private UnityEngine.Object fromObj;
private UnityEngine.Object toObj;
[MenuItem("Window/ComponentFieldCopyer")]
private static void OpenWindow()
{
EditorWindow.GetWindow<UniCopyField>("ComponentFieldCopyer");
}
void OnGUI()
{
fromObj = EditorGUILayout.ObjectField("From", fromObj, typeof(UnityEngine.Object), true);
toObj = EditorGUILayout.ObjectField("To", toObj, typeof(UnityEngine.Object), true);
if(GUILayout.Button("Copy")) {
copy(fromObj.GetType());
}
}
private void copy(Type fromType)
{
if(fromType == typeof(MonoBehaviour)) return;
foreach(var from in fromType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) {
var other = fromType.GetField(from.Name, BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if((other != null)) {
try {
other.SetValue(toObj, from.GetValue(fromObj));
} catch(Exception e) {
Debug.Log(e);
}
}
}
// fromの親クラスからコピー
copy(fromType.BaseType);
}
}
仕組み
設定Window
UnityのEditorWindowでコピー元とコピー先のコンポーネントを取得する。
UnityEngine.Object型で取得するためほぼ全てのコンポーネントに対応できる。
Inspectorから「コンポーネントを」ドラッグアンドドロップで設定すること。
EditorGUILayout.ObjectFieldで設定されたコンポーネントを取得しておく。
メンバ変数の取得
Reflectionを用いて2つのクラスの共通のメンバ変数を取得する。
GetFieldおよびGetFieldsで指定したTypeのメンバ変数が取得できる。
BindingFlagsで取得するメンバ変数の条件を設定する。
両方に共通して持つフィールドのみSetValueで値を代入。
コピー先がメンバ変数を持っていない場合は例外を吐かせることにした。
GetFieldsでは親クラスのprivateメンバは取得できないため、Type.BaseTypeで今度は親クラスのメンバ変数の取得を行う。
GitHub