LoginSignup
3
2

Unity HierarchyとProjectの階層構造をラインで見やすくする。

Last updated at Posted at 2024-04-13

できるようになること

Hierarchy
image.png
Project
image.png

フォルダ構造をラインで表して、ファイルがどこの階層にあるのかわかりやすくなる。

前置き

有料アセットにもあるが自分で作れば無料なので自分でつくった。

使い方

以下のコードをEditorフォルダに入れる。表示が変化しなときはUnity再起動。

ProjectFolderLines.cs
using UnityEditor;
using UnityEngine;
using System.Linq;

[InitializeOnLoad]
public static class ProjectFolderLines
{
    static ProjectFolderLines()
    {
        EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemOnGUI;
    }

    private static void OnProjectWindowItemOnGUI(string guid, Rect selectionRect)
    {
        string path = AssetDatabase.GUIDToAssetPath(guid);
        bool isFolder = AssetDatabase.IsValidFolder(path);
        int depth = path.Count(f => f == '/') - "Assets".Count(f => f == '/');

        // スプライトシートからのスプライトであるかどうかを判断
        bool isMultiSprite = false;
        TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
        if (importer != null && importer.spriteImportMode == SpriteImportMode.Multiple)
        {
            isMultiSprite = true;
        }

        if (depth > 0)
        {
            DrawVerticalLines(selectionRect, depth, isFolder, isMultiSprite);
        }
    }

    private static void DrawVerticalLines(Rect selectionRect, int depth, bool isFolder, bool isMultiSprite)
    {
        float indent = 14; // Unityのデフォルトのインデントサイズ
        Handles.BeginGUI();

        // フォルダとファイル、スプライトシートからのスプライトでオフセットを調整
        float baseOffset = isFolder ? 7 : 7; // 通常のファイルやフォルダに対するオフセット
        if (isMultiSprite)
        {
            baseOffset = 7; // スプライトシートからのスプライトに対するオフセット
        }

        for (int i = 1; i <= depth; i++)
        {
            float lineX = selectionRect.x - indent * i - baseOffset;

            Handles.color = GetColorByDepth(depth - i + 1);

            Vector2 startPoint = new Vector2(lineX, selectionRect.y);
            Vector2 endPoint = new Vector2(lineX, selectionRect.yMax);

            Handles.DrawLine(startPoint, endPoint);
        }

        Handles.EndGUI();
    }

    // 階層の深さに応じた色を取得するメソッド
    private static Color GetColorByDepth(int depth)
    {
        switch (depth)
        {
            case 1:
                return Color.red;
            case 2:
                return Color.green;
            case 3:
                return Color.blue;
            case 4:
                return Color.yellow;
            case 5:
                return Color.magenta;
            case 6:
                return Color.cyan;
            case 7:
                return Color.grey;
            case 8:
                return new Color(1f, 0.5f, 0f); // オレンジ
            case 9:
                return new Color(0.5f, 0f, 0.5f); // パープル
            case 10:
                return new Color(0f, 0.5f, 0f); // ダークグリーン
            case 11:
                return new Color(0.5f, 0.5f, 0f); // オリーブ
                                                  // 以下、必要に応じて他の階層の色を追加
            default:
                return new Color(0.5f, 0.5f, 0.5f, 0.2f); // デフォルトの色
        }
    }

}


HierarchyFolderLines.cs
using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public static class HierarchyFolderLines
{
    static HierarchyFolderLines()
    {
        EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemOnGUI;
    }

    private static void OnHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect)
    {
        GameObject obj = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
        if (obj != null)
        {
            int depth = GetDepth(obj.transform);
            DrawVerticalLines(selectionRect, depth);
        }
    }

    private static int GetDepth(Transform transform)
    {
        int depth = 0;
        while (transform.parent != null)
        {
            depth++;
            transform = transform.parent;
        }
        return depth; // "Assets"の階層を含まないので、ここでは調整不要
    }

    private static void DrawVerticalLines(Rect selectionRect, int depth)
    {
        float indentWidth = 14f; // Unityのデフォルトのインデントサイズ
        float baseIndent = 14f; // 基準となるインデント
        float lineWidth = 1f; // 線の幅

        Handles.BeginGUI();

        for (int i = 0; i < depth; i++)
        {
            float indent = baseIndent + (indentWidth * i) + (indentWidth / 2f); // インデントの調節
            float lineX = selectionRect.x - indent;

            // 色を親から決定する
            Color lineColor = GetColorByDepth(depth - i,0.2f);
            Handles.DrawSolidRectangleWithOutline(new Rect(lineX, selectionRect.y, lineWidth, selectionRect.height), lineColor, lineColor);
        }

        Handles.EndGUI();
    }
    // 階層の深さに応じた色を取得するメソッド(アルファ値付き)
    private static Color GetColorByDepth(int depth, float alpha = 1.0f)
    {
        Color color;
        switch (depth)
        {
            case 1:
                color = Color.red;
                break;
            case 2:
                color = Color.green;
                break;
            case 3:
                color = Color.blue;
                break;
            case 4:
                color = Color.yellow;
                break;
            case 5:
                color = Color.magenta;
                break;
            case 6:
                color = Color.cyan;
                break;
            case 7:
                color = Color.grey;
                break;
            case 8:
                color = new Color(1f, 0.5f, 0f); // オレンジ
                break;
            case 9:
                color = new Color(0.5f, 0f, 0.5f); // パープル
                break;
            case 10:
                color = new Color(0f, 0.5f, 0f); // ダークグリーン
                break;
            case 11:
                color = new Color(0.5f, 0.5f, 0f); // オリーブ
                break;
            default:
                color = new Color(0.5f, 0.5f, 0.5f); // デフォルトの色
                break;
        }
        return new Color(color.r, color.g, color.b, alpha);
    }

}



これで見やすくなるね。やったね。

202406 追記

HierarchyとProjectの名前が逆になっていたので修正

もっとみやすくProjectフォルダにラインと同様の色を設定できるスクリプト追加
適応後
image.png

ProjectFolderColors.cs
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

public static class ColoredProjectView
{
    const string MenuPath = "NXLab/ColoredProjectView";
    const string PrefKey = "NXLab_ColoredProjectView_Enabled";

    [MenuItem(MenuPath)]
    static void ToggleEnabled()
    {
        bool isEnabled = !Menu.GetChecked(MenuPath);
        Menu.SetChecked(MenuPath, isEnabled);
        EditorPrefs.SetBool(PrefKey, isEnabled);
        EditorApplication.RepaintProjectWindow();
    }

    [InitializeOnLoadMethod]
    static void Initialize()
    {
        SetEvent();
        bool isEnabled = EditorPrefs.GetBool(PrefKey, true);  // 初期値をtrueに設定
        Menu.SetChecked(MenuPath, isEnabled);
    }

    static void SetEvent()
    {
        EditorApplication.projectWindowItemOnGUI += OnGUI;
    }

    static void OnGUI(string guid, Rect selectionRect)
    {
        if (!Menu.GetChecked(MenuPath))
        {
            return;
        }

        string assetPath = AssetDatabase.GUIDToAssetPath(guid);
        int depth = assetPath.Split('/').Length - 1;
        Color colorToUse = GetColorByDepth(depth);

        // アルファ値を設定して色を適用
        colorToUse.a = GetAlphaByDepth(depth);
        EditorGUI.DrawRect(selectionRect, colorToUse);
    }

    private static Color GetColorByDepth(int depth)
    {
// 指定された階層に基づいて色を返す
        switch (depth)
        {
            case 1: return Color.red;
            case 2: return Color.green;
            case 3: return Color.blue;
            case 4: return Color.yellow;
            case 5: return Color.magenta;
            case 6: return Color.cyan;
            case 7: return Color.grey;
            case 8: return new Color(1f, 0.5f, 0f); // オレンジ
            case 9: return new Color(0.5f, 0f, 0.5f); // パープル
            case 10: return new Color(0f, 0.5f, 0f); // ダークグリーン
            case 11: return new Color(0.5f, 0.5f, 0f); // オリーブ
            default: return new Color(0.5f, 0.5f, 0.5f); // デフォルトの色
        }
    }

    private static float GetAlphaByDepth(int depth)
    {
        // 階層の深さに応じてアルファ値を補間する
        // 例:最深部でアルファ値を最も低くする
        const float maxDepth = 10f;  // この深さ以降はアルファ値が最小になる
        const float minAlpha = 0.01f; // アルファ値の最小値
        const float maxAlpha = 0.05f; // アルファ値の最大値

        // 階層の深さに基づいてアルファ値を計算する
        float alpha = maxAlpha - ((depth - 1) / maxDepth) * (maxAlpha - minAlpha);
        return Mathf.Clamp(alpha, minAlpha, maxAlpha);
    }
}
#endif

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2