Unity 검색

다루는 주제
공유

UIElements는 Unity에서 제공하는 새로운 보류 모드(retained mode) UI 프레임워크로, 이제부터 Unity 2019.1용 공개 API로 사용할 수 있습니다. 현재로서는 Unity 에디터를 더 쉽게 확장할 수 있는 툴 기능을 제공하며, 게임 내 지원 및 시각화 제작은 추후 릴리스에서 제공할 예정입니다.

이 콘텐츠는 Targeting Cookies 카테고리를 수락해야만 동영상을 시청할 수 있도록 허용하는 타사 제공업체에서 호스팅합니다. 이러한 제공업체의 비디오를 보려면 쿠키 환경 설정에서 Targeting Cookies 카테고리를 수락하시기 바랍니다.

이전에는 커스텀 에디터 창과 인스펙터를 Unity에 구축하려면 즉시 모드(immediate mode) API인 IMGUI를 사용해야 했습니다. IMGUI를 사용하면 사용자 인터페이스 구축을 쉽게 시작할 수 있지만 좀 더 복잡한 애플리케이션을 구축하는 경우에는 확장이 불가능합니다. 또한 사용자가 현재 프레임 내에서 UI 구조를 수시로 다양하게 바꿀 수 있기 때문에 시스템에서 렌더링을 최적화하기가 어렵습니다. 또 이 모든 UI는 C#에서 선언되는데, 이렇게 하면 향후 UI 시각화 제작 툴에서 C# 코드를 생성해야 하므로, 과정이 매우 복잡해집니다.

하지만 보류 모드 API인 UIElements를 활용하여 사용자가 오브젝트의 UI 계층 구조를 구축하면 시스템에서 직접 렌더링합니다. 이를 통해 시스템은 드로우할 대상을 최적화할 수 있고 드로우 시 전반적인 성능을 향상시킬 수 있습니다. 또한 이 패러다임을 사용하면 계층 구조(hierarchy)와 스타일링(styling)을 기능성(functionality)로부터 분리할 수 있으므로 아티스트와 프로그래머 모두 근심을 덜고 더욱 수월하게 UI를 제작할 수 있습니다.

보류 모드

UIElements의 기본 구성 요소는 VisualElement 클래스입니다. 모든 요소는 VisualElement이거나 VisualElement에서 상속받습니다. VisualElement 각각은 UI 계층 구조를 형성하기 위해 서로의 부모로 지정될 수 있습니다. 그러면 레이아웃, 스타일 및 기타 시스템이 이 계층을 트래버스하여 UI를 화면에 적절하게 렌더링합니다.

에디터에서 각 EditorWindow에는 계층의 최상위 VisualElement를 나타내는 rootVisualElement 프로퍼티가 있습니다. 요소가 이 루트에 자식으로 추가되어야 시스템이 요소에 대해 파악하고 드로우할 수 있습니다.

using UnityEditor;
using UnityEngine.UIElements;

public class ExampleWindow : EditorWindow
{
   public void OnEnable()
   {
       var root = this.rootVisualElement;
       SliderInt slider = new SliderInt();
       root.Add(slider); // Add slider as a child of root.
   }
}

요소가 계층에 포함되어 있는 한, 개발자가 따로 입력하지 않아도 해당 요소에서 사용자 이벤트를 계속 드로우, 업데이트 및 사용합니다. 이 점이 보류 모드가 즉시 모드의 차이를 가장 명확하게 보여 줍니다. 개발자는 어떤 일이 언제 일어나야 하는지만 선언하면 되며, 프레임별 렌더링을 관리할 필요가 없습니다.

위 슬라이더와 같은 요소의 드로잉을 멈추고 싶은 경우 스타일 변경으로 잠시 보이지 않게 하거나 계층에서 영구적으로 제거하면 됩니다.

// You want to easily hide/show dynamically...
slider.style.display = Display.None;

// or, you're done with this element. Make it go away.
slider.RemoveFromHierarchy();

보류 모드를 사용하면 UXML을 사용하는 계층과 USS를 사용하는 스타일링 선언을 별도의 에셋으로 분리할 수 있는 문서 모델을 사용할 수 있습니다. C#에서는 빌트인 쿼리 시스템과 이벤트 시스템을 사용하여 선언된 UI를 기능 및 데이터와 바인딩하는 것에만 집중할 수 있습니다.

계층 및 스타일링에 별도의 에셋을 이용하면 UI를 시각적으로 제작하는 것이 가능합니다. 이를 통해 모든 사용자가 Unity에서 손쉽게 UI를 미세 조정하고 제작하고 디자인할 수 있습니다.

재사용 가능한 템플릿(UXML)

요소의 계층 구조는 모두 C#에서 조합할 수 있습니다. 하지만 스타일과 마찬가지로, 대부분의 계층 구조는 UI를 사용하는 동안 크게 변경되지는 않습니다. 따라서 UXML이라는 별도의 XML 기반 에셋에 계층을 정의하여 UI를 모듈화할 것을 권장합니다.

