본문 바로가기

Unity/Articles

Unity: 유니티에서 Flutter처럼 작업하기 - uiwidgets

유니티 엔진에서 사용할 수 있는 UI 프레임워크는 다음과 같습니다.

 

공식 지원 시스템

  • IMGUI : 런타임 사용에 적절하지 않은 코드기반의 GUI 시스템
  • uGUI : 가장 점유율이 높은 기본 내장 UI 프레임워크
  • UI Toolkit : 웹과 유사한 uxml/uss 방식의 UI 프레임워크

에셋 스토어 플러그인

  • NGUI : 에셋스토어에서 유료로 판매되는 UI 에셋. uGUI가 대중화되기 전에 주로 사용

 

https://docs.unity3d.com/Manual/UI-system-compare.html

 

Unity - Manual: Comparison of UI systems in Unity

Creating user interfaces (UI) Comparison of UI systems in Unity Unity intends for UI(User Interface) Allows a user to interact with your application. More infoSee in Glossary Toolkit to become the recommended UI system for new UI development projects, but

docs.unity3d.com

 

UI Widgets

이번에 소개할 ui widgets는 유니티 중국 오피스에서 개발중인 프리뷰 패키지입니다.

 

https://github.com/Unity-Technologies/com.unity.uiwidgets

 

GitHub - Unity-Technologies/com.unity.uiwidgets: UIWidgets is a Unity Package which helps developers to create, debug and deploy

UIWidgets is a Unity Package which helps developers to create, debug and deploy efficient, cross-platform Apps. - GitHub - Unity-Technologies/com.unity.uiwidgets: UIWidgets is a Unity Package which...

github.com

 

설치 방법과 제약 사항

  • GitHub에서 소스를 다운로드 후 패키지로 임포트
  • 중국 버전의 유니티 에디터 사용이 필수

GitHub에 게시된 버전을 통해 설치할 수 있고, 특이사항은 글로벌 버전의 유니티 에디터를 사용하면 크래쉬가 발생한다는 점입니다. 반드시 유니티 차이나 사이트에서 유니티 에디터를 설치해야만하는 제약이 있습니다. 설치 방법은 여느 커스텀 패키지를 프로젝트에 적용하는것과 유사합니다. 

 

Flutter on uGUI

이 패키지를 사용하면 Flutter를 개발하는 것과 비슷하게 작업할 수 있습니다.

 

기본적으로는 uGUI Canvas 위에서 동작합니다. 

코드로 UI를 작성하면, 컨텍스트에 따라 UI 빌드를 거쳐 메쉬를 생성해 그려줍니다.

 

공식 문서에서는 최신 유니티 렌더링 SDK를 사용해서 꽤 만족스러운 퍼포먼스를 낼 수 있다고는 하지만, 구체적인 테스트나 프로파일링에 대한 자료는 소개하지 않고 있으므로 실제 사용 벤치마크는 직접 해보아야겠습니다.

 

간단 예제

공식문서에서 제공하는 예제는 간단하면서 직관적입니다. 

스크립트를 하나 생성하고, 캔버스 하위에 빈 UI Panel을 하나 만든 뒤, Image 컴포넌트를 지우고 예제 컴포넌트를 붙이면 됩니다. 

 using System.Collections.Generic;
 using uiwidgets;
 using Unity.UIWidgets.cupertino;
 using Unity.UIWidgets.engine;
 using Unity.UIWidgets.ui;
 using Unity.UIWidgets.widgets;
 using Text = Unity.UIWidgets.widgets.Text;
 using ui_ = Unity.UIWidgets.widgets.ui_;
 using TextStyle = Unity.UIWidgets.painting.TextStyle;

 namespace UIWidgetsSample
 {
     public class UIWidgetsExample : UIWidgetsPanel
     {
         protected void OnEnable()
         {
             // if you want to use your own font or font icons.
                 // AddFont("Material Icons", new List<string> {"MaterialIcons-Regular.ttf"}, new List<int> {0});
             base.OnEnable();
         }

         protected override void main()
         {
             ui_.runApp(new MyApp());
         }

         class MyApp : StatelessWidget
         {
             public override Widget build(BuildContext context)
             {
                 return new CupertinoApp(
                     home: new CounterApp()
                 );
             }
         }
     }

     internal class CounterApp : StatefulWidget
     {
         public override State createState()
         {
             return new CountDemoState();
         }
     }

     internal class CountDemoState : State<CounterApp>
     {
         private int count = 0;

         public override Widget build(BuildContext context)
         {
             return new Container(
                 color: Color.fromARGB(255, 255, 0, 0),
                 child: new Column(children: new List<Widget>()
                     {
                         new Text($"count: {count}", style: new TextStyle(color: Color.fromARGB(255, 0 ,0 ,255))),
                         new CupertinoButton(
                             onPressed: () =>
                             {
                                 setState(() =>
                                 {
                                     count++;
                                 });
                             },
                             child: new Container(
                                 color: Color.fromARGB(255,0 , 255, 0),
                                 width: 100,
                                 height: 40
                             )
                         ),
                     }
                 )
             );
         }
     }
 }

 

