Skip to content

Instantly share code, notes, and snippets.

@yasuakiohama
Last active November 6, 2017 15:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuakiohama/3bb76365d598659f8598 to your computer and use it in GitHub Desktop.
Save yasuakiohama/3bb76365d598659f8598 to your computer and use it in GitHub Desktop.
SortComponentsWindow.cs
//
// Unity5.2.3p3
// SortComponentsWindow.cs
// http://yasuaki-ohama.hatenablog.com/entry/SortComponentsWindow
//
// Created by yasuaki ohama on 2016/01/11.
// http://yasuaki-ohama.com/
//
// 機能
// ドラックでコンポーネント入れ替え+更新
// Undo、Redoに対応
// スクリプトが外れている場合の対処
// コンポーネントの順番とスクリプト名を表示
// アタッチしたスクリプト内にある変数の値を表示
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
/// <summary>
/// GameObjectのコンポーネントをソートする
/// </summary>
public sealed class SortComponentsWindow : EditorWindow
{
/// <summary>
/// 参照するGameObject
/// </summary>
private GameObject m_target = null;
/// <summary>
/// 参照するオブジェクトのコンポーネントの格納
/// </summary>
private Component[] m_targetComponents;
/// <summary>
/// コンポーネントの入れ替えに利用
/// </summary>
private ReorderableList m_reorderableList = null;
/// <summary>
/// 入れ替えの状態を格納
/// </summary>
private List<Component> m_components = new List<Component> ();
/// <summary>
/// GameObjectのコンポーネントの更新状態と同期
/// </summary>
private List<Component> m_diffComponents = new List<Component> ();
/// <summary>
/// スクロール用変数
/// </summary>
private Vector2 m_scrollPosition;
/// <summary>
/// ソートウィンドウの表示
/// </summary>
[MenuItem( "EditorWindow/Sort Components Window" )]
private static void Init()
{
EditorWindow.GetWindow (typeof(SortComponentsWindow), false, "Sort Components Window");
}
/// <summary>
/// GameObjectのコンポーネントの更新を反映
/// </summary>
/// <param name="components">Components.</param>
private void UpdateComponents(List<Component> components)
{
components.Clear ();
components.AddRange (m_targetComponents);
components.RemoveAt (0);// delete Transform
if (components == m_components) {
m_reorderableList = new ReorderableList (components, typeof(Component));
m_reorderableList.displayAdd = false;
m_reorderableList.displayRemove = false;
m_reorderableList.drawHeaderCallback = (rect) => {
EditorGUI.LabelField(rect, m_target.name + " Components");
};
m_reorderableList.drawElementCallback = (rect, index, isActive, isFocused) => {
EditorGUI.LabelField(rect, DrawElementCallback((Object)m_reorderableList.list[index], index));
};
}
}
/// <summary>
/// リストの順番とクラス名を表示
/// </summary>
/// <returns>The element callback.</returns>
/// <param name="obj">Object.</param>
/// <param name="index">Index.</param>
private string DrawElementCallback(Object obj, int index)
{
return string.Format ("{0:D2}:{1}", (index + 1), obj.GetType ());
}
/// <summary>
/// アタッチしたスクリプト内にある変数の内容を表示する(なければnull)
/// 型:GameObject 変数名:target
/// 型:String 変数名:key
/// 型:int 変数名:value
/// </summary>
/// <returns>The element callback custom.</returns>
/// <param name="obj">Object.</param>
/// <param name="index">Index.</param>
private string DrawElementCallbackCustom(Object obj, int index)
{
var targetName = "null";
var key = "null";
var value = 0;
if (obj == null) {
return string.Format ("{0:D2}:{1}:{2}:{3}:{4}", (index + 1), obj.GetType (), targetName, key, value);
}
SerializedObject so = new SerializedObject (obj);
if (so.FindProperty ("target") != null) {
if (so.FindProperty ("target").objectReferenceValue != null) {
targetName = so.FindProperty ("target").objectReferenceValue.name;
}
}
if (so.FindProperty ("key") != null) {
if (so.FindProperty ("key").stringValue != null) {
key = so.FindProperty ("key").stringValue;
}
}
if (so.FindProperty ("value") != null) {
value = so.FindProperty ("value").intValue;
}
return string.Format ("{0:D2}:{1}:{2}:{3}:{4}", (index + 1), obj.GetType (), targetName, key, value);
}
/// <summary>
/// GameObjectのコンポーネントに更新があるかチェック
/// </summary>
/// <returns><c>true</c>, if components update was checked, <c>false</c> otherwise.</returns>
private bool CheckComponentsUpdate()
{
if (m_components.Count != m_targetComponents.Length - 1) {
//Debug.Log ("コンポーネントの数が合わない");//ウィンドウの + -を押した場合の対処
return true;
}
if (m_diffComponents.Count != m_targetComponents.Length - 1) {
//Debug.Log ("コンポーネントの数が合わない");
return true;
}
foreach (var component in m_components) {
if (component == null) {
//Debug.Log ("componentがnull");
return true;
}
}
foreach (var component in m_diffComponents) {
if (component == null) {
//Debug.Log ("componentがnull");
return true;
}
}
foreach (var component in m_targetComponents.Select((v, i) => new { index = i, value = v })) {
if (component.index == 0) {
//Transformはチェックしない
continue;
}
if (component.value != m_diffComponents [component.index - 1]) {
//Debug.Log ("オブジェクトの参照先が違う");
return true;
}
}
return false;
}
private void OnGUI()
{
m_target = (GameObject)EditorGUILayout.ObjectField (m_target, typeof(GameObject), true);
if (m_target == null) {
//オブジェクトがなければ何も表示しない
return;
}
m_targetComponents = m_target.GetComponents<Component> ();
foreach (var component in m_targetComponents) {
if (component == null) {
//スクリプトが外れていれば何も表示しない
EditorGUILayout.LabelField ("The referenced script on this Behaviour is missing!");
return;
}
}
//参照しているGameObjectの更新は「EditorGUI.BeginChangeCheck ();」で習得することができないため、
//手動でGameObjectのコンポーネントの更新をチェックする。
//毎回更新を行うとReorderableListで入れ替え操作ができないため更新時のみ反映するようにした
if (CheckComponentsUpdate () || m_reorderableList == null) {
UpdateComponents (m_diffComponents);
UpdateComponents (m_components);
}
m_scrollPosition = EditorGUILayout.BeginScrollView(m_scrollPosition);
//GameObjectのコンポーネントの順番を表示
m_reorderableList.DoLayoutList ();
EditorGUILayout.EndScrollView();
//ボタンの設置
if (GUILayout.Button ("Apply")) {
//ソートしたコンポーネントを複製し値を入れる
foreach (Component component in m_components) {
var addedComponent = Undo.AddComponent(m_target, component.GetType ());
foreach (FieldInfo fi in component.GetType().GetFields()) {
fi.SetValue (addedComponent, fi.GetValue (component));
}
}
//古いコンポーネントの削除
foreach (Component component in m_components) {
Undo.DestroyObjectImmediate (component);
}
UpdateComponents (m_diffComponents);
UpdateComponents (m_components);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment