UI Toolkit Binding Support
A library that supports property binding of custom class controls.
Unity Project
Download the source from GitHub
Dependencies (5)
README
UI Toolkit Binding Support
Languages available in README: [ํ๊ตญ์ด (๋ํ๋ฏผ๊ตญ)] [English (US)]
์๊ฐ
์ ๋ํฐ์ ์ฐจ์ธ๋ UI ์์คํ
(์ด๋ผ๊ณ ์ฃผ์ฅํ๋) UI Toolkit์์ ์ปค์คํ
ํด๋์ค์ SerializedProperty ๋ฐ์ธ๋ฉ์ ์ง์ํ์ง ์๋๋ค๋ ๊ฒ์ ๊นจ๋ซ๊ณ
์ ๋ง ํฐ ์ถฉ๊ฒฉ์ ๋ฐ์์ ๋ง๋ ํจํค์ง์
๋๋ค.
์ด ํจํค์ง๋ ์ ๋ํฐ๋ฅผ HarmonyX ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ๋ฐํ์์ ์ ๋ํฐ ๋ด๋ถ ์ฝ๋๋ฅผ ํจ์นํ์ฌ
์ ๋ํฐ ๋ฐ์ธ๋ฉ ์์คํ
์ด ์ปค์คํ
ํด๋์ค๋ฅผ ์ธ์ํ ์ ์๋๋ก ๋์์ค๋๋ค.
๋น์ฐํ? ์ด๋ป๊ฒ ๋ฐ์ธ๋ฉ ๋ ๊ฒ์ธ์ง, ์ํ๋ ํ์
์ null๋ก ํ ๋นํ ์ ์๊ฒ๋ ์ค์ ํ๋๊ฒ ๋ํ ์ ๋ถ ์ปค์คํ
๊ฐ๋ฅํฉ๋๋ค.
ํน์ ํ์
์ด null๋ก ํ ๋น ๊ฐ๋ฅ์ผ๋ก ์ธ์ํ๊ฒ๋ ์ค์ ํ๋ ๊ธฐ๋ฅ์ด ์๋ ์ด์ ๊ฐ, Serializable Nullable ๊ฐ์ด, null์ ์ง๋ ฌํํ ์ ์๊ฒ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ํ ์ ์์ ์ผ๋ก ์๋ํ ์ ์๊ฒ ํ๊ธฐ ์ํจ์
๋๋ค.
๊น์ผ๋ก ์ค์นํ์๋ฉด ๋ฉ๋๋ค!
URL : https://github.com/Rumi727/UI-Toolkit-Binding-Support.git?path=Packages/com.rumi.custombinding
์ฐธ๊ณ ์ฌํญ
HarmonyX ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ฐํ์์์ ์ ๋ํฐ ์ฝ๋์ ๋ฐ์ธ๋ ์ฝ๋๋ฅผ ์ง์ด๋ฃ๋๋ค๋ ๊ฒ์ ๊ธฐ์ตํด์ฃผ์ธ์!
์ฝ๊ฒ ๋งํ๋ฉด, ์ ๋ํฐ๋ฅผ ๋ชจ๋ฉํ๊ฒ๋๋ค!
๋ถ์์ ์ ์ผ ์ ์์ผ๋, ์ฐธ๊ณ ํด์ฃผ์ธ์!
๋ฒ๊ทธ๊ฐ ์๋ค๋ฉด ๊ผญ! ์ด์์ ์ฌ๋ ค์ฃผ์ธ์!
์ง์๋๋ ๋ฒ์
Unity 2021.3 ๋ฒ์ ๋ถํฐ ์๋ํ์ง๋ง, ๋ง์ด๋ํ ๋ฒ๊ทธ ์์ ์กด์ฌํ์ฌ ์ถ์ฒํ์ง ์์ต๋๋ค.
๊ผญ ํ์ํ๋ค ์ถ์๋๋ง ์ฌ์ฉํด์ฃผ์ธ์.
๊ณต์์ ์ผ๋ก Unity 6 ๋ฒ์ ๋ถํฐ ์ง์ํฉ๋๋ค!
์ฌ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- HarmonyX
- Harmony, HarmonyX๋ฅผ ๊ฐ๋ฐํ์ ๋ถ๋ค์๊ฒ ์ ๋ง ๊ฐ์ฌํฉ๋๋ค! Harmony๊ฐ ์์๋ค๋ฉด ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋์ค์ง ๋ชปํ์๊ฑฐ์์.
- ์ข ์์ฑ
๋ฏธ๋ฆฌ๋ณด๊ธฐ
์ฌ์ฉ ๋ฐฉ๋ฒ
๊ธฐ๋ณธ์ ์ผ๋ก, ObjectPropertyBinder ๋ฐ์ธ๋๊ฐ ํฌํจ๋์ด์๊ธฐ์ ๊ทธ๋ฅ ํจํค์ง ์ค์น๋ง ํ์๋ฉด
์ปค์คํ
์ปจํธ๋กค์ (์: BaseField
๊ทธ๋ฌ๋๊น field.bindingPath = "myStruct"; ์ด๋ฐ์์ผ๋ก ํ์์ฒ๋ผ Vector3Field, ObjectField ๊ฐ์ ๋ด์ฅ ์ปจํธ๋กค์ ๋ฐ์ธ๋ฉํ๋ฏ์ด ํ๋ฉด ๋ชจ๋ ๊ฒ ์์์ ๋ ๊ฑฐ์์!
ํ์ง๋ง, SerializedProperty.boxedValue ์์ฑ์ด ๋์ํ์ง ์๋๋ค๊ฑฐ๋ (๋งค์ฐ ํน์ดํ ์ผ์ด์ค์ด๊ธด ํฉ๋๋ค. ์ ๋ ์ด๊ฑธ ์ถฉ๋๋ก ๊ฒฝํํด๋ดค์ด์...),
Serializable Nullable ๊ฐ์ด ๋ฐ์ธ๋๋ฅผ ์ปค์คํ
ํด์ผํ ์ํฉ๋ ์์ผ์ค๊ฑฐ์์.
(์, ๊ฒ๋ค๊ฐ ์ด๊ฑฐ ๋ง๋ค๋ฉด์ ์ฒ์ ์์๋๋ฐ SerializedProperty.boxedValue๋ 2022.1๋ถํฐ ์๋๋ผ๊ณ ์?, ๊ทธ ์ ์ ์ด๋ป๊ฒ ๊ฐ ์ป์ผ๋ผ๋๊ฑฐ์์ง...)
์, ์ด๋ฐ MyStruct ๊ตฌ์กฐ์ฒด๊ฐ ํ๋ ์๋ค๊ณ ํด๋ณผ๊ฒ์.
#nullable enable
using System;
[Serializable]
public struct MyStruct
{
public string? name;
public float value;
}
๊ทธ๋ฌ๋ฉด ์๋์ ๊ฐ์ด ๋ฐ์ธ๋๋ฅผ ์ง๋ฉด ๋ฉ๋๋ค. PropertyDrawer ์ด๊ฑฐ๋ ๋น์ทํ์ฃ ?
#nullable enable
using Rumi.CustomBinding.Editor;
using System;
using UnityEditor;
using UnityEngine.UIElements;
[CustomPropertyBinder(typeof(MyStruct))] // CustomPropertyBinder ์ดํธ๋ฆฌ๋ทฐํธ๊ฐ ์์ด์ผ ๋ฐ์ธ๋๋ก ์ธ์ํฉ๋๋ค!
public class MyStructPropertyBinder : PropertyBinder // ๋ฌผ๋ก PropertyBinder ์ด๊ฒ๋ ๊ฐ์ด ์์ํด์ผํด์!
{
// SerializedProperty์์ ๊ฐ์ ์ฝ์ด์ MyStruct๋ก ์ญ์ง๋ ฌํ ํด์ผํฉ๋๋ค.
public override object Read(VisualElement element, SerializedProperty property, Type propertyType)
{
property.Next(true); // name
string name = property.stringValue;
property.Next(false); // value
float value = property.floatValue;
return new MyStruct { name = name, value = value };
}
// MyStruct์์ ๊ฐ์ ์ฝ์ด์ SerializedProperty์ ์ง๋ ฌํ ํด์ผํฉ๋๋ค.
public override void Write(VisualElement element, SerializedProperty property, Type propertyType, object? value)
{
if (value is MyStruct myStruct)
{
property.Next(true); // name
property.stringValue = myStruct.name;
property.Next(false); // value
property.floatValue = myStruct.value;
}
}
}
์ ๊น! ์ค์ํ๊ฒ ์์ด์!
๊ธฐ๋ณธ์ ์ผ๋ก PropertyDrawer๋์ ๋ค๋ฅด๊ฒ ์ ํ ํ์
๊ณผ (์ฌ๊ธฐ์ MyStruct) ๋ฐ์ธ๋ฉํ ํ๋กํผํฐ์ ํ์
์ด ์๋ก ๋์ผํ ํ์
๋ง ๋ฐ์ธ๋๊ฐ ๋์ํฉ๋๋ค!
ํ์ง๋ง, CustomPropertyBinder ์ดํธ๋ฆฌ๋ทฐํธ๋ ์จ๊ฒจ์ง ๋งค๊ฐ๋ณ์๊ฐ ํ๋ ๋ ์๋๋ฐ,
๋ฐ๋ก isSubtypeCompatible ์
๋๋ค!
[CustomPropertyBinder(typeof(MyStruct), true)] ์ด๋ฐ์์ผ๋ก isSubtypeCompatible ๋งค๊ฐ๋ณ์๋ฅผ true๋ก ์ค์ ํด์ฃผ๋ฉด,
๊ทธ ๋ฐ์ธ๋๋ MyStruct์ ํ์ ํ์
๋ ์ฒ๋ฆฌํ ์ ์๋ ๋ฐ์ธ๋๋ก ์ธ์ํด์! (๊ตฌ์กฐ์ฒด๊ฐ ์ด๋ป๊ฒ ํ์ ํ์
์ด ์๋๊ฑฐ์ง?)
์ด๋๋, PropertyDrawer์ ์์ ๋์ผํ๊ฒ ๋์ํฉ๋๋ค! (์ธํฐํ์ด์ค, ์ ๋ค๋ฆญ ํ์
์ ์ (์: List<>) ๋ฑ๋ ์ฌ๋ฐ๋ฅธ ๋ฐ์ธ๋๋ก ์ธ์ํจ)
ํ์ง๋ง! ๊ทธ๋ ๊ธฐ์ ํ์ ํ์
๊ณผ ํธํ๋๋ ๋ฐ์ธ๋๋ฅผ ์์ฑํ ๋๋ ๋ ์กฐ์ฌํ์
์ผํด์!
๋น์ฐํ ์๋ฆฌ์ด๊ธด ํ์ง๋ง, ๋ฐ์ธ๋์ ๋ฐํ ๊ฐ์ด object๋ผ๊ณ ์๋ฌด ์ค๋ธ์ ํธ๋ ๋ฐํํด๋ ๋๋ ๊ฒ์ด ์๋,
ํญ์ ๋ฐ์ธ๋ฉ ํ ํ๋กํผํฐ์ ํ์
์ ํ ๋น ๊ฐ๋ฅํ ํ์
์ด์ฌ์ผํฉ๋๋ค! (์ฌ๊ธฐ์ MyStruct ๋๋ MyStruct๋ฅผ ์์(??)ํ๊ณ ์๋ ํ์
)
์๋๋ ํ์ ํ์ ๊ณผ ํธํ๋๋ ๋ฐ์ธ๋์ ์์์์!
#nullable enable
using System;
[Serializable]
public class MyClass
{
public string name = string.Empty;
public float value;
}
#nullable enable
using Rumi.CustomBinding.Editor;
using System;
using UnityEditor;
using UnityEngine.UIElements;
[CustomPropertyBinder(typeof(MyParent), true)]
public class MyParentPropertyBinder : PropertyBinder
{
public override object Read(VisualElement element, SerializedProperty property, Type propertyType) => property.boxedValue;
public override void Write(VisualElement element, SerializedProperty property, Type propertyType, object? value) => property.boxedValue = value;
}
์! ๋ฐ์ธ๋ฉ ๊ฐ๋ฅํ ํ์ ์ด ๋๋ ค๋ฉด MyStruct, MyParent ์ฒ๋ผ ๊ผญ ๋งค๊ฐ๋ณ์ ์๋ public ์์ฑ์๊ฐ ์์ด์ผํ๋๊น ์ฐธ๊ณ ํด์ฃผ์ธ์!
Nullable ํ์ ์ ๋ฑ๋กํ๊ณ ์ถ์ด์!
์ฐ์ , NullableType.isNullable ๋๋ฆฌ๊ฒ์ดํธ์ ์ํ๋ ํ์
์ด Nullable์ด๋ผ๊ณ ์ธ์ํ ์ ์๊ฒ ๋ฑ๋กํด์ฃผ์
์ผํด์!NullableType.isNullable += x => Nullable.GetUnderlyingType(x) != null;
์ด๋ฐ์์ผ๋ก ๋ฐํ๊ฐ์ด true์ด๋ฉด ํด๋นํ๋ ํ์
์ Nullable ์ฒ๋ผ ์ทจ๊ธํด์!
๊ทธ๋ฆฌ๊ณ , Nullable์ ๊ธฐ๋ณธ ํ์
์ ์ ์ ์๊ฒ NullableType.getNullableUnderlyingType ๋ํ ๋ฑ๋กํด์ฃผ์
์ผํด์!NullableType.getNullableUnderlyingType += static x => Nullable.GetUnderlyingType(x);
์ด๋ฐ์์ผ๋ก ๋งค๊ฐ๋ณ์๋ก ๋ค์ด์จ ํ์
์ ๊ธฐ๋ณธ ํ์
์ด ์์ผ๋ฉด ๊ทธ ํ์
์ ๋ฐํํด์ฃผ์๋ฉด ๋๊ณ , Nullable ํ์
์ด ์๋๋ผ์ ๊ธฐ๋ณธ ํ์
์ ์ฐพ์ ์ ์๋ค๋ฉด ๊ผญ null์ ๋ฐํํด์ฃผ์ธ์!
๋ํ ์ฃผ์ํ์ค์ ์ด ์์ด์!
Nullable๋ก ํ์๋ ํ์
์ ๊ผญ๊ผญ ๊ธฐ๋ณธ ํ์
์ผ๋ก ์์์ ํ๋ณํํ ์ ์์ด์ผํฉ๋๋ค
์๊ทธ๋ฌ๋ฉด ์บ์คํ
์์ธ๋์!!
Comments
No comments yet. Be the first!
Sign in to join the conversation
Sign In