본문 바로가기

게임 프로그래밍 (Game Programming)/유니티 (Unity)

Unity Editor Customizing, 유니티 에디터 커스터마이징, 사용자 친화 인터페이스!

이번 시간에는 유니티 에디터의 인터페이스를 사용자 친화적으로 더 깔끔하고 보기 쉽게 커스텀해보겠습니다.

이렇게 에디터를 커스텀하는 이유는 작업자인 저는 물론이고 기획자 및 그래픽 아티스트까지 유니티 프로젝트를 확인하기 쉽게 하기위함입니다. 유니티의 강점이 무엇이겠습니까? 바로 협업툴이라는 것이죠! 

혼자할 때도 좋지만 개발팀이 다 함께 작업하면 더 좋은 에디터가 바로 유니티입니다. 시작해보죠!

 

 

저는 지난 시간에 함께 만들었던 Lotto 프로젝트를 이용해서 진행해볼게요.

여러분들은 지금 하고계신 프로젝트나 새로운 프로젝트를 만드셔도 상관없습니다.

 

 

우선 새폴더를 만드시고 Editor로 변경합니다.

Editor라고 명명한 이 폴더는 특수한 기능을 담당하게 됩니다.

폴더 안의 스크립트들은 런타임 스크립트가 아닌, 에디터 스크립트로 간주되며 빌드 시 추가되지 않습니다.

 

 

우선 스크립트를 새로 만들고 여러분이 구별할 수 있는 이름으로 수정해주세요.

저는 EasyHierarchy로 수정하였습니다.

 

using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
internal static class EasyHierarchy
{
    private const int ROW_HEIGHT = 16;
    private const int OFFSET_Y = -4;

    private static readonly Color COLOR = new Color(0, 0, 0, 0.08f);

    static EasyHierarchy()
    {
        EditorApplication.hierarchyWindowItemOnGUI += OnGUI;
    }

    private static void OnGUI(int instanceID, Rect rect)
    {
        var index = (int)(rect.y + OFFSET_Y) / ROW_HEIGHT;

        if (index % 2 == 0) return;

        var xMax = rect.xMax;

        rect.x = 32;
        rect.xMax = xMax + 16;

        EditorGUI.DrawRect(rect, COLOR);
    }
}

 

이후에 스크립트 안의 내용을 싹 다 지워준 후 위의 내용을 붙여넣기 해주시고 저장 후 에디터로 돌아와봅시다.

 

차이점이 보이시나요???

스크립트를 추가하기 전에는 하이어라키 창이 단색으로 이루어졌었다면 스크립트 추가 후에는 한 줄마다 조금 더 진한 색과 옅은 색이 반복되어 게임오브젝트들을 구별하기 쉽게 해줍니다.

지금은 하이어라키 위에 올려진 오브젝트들의 수가 얼마 안 되지만 나중에 프로젝트 규모가 커진다면 하이어라키가 지저분해 원하는 오브젝트를 바로 찾기 어려울 수 있습니다. 

 

이번에는 하이어라키창과 마찬가지로 프로젝트탭 또한 같은 처리를 해주겠습니다.

역시 스크립트를 만든 후 이름을 수정해주세요. 저는 EasyProject로 하였습니다.

 

using UnityEditor;
using UnityEngine;

public static class EasyProject
{
    [InitializeOnLoadMethod]
    private static void Example()
    {
        EditorApplication.projectWindowItemOnGUI += OnGUI;
    }

    private static void OnGUI(string guid, Rect selectionRect)
    {
        var index = (int)(selectionRect.y - 4) / 16;

        if (index % 2 == 0)
        {
            return;
        }

        var pos = selectionRect;
        pos.x = 0;
        pos.xMax = selectionRect.xMax;

        var color = GUI.color;
        GUI.color = new Color(0, 0, 0, 0.2f);
        GUI.Box(pos, string.Empty);
        GUI.color = color;
    }
}

 

프로젝트 탭은 조금 더 쉬운 구별이 가능하겠네요.

이로써 하이어라키와 프로젝트탭을 커스터마이징하였습니다. 아직 끝나지 않았습니다! 계속 따라오세요.

 

이번에도 스크립트를 추가한 뒤에 ShowComponents라고 명명해주세요.

 

using System.Linq;
using UnityEditor;
using UnityEngine;

public static class ShowComponents
{
    private static readonly Color mDisabledColor = new Color(1, 1, 1, 0.5f);

    private const int WIDTH = 16;
    private const int HEIGHT = 16;

    [InitializeOnLoadMethod]
    private static void Example()
    {
        EditorApplication.hierarchyWindowItemOnGUI += OnGUI;
    }