<UXML xmlns="UnityEngine.UIElements">
   <VisualElement name="the-container">
       <Label class="blue-label" />
       <SliderInt low-value="0" high-value="100" />
   </VisualElement>
</UXML>

태그 이름은 C# 유형과 일치하며 VisualElement로부터 상속하는 사용자 정의 유형을 완벽하게 지원합니다. 속성은 생성 시 새로운 요소에 설정되고 중첩 태그는 부모 태그의 자식이 됩니다.

.uxml 에셋을 다른 Unity 에셋처럼 로드하여 프로세스에서 VisualTreeAsset 오브젝트를 구성할 수 있습니다. 그런 다음 이 VisualTreeAsset을 임의의 요소 아래에서 원하는 만큼 인스턴스화하거나 복제할 수 있습니다.

var uxml =
    AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/ExampleUI.uxml");
uxml.CloneTree(root); // Create the tags in uxml as children of root.

UXML을 통해 방금 생성한 요소에 도달하려면 쿼리 시스템을 사용하면 되며, 아래 부분에서 간략히 설명드리겠습니다.

공유 스타일(USS)

스타일은 C#에서 프로퍼티를 통해 VisualElements에 직접 설정할 수 있습니다. 그러나 대부분의 스타일은 정적으로 정의되었으므로 C#에서 UI 로직과 설명을 분리하는 것이 좋습니다. UIElements는 CSS 표준의 하위 집합을 사용하는 USS라는 Unity 전용 StyleSheet 에셋을 사용합니다. 스타일 자체는 키-값으로 이루어진 쌍이지만, CSS에서 익숙한 동일한 선택기를 사용하여 어떤 요소에 어떤 스타일을 할당해야 하는지 식별할 수 있습니다.

/* By style class. */
.standard-label {
    padding: 6px;
}

/* By element name. */
#the-label {
    font-size: 60px;
}

/* By C# type. */
Label {
    color: rgb(68, 255, 93);
}

.uss 에셋을 다른 Unity 에셋처럼 로드하여 프로세스에서 StyleSheet 오브젝트를 구성할 수 있습니다. 그런 다음 원하는 요소에 할당하면 해당 요소뿐만 아니라 모든 자식에도 스타일이 자동 적용됩니다. 자식이 나중에 추가되는 경우, 스타일도 함께 적용됩니다.

var uss = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/ExampleUI.uss");
root.styleSheets.Add(uss);

스타일을 이름 속성 또는 C# 유형으로 적용할 수도 있지만, 스타일을 더 효과적으로 재사용하기 위해 요소에 하나 혹은 그 이상의 스타일 클래스를 할당하고 USS에서 해당 클래스를 기준으로 스타일을 대응시킬 수 있습니다. 즉, 태그와 같다고 볼 수 있습니다.

<!-- Assign a style class in UXML: -->
<Label class="blue-label" />

// Assign a style class in C#:
var label = new Label();
label.AddToClassList("blue-label");

또한 동일한 요소에 여러 StyleSheet를 추가하고 같은 요소에 여러 규칙이 대응되도록 할 수 있습니다. 스타일을 가능한 한 많이 재사용하는 동시에 복잡한 오버라이드 규칙을 설정하려면 USS를 사용하시길 권장드립니다. 특히 C#에서 다시 컴파일할 때까지 기다릴 필요가 없기 때문에 일반 버튼의 색상과 같이 공유 스타일에 대한 반복 작업이 정말 간단해집니다. StyleSheet(USS) 에셋의 변경 사항은 파일을 저장할 때 에디터에서 자동으로 적용됩니다.

UQuery

UIElements의 쿼리 시스템은 UQuery라고 합니다. Uquery는 계층 구조에서 요소의 이름 속성, 현재 할당된 스타일 클래스 목록 및 C# 유형을 조합하여 요소를 찾을 수 있다는 점에서 웹의 jQuery와 비슷합니다.

// By style class and type.
var label = root.Q<Label>(className: "blue-label");

// By name (returns a VisualElement).
var container = root.Q("the-container");

동적 계층 구조에서 쿼리를 여러 번 실행해야 하는 곳에서 최적화된 재사용이 가능하도록 쿼리 오브젝트를 만들 수도 있습니다.

// Build the query once.
UQueryBuilder<SliderInt> query = root.Query<SliderInt>(classes: "blue-slider");

// Run many times to get updated results.
query.ForEach(slider => Debug.Log(slider.name));

이벤트

