Unity - UI Toolkit
๐ซ UI Toolkit
๊ธฐ์กด IMGUI, UGUI ์๋ ๋ค๋ฅธ ๋ ๋ค๋ฅธ UI ์์คํ
UI Elements๊ฐ ์ ๋ํฐ 2020 ๋ฒ์ ์ผ๋ก ๋์ด์ค๋ฉด์ UI Toolkit์ผ๋ก ์ด๋ฆ์ด ๋ฐ๋
์น ๊ฐ๋ฐ์ ๋ ์ด์์
, ์คํ์ผ
, ๋ก์ง
๊ฐ๋
๊ทธ๋๋ก
UI Toolkit์์๋ ๋ ์ด์์ - UXML
, ์คํ์ผ- USS
, ๋ก์ง - C#
์ผ๋ก UI๋ฅผ ๊ตฌํ
๋ฐํ์ UI, ์๋ํฐ UI ๋ชจ๋ ๊ตฌํ ๊ฐ๋ฅ
๋ฐํ์ UI์ ๊ฒฝ์ฐ, UI Toolkit์ผ๋ก ๊ตฌํ๋ UI๋ ๋ง์ง๋ง ๋จ๊ณ์ ๋ ๋๋๊ธฐ ๋๋ฌธ์, ์ผ๋จ ์๋ ์คํ์ด์ค์๋ UI๋ฅผ ๋ณด์ฌ์ค ์ ์๋ ๊ฒ์ผ๋ก
๊ธฐ์กด ์๋ํฐ UI๋ค๋ UI Toolkit์ผ๋ก ๋ค์ ๋ง๋ค์ด์ง (์๋ง 2022๋ฒ์ ๋ถํฐ?)
๊ทธ๋์ UI Toolkit Debugger๋ฅผ ํตํด ๊ธฐ์กด ์๋ํฐ์ UI๋ฅผ ์ง์ ๋๋ฒ๊น
ํ ์๋ ์์
- ํ์๋ ์ปค์คํ
์๋ํฐ UI ๊ตฌํ์ ๋ชฉ์ ์ผ๋ก ๊ณต๋ถ
- ํ๋ ค๊ณ ํ๋๋ฐ, ๋ฐํ์ UI์ ์๋ํฐ UI๋ ๋จ์ง ๋ณด์ฌ์ง๋ ๊ณณ์ ์ฐจ์ด์ผ ๋ฟ, ๊ตฌํ์ ๋๊ฐ์ ๋ฐฉ์์ผ๋ก ํ๋ ๊ฑฐ์์
- ๊ทธ๋์ ๋ฐํ์ UI ์ฉ์ผ๋ก ๋ง๋ ๋ ์ด์์, ์คํ์ผ, ๋ก์ง์ ๊ทธ๋๋ก ์๋ํฐ UI ์ ์ ์ฉ์ํฌ ์ ์๊ณ , ๋ฐ๋๋ ๋ง์ฐฌ๊ฐ์ง
- ์ด๋, ๋ก์ง์ ๊ฒฝ์ฐ 2023๋ถํฐ ์ ๋๋ก ๋์ํ๋๋ฏ?
๐ซ SerializedObject
Serialize๋ ๋ฐ์ดํฐ๋ฅผ Unity์์ ๋ค๋ฃจ๊ธฐ ์ฝ๊ฒ ๊ฐ๊ณตํ ๊ฒ
์ ๋ํฐ ์๋ํฐ ์์ ๋ชจ๋ ์ค๋ธ์ ํธ๋ SerializedObject๋ก ๋ณํ๋์ด ๋ค๋ฃจ์ด์ง
UnityEngine Object/์คํฌ๋ฆฝํธ๊ฐ ํธ์งํ๋ ์์ญ <-> SerializedObject/์๋ํฐ๊ฐ ํธ์งํ๋ ์์ญ
UnityEngine Object๋ฅผ Asset์ผ๋ก ๋ง๋ค ๋,
UnityEngine Object๋ Serialized Object๋ก ๋ณํ๋ ์ดํ, Serialized Object์์ Asset๊ณผ .metaํ์ผ ์์ฑ
๋ฌดํผ Editor์์๋ SerializedObject๋ฅผ ๋ค๋ฃธ
๐ซ SerializedProperty
SerializedObject๋ณ์.FindProperty()
C#์ ๋ฆฌํ๋ ์
์ ํตํด,
SerializedObject์์ SerializedProperty์ ์ป์ ์ ์์
๐ซ VisualElement
UI Toolkit์ ๋ชจ๋ Element๋ค์ Base๊ฐ ๋๋ Element
VisualElement ์์ฒด๋ ์๋ฌด ๊ธฐ๋ฅ์ด ์๊ณ , ๊ตฌ์ฒดํ๋ VisualElement๋ค์ ๋จ์ ์ปจํ
์ด๋ ์ฉ์ผ๋ก ์ฐ์
C#์ผ๋ก ์น๋ฉด Object?
๋ชจ๋ VisualElement๋ generateVisualContext ์ฝ๋ฐฑ์ ๊ฐ์ง
๐ซ Property Drawer
์ปดํฌ๋ํธ/์คํฌ๋ฆฝํธ์ ์์ฑ
์ด ์ธ์คํํฐ์ ๋ณด์ด๋ ๋ฐฉ๋ฒ์ ์ ์ด/์ปค์คํ
1
2
3
4
5
6
7
8
9
[CustomPropertyDrawer(typeof(Something))]
public class SomethingEditor : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return new PropertyField(property);
// ์ ์ฝ๋๋ ๊ธฐ์กด ๋ชจ์ ๊ทธ๋๋ก ์ถ๋ ฅ
}
}
๐ซ Custom Editor
์ปดํฌ๋ํธ/์คํฌ๋ฆฝํธ๊ฐ ์ธ์คํํฐ์ ๋ณด์ด๋ ๋ฐฉ๋ฒ์ ์ ์ด/์ปค์คํ
1
2
3
4
5
6
7
8
9
10
11
[CustomEditor(typeof(Something))]
public class SomethingEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
InspectorElement.FillDefaultInspector(root, serializedObject, this);
// ์ ์ฝ๋๋ ๊ธฐ์กด ๋ชจ์ ๊ทธ๋๋ก ์ถ๋ ฅ
return root;
}
}
๐ซ viewDataKey
ํน์ VisualElement์ Uniqueํ ๊ฐ
VisualElement์ ์ํ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฌ์ฌ ๋ ์ฌ์ฉ๋จ
์ง์ ํ์ง ์์ผ๋ฉด VisualElement๊ฐ ํฌํจ๋ ์๋์ฐ๋ฅผ ์ด๊ฑฐ๋ ํ ๋๋ง๋ค ์๋ก ์์ฑ = ๊ธฐ๋ณธ ์ํ
์ง์ ํ๋ฉด ๋ง์ง๋ง ์ํ๋ก ๋ณต๊ตฌ
i.e.
Foldout์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ํ์ง ์ํ
๋ง์ฝ viewDataKey๋ฅผ ์ง์ ํ๋ฉด, ๋ง์ง๋ง์ผ๋ก Foldout๋ฅผ ํผ์ณค์ ๊ฒฝ์ฐ ๋ค์ ์๋์ฐ๋ฅผ ์ด๊ฑฐ๋ ํ ๋ ์ ํ์ง ์ํ๋ก ๋ณต๊ตฌ
ScrollView์ ๊ฒฝ์ฐ, ๋ง์ง๋ง์ผ๋ก ์คํฌ๋กคํ ์์น๋ฅผ ๋ณต๊ตฌํ๋ค๋์ง ๋ฑ
๐ซ Foldout
์ ๊ฑฐ๋ ํผ์น ์ ์๋ ๋ฐ์ค
1
2
3
4
5
6
var foldout = new Foldout()
{
viewDataKey = "*Foldout",
text = "์ธ์คํํฐ์์ ๋ณด์ฌ์ง Foldout Text",
InspectorElement.FillDefaultInspector(root, serializedObject, this);
}
๐ซ UXML ์ฐ๊ฒฐํ๊ธฐ
1
2
3
4
5
6
7
8
9
10
public VisualTreeAsset someUXML;
// CustomEditor๋ผ๋ฉด
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
someUXML.CloneTree(root);
// ...
}
Project ์ฐฝ์์ ํด๋น Editor ์คํฌ๋ฆฝํธ๋ฅผ ์ ํํ๊ณ , UXML ํ์ผ ํ ๋น
๐ซ ์ปค์คํ UI Shape?
BindableElement
UxmlFactory UXML ํ์ผ์์ ๋ถ๋ฌ์จ ๋ฐ์ดํฐ๋ก Image ์ธ์คํฐ์ฑ?
generateVisualContext ์ฝ๋ฐฑ์ MeshGenerationContext๋ฅผ ๋ฐ๋ ํจ์๋ฅผ ๋ฑ๋กํ๋ฉด ๋ฉ์ฌ ๊ทธ๋ฆด ์ ์์
Unity์์ ์ง์ํ๋ Painter2D API ํ์ฉ
๐ซ Editor Window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SomethingEditor : EditorWindow
{
[SerializeField] Something something;
[MenuItem("SomePath/Something")]
static void CreateMenu()
{
var window = GetWindow<SomethingWindow>();
window.titleContent = new GUIContent("Complex");
}
public void OnEnable() { // ... }
public void CreateGUI() { // ... }
// https://youtu.be/J2KNj3bw0Bw?t=2519
}
๐ซ ์ฐธ๊ณ
Extending the Unity Editor with custom tools using UI Toolkit | Unite 2022
์๋ํฐ ํ์ฅ ์
๋ฌธ - ๋ฒ์ญ 5์ฅ SerializedObject์ ๋ํด์
์ฐธ๊ณ
์ฐธ๊ณ