    private static void OnGUI(int instanceID, Rect selectionRect)
    {
        var go = EditorUtility.InstanceIDToObject(instanceID) as GameObject;

        if (go == null)
        {
            return;
        }

        var pos = selectionRect;
        pos.x = pos.xMax - WIDTH;
        pos.width = WIDTH;
        pos.height = HEIGHT;

        var components = go
            .GetComponents<Component>()
            .Where(c => c != null)
            .Where(c => !(c is Transform))
            .Reverse();

        var current = Event.current;

        foreach (var c in components)
        {
            Texture image = AssetPreview.GetMiniThumbnail(c);

            if (image == null && c is MonoBehaviour)
            {
                var ms = MonoScript.FromMonoBehaviour(c as MonoBehaviour);
                var path = AssetDatabase.GetAssetPath(ms);
                image = AssetDatabase.GetCachedIcon(path);
            }

            if (image == null)
            {
                continue;
            }

            if (current.type == EventType.MouseDown &&
                 pos.Contains(current.mousePosition))
            {
                //c.SetEnable(!c.IsEnabled());
            }

            var color = GUI.color;
            GUI.color = c.IsEnabled() ? Color.white : mDisabledColor;
            GUI.DrawTexture(pos, image, ScaleMode.ScaleToFit);
            GUI.color = color;
            pos.x -= pos.width;
        }
    }

    public static bool IsEnabled(this Component self)
    {
        if (self == null)
        {
            return true;
        }

        var type = self.GetType();
        var property = type.GetProperty("enabled", typeof(bool));

        if (property == null)
        {
            return true;
        }

        return (bool)property.GetValue(self, null);
    }

    public static void SetEnable(this Component self, bool isEnabled)
    {
        if (self == null)
        {
            return;
        }

        var type = self.GetType();
        var property = type.GetProperty("enabled", typeof(bool));

        if (property == null)
        {
            return;
        }

        property.SetValue(self, isEnabled, null);
    }
}

 

스크립트 안의 내용들을 위의 코드로 수정해줍니다.

 

이번에 추가한 스크립트는 차이점이 한 눈에 들어오시죠?

바로 게임오브젝트에 추가된 컴포넌트들이 게임오브젝트의 이름 옆에 보이게 됩니다.

컴포넌트들을 마우스 클릭으로 끄고 켜는 기능도 할 수 있지만 직접 사용해보니 마우스 더블 클릭과 혼용되는 커멘드이기도 하고 실수로 컴포넌트들을 꺼거나 켜는 일이 발생하여 해당 기능을 삭제한 상태입니다.

 

 

해당 기능을 사용하고 싶으신 분들은 스크립트의 내용 중 위의 부분을 찾아 주석을 제거하시면 됩니다.

 

마지막으로 한 가지만 더 추가하겠습니다.

스크립트를 추가 후 ShowWarningObjects 로 명명해주세요.

 

using System.Linq;
using UnityEditor;
using UnityEngine;

public static class ShowWarningObjects
{
    private const int WIDTH = 80;

    [InitializeOnLoadMethod]
    private static void Example()
    {
        EditorApplication.hierarchyWindowItemOnGUI += OnGUI;
    }

    private static void OnGUI(int instanceID, Rect selectionRect)
    {
        var go = EditorUtility.InstanceIDToObject(instanceID) as GameObject;

        if (go == null)
        {
            return;
        }

        var isWarning = go
            .GetComponents<MonoBehaviour>()
            .Any(c => c == null);

        if (!isWarning)
        {
            return;
        }

        var pos = selectionRect;
        pos.x = pos.xMax - WIDTH;
        pos.width = WIDTH;

        GUI.Label(pos, "!");
    }
}

스크립트의 내용을 싹 다 지운 뒤에 위의 내용으로 수정합니다.

 

 

이번에 추가한 커스텀 에디터 스크립트는 어떠한 변화도 보이지 않습니다.

물론 지금은 말이죠.

 

 

하지만 스크립트의 연결이 끊어진다면 어떻게 될까요?

하이어라키창의 게임오브젝트 이름의 옆에 ! 로 경고를 표시해줍니다.

스크립트의 연결이 끊어지는 경우는 보통은 작업자의 실수로 인해 나타나죠.

협업을 할 때도 유니티를 잘 모르는 분들이 이것저것 건드리게 된다면 종종 발생합니다.

이 때 실행을 하면 오류와 함께 실행이 안 되거나 실행 중에 특정 부분에서 오류와 함께 동작을 하지않게 됩니다.

이 전에 미리 !로 표시를 해주어 무언가 오류가 있으니 수정을 하라 라는 경고를 보내는 것이죠.

 

 

오늘은 사용자로 하여금 더 쉽고 편안하게 유니티를 다룰 수 있도록 에디터를 커스터마이징해보았습니다.

제가 소개한 기능은 총 네 가지이지만 사실 에디터 커스터마이징은 셀 수도 없이 많이 존재합니다.

여러분이 필요한 특정 기능이 있다면 검색을 해보시거나 직접 만드실 수도 있겠죠. 

 

다음 시간에도 유용한 팁을 가지고 여러분께 소개해드리겠습니다.

오늘도 따라오시느라 고생하셨습니다 :D