UIElements에는 이벤트 시스템이 포함되어 있습니다. 이벤트는 보통 특정 요소로 전송된 후 이벤트가 사용될 때까지 UI 트리의 아래 위로 전파되지만, 이 전파 동작은 커스터마이징이 가능합니다. MouseMoveEvent와 같은 기본 이벤트는 시스템에서 전송되며 사용자는 등록을 통해 이벤트를 수신할 수 있습니다. 커스텀 사용자 이벤트를 정의하고 전송할 수도 있습니다.

이벤트는 UI의 상태가 변경되거나 사용자가 액션을 취했을 때를 알 수 있는 주요 방법입니다. 아래의 예시에서는 사용자가 언제 슬라이더 값을 변경했는지를 감지하여 레이블 요소에 이 새로운 값을 표시합니다.

var label = new Label();
var slider = new SliderInt();
slider.RegisterCallback< ChangeEvent<int> >(evt =>
{
   label.text = evt.newValue.ToString();
});

디버거

UI가 깨져 보이거나, 화면에 보여야 할 요소가 안 보이는 경우, UIElements 디버거가 해결해 줍니다. Chrome과 Firefox에서 웹사이트 디버거를 사용해본 적이 있다면 아마 익숙하게 느껴질 것입니다.

이 디버거로 UI 요소를 디버그하려면 Pick을 활성화하고 마우스 커서를 요소 위에 올려놓거나 요소를 마우스 오른쪽 버튼으로 클릭하고 Inspect를 선택하면 됩니다. 디버거는 현재 창의 전체 라이브 계층을 왼쪽에 표시하고 스타일 인스펙터를 오른쪽에 표시합니다. 이 스타일 인스펙터에서 요소에 할당된 스타일과, 각 스타일 값의 출처가 어딘지를 확인할 수 있습니다(즉, 출처에 해당하는 StyleSheet 에셋 및 선택자). 마지막으로 스타일 값을 즉시 추가 및 편집하고 UI에 적용된 효과를 확인할 수 있습니다.

기타 기능

  • 바인딩:많은 컨트롤을 SerializedObjects에 바인딩하여 UI와 에셋 데이터를 연결할 수 있습니다. Unity의 모든 빌트인 필드가 그러하듯이 IBindable 인터페이스를 구현하는 모든 요소에 SerializedProperty로의 문자열 바인딩 경로를 설정할 수 있습니다. 이를 통해 명시적으로 요소 계층을 SerializedObjects에 Bind()할 수 있습니다.
  • IMGUIContainer: IMGUI에 작성된 기존 에디터 UI가 많은 경우 specialIMGUIContainer 요소를 사용하여 IMGUI UI를 다른 요소로 UIElements UI 내에 포함할 수 있습니다. IMGUIContainer는 OnGUI() 루프 역할을 하는 콜백을 사용하여 평상시와 동일하게 외부에서 모든 이벤트를 수신합니다.
  • 스케줄러:UIElements에는 간단한 빌트인 스케줄러가 포함되어 있습니다. 스케줄러를 사용하여 콜백을 설정된 시간만큼 지연시키거나 설정된 간격에 맞게 반복적으로 실행할 수 있습니다.

추후 릴리스 예정

유니티는 UIElements를 게임 내 UI에서도 사용할 수 있도록 지원하기 위해 노력하고 있습니다. 또한 UIElements 중심의 시각적 워크플로를 마련하여 C# 코딩이 필요없이도 기능적 UI를 디자인하고 제작할 수 있도록 할 예정입니다.

인스펙터와 전용 에디터 창을 사용하는 새로운 툴 및 툴바를 비롯하여 UIElements를 사용하여 Unity의 기능을 계속 더 많이 구축해 나갈 예정입니다.

물론 유니티는 IMGUI와 uGUI도 유지 보수하고 필요에 따라 개선할 것입니다. 당분간 지원 중단할 계획은 없습니다.

Unity 2019.1 버전부터는 Unity에서 UI를 제작하는 방법으로 UIElements를 적극 권장하고 지원할 것입니다.

시작 방법

처음 시작해볼 때는 UIElements에 대한 유나이트 LA 2018의 발표 내용이 도움이 많이 됩니다. 해당 연설에서는 직접 따라해 볼 수 있는 샘플 프로젝트를 함께 제공하며, IMGUI와 UIElements 간의 주요 차이점과 공통점을 집중 조명하고 UIElements의 주요 기능을 실제로 예를 들어 보여주면서 설명합니다.

이 콘텐츠는 Targeting Cookies 카테고리를 수락해야만 동영상을 시청할 수 있도록 허용하는 타사 제공업체에서 호스팅합니다. 이러한 제공업체의 비디오를 보려면 쿠키 환경 설정에서 Targeting Cookies 카테고리를 수락하시기 바랍니다.

Github에서 예시 프로젝트를 다운로드할 수 있습니다.

API에 관한 자세한 내용은 Unity 2019.1 매뉴얼을 참조하시기 바랍니다.

2019년 4월 23일 테크놀로지 | 9 분 소요
다루는 주제