Как в Unity создать поле в инспекторе с пользовательским окном выбора
Я разрабатываю пакет для Unity для адаптирования интерфейсов (в основном) под разные темы и языки. Я уже написал классы для пользовательских UI-элементов, и мне надо сделать чтобы я мог в поле со строкой выбирать значение из путей которые есть в теме/языке как например в полях public Color m_Color;, public GameObject m_GameObject; или даже public AnimationCurve m_AnimationCurve. Вот класс для UI-изображения:
using Adapter.Styles;
using UnityEngine;
namespace Adapter.Elements
{
[AddComponentMenu("UI/Adaptive/Image", order: 2)]
public class Image : UnityEngine.UI.Image, IElement
{
[SerializeField] protected Setting m_Setting;
[SerializeField] protected string m_Style;
public Setting setting { get => m_Setting; set => m_Setting = value; }
public string style { get => m_Style; set => m_Style = value; }
public void Modify()
{
if (m_Setting != null && m_Setting.currentTheme != null && m_Setting.currentTheme.SearchStyle(m_Style, out ImageStyle imageStyle))
imageStyle.Apply(this);
}
private void OnThemeChanged(string themeName, bool nameIsEmpty) => Modify();
protected override void OnEnable()
{
base.OnEnable();
if (m_Setting != null)
m_Setting.ThemeChanged += OnThemeChanged;
}
protected override void OnDisable()
{
base.OnDisable();
if (m_Setting != null)
m_Setting.ThemeChanged -= OnThemeChanged;
}
protected override void Start()
{
base.Start();
Modify();
}
}
}
Вот картинка что я имею ввиду, туда куда указывает красная стрелка надо что-то наподобие куда указывают зеленые:
Пример того что я хочу добиться:
[SerializedField, AddMiniButton(typeof(SomeCustomWindow))] protected string m_Style;
Желательно чтобы в этом поле можно было писать вручную но можно и как public Color m_Color; а я тогда в окне инспектора все реализую, сейчас я исследую метод EditorGUI.DoObjectField может что-то и найду.
PS: И еще вопрос, если у меня вдруг не получится реализовать такое поле самому по техническим причинам то как мне хотя бы получить иконки как на этих полях: кружочек или например пипетка как на цветовом поле. Я уже очень много спрашивал у ChatGPT но он мне пишет класс с полем с текстурой а не получение этих иконок. Получилось только что-то с иконками ошибки, предупреждения и информации но они для другого нужны были.
PSS: Как можно создать окно только с кнопкой закрыть. Я когда то в Visual Studio создавал проект и там я как-то создавал окно у которого был только крестик на панели сверху. В Unity такие окна есть на как раз этих полях дл выбора объектов или цвета.
Кстати я не против кода на
c++если это единственный вариант.
Ответы (1 шт):
Если это ключи, коих не сотни, то проще отображать поле в виде выпадающего списка.
public class StyleFieldDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI (SerializedProperty property)
{
var options = GetOptions();
var field = new PopupField<string>(property.displayName, options, property.stringValue);
field.BindProperty(property);
return field;
}
// Поскольку все стили это ScriptableObject,
// то эти ассеты можно найти и собрать список всех ключий.
private List<string> GetOptions ()
{
List<string> options = new List<string>();
var guids = AssetDatabase.FindAssets("t:MyStyleObjectType", null);
foreach (string g in guids)
{
string path = AssetDatabase.GUIDToAssetPath(g);
var style = AssetDatabase.LoadAssetAtPath(path) as MyStyleObjectType;
if (style != null)
options.Add(style.Key);
}
return options;
}
}
С тем-же успехом можно отображать поле в виде объекта, хотя хранит оно только string.
public class StyleFieldDrawer : PropertyDrawer
{
private SerializedProperty _property;
public override VisualElement CreatePropertyGUI (SerializedProperty property)
{
// Не совсем уверен что можно хранить ссылку на сериализуемое свойство.
_property = property;
var field = new ObjectField(property.displayName);
field.objectType = typeof(MyStyleObjectType);
field.value = GetStyle(property.stringValue);
// В идеале нужно подписываться при AttachToPanelEvent
// и отписываться при DetachFromPanelEvent от всех событий.
field.RegisterValueChangedCallback(OnChange);
return field;
}
private void OnChange (ChangeEvent<Object> e)
{
if (e.target == null)
_property.stringValue = "";
else
_property.stringValue = (e.target as MyStyleObjectType).Key;
}
private MyStyleObjectType GetStyle (string key)
{
var guids = AssetDatabase.FindAssets("t:MyStyleObjectType", null);
foreach (string g in guids)
{
string path = AssetDatabase.GUIDToAssetPath(g);
var style = AssetDatabase.LoadAssetAtPath(path) as MyStyleObjectType;
if (style != null && style.Key == key)
return style;
}
return null;
}
}
п.с. код написа на коленках и не факт, что работает.
Как написать атрибут для поля, показано в PropertyDrawer.