main 함수에서 앱을 생성하고, State와 StatefulWidget을 구현합니다. 

Slate 방식으로 위젯을 디자인하고, 앱에 배치합니다. 각 엘리먼트 이벤트에 대한 콜백도 정의해줍니다.

 

플레이모드로 들어가면, 빨간색과 녹색, 파란색으로 구성된 ui widget이 렌더링됩니다.

 

다소 성의없는 예제이지만, 동작에 대한 확인은 할 수 있습니다.

 

눈여겨 볼 만한 점

이미지 로드

이미지를 StreamingAssets 폴더로부터 png상태 그대로 로드할 수 있습니다. 기존 유니티에서도 원한다면 RawImage를 읽고 Texture를 만들어 동적으로 로드할 수 있습니다. 하지만 여기에서는 기본적으로 이 방식만을 사용하고 있고, 중요한 기능이라 성능적으로도 많은 고려를 했을것입니다.

 

GIF 로드

이미지 로드 방식으로부터 오는 장점입니다. 움직이는 GIF 이미지 파일 형식도 문제없이 그릴 수 있습니다. 

 

유니티 기능 사용

3D 오브젝트 렌더링, 파티클 시스템 들 유니티 내장 멀티미디어 기능들을 활용할 수 있습니다. 

유니티 엔진으로 빌드된 앱에 사용할 UI 프레임워크를 선택한다기 보다, Flutter 느낌의 앱에서 유니티 기능을 사용할 수 있다는 느낌이 더 강합니다.

 

기여 허용

거의 모든 유니티 패키지들은 GitHub에 소스가 공개되어있더라도, 기여를 허용하지 않고 있습니다. 포럼을 통해서만 피드백을 받고 프로덕트 릴리즈 매니저를 통해서만 이슈나 기능에 대한 의사소통이 가능한 폐쇄적인 구조입니다. 반면 ui.widgets 패키지는 기여를 허용하고 있으며, 이 기능을 사용하는 여러 기여자들이 필요에 따라 버그를 수정하거나 퍼포먼스를 개선하는 등의 작업을 함께 작업하고 있습니다. 

 

만약 이 패키지를 사용해 작업하다 문제가 발생한다면, 역량이 허용하는 내에서 얼마든지 수정 후 반영할 수 있습니다.

 

에디터 코어 후킹

이 패키지는 어떠한 모종의 이유로 에디터 코어 모듈을 후킹해서 원하는 동작을 구현하려고 합니다. 이는 글로벌버전 유니티 에디터로 패키지 설치를 시도하면 발생하는 크래시 로그에서 네이티브 플러그인으로부터 심볼을 찾지 못해 셧다운됨을 확인할 수 있습니다. 

 

이것이 글로벌 버전에서 사용할 수 없는 이유이면서도 퍼포먼스가 좋게 텍스쳐에 직접 액세스하는 구현을 위해 필수적으로 가져가야만 하는 기능이라... 애매 합니다.

 

결론

안타깝지만 저는 사용하게 될 일은 없을 듯 합니다. 

가장 큰 제약은 중국 로컬버전의 유니티 에디터를 사용하여야 한다는 점입니다. 

다만 앱 개발의 용도와 니즈가 맞는다면 충분히 고려해 볼 만한 선택인 것은 확실합니다.