Почему serializedObject.FindProperty возвращает null?

Программирование на Юнити.

Почему serializedObject.FindProperty возвращает null?

Сообщение NapalmRain 08 окт 2022, 20:47

Доброго всем времени суток!

Есть скрипт, унаследованный от MonoBehaviour и повешенный на объект, вот его содержимое:
Синтаксис:
Используется csharp
public class NPCActionsQueue : MonoBehaviour
    {
        public int RandomFactor { get; set; }
        public int TimeInterval { get; set; }
        public List<BehaviorPoint> BehaviorPoints { get; set; }
    }
 


Так как он содержит список сложных самописных классов, которые Unity, что логично, отображать в инспекторе не умеет, решил написать свой кастомный.


Синтаксис:
Используется csharp
[CustomEditor(typeof(NPCActionsQueue))]
public class ActionsQueueEditor : Editor
{
...

 

Но вот тут столкнулся с проблемой:
Если использовать в качестве объекта для работы с данными внутри ActionsQueueEditor
this.target
То всё прекрасно, отображается, добавляется, меняется, но... не сохраняется. После перезапуска редактора, перехода на разные сцен или даже изменения какого-то из задействованных скриптов, все внесённые через инспектор данные удаляются.

Решил использовать serializedObject и его методы
Синтаксис:
Используется csharp
serializedObject.Update();
... тут рисуется редактор
serializedObject.ApplyModifiedProperties();
 

Но проблема в том, что в момент инициализации скрипта я пытаюсь получить свойства, но они всё время равны null'ю
Хотя, если посмотреть через отладку, скрипт нужный подтянулся и данные в нём видно
Изображение

Однако же, в переменной после FindProperty null

Уверен, что просто упускаю какую-то мелочь

Версия Unity 2021.3.11f1
NapalmRain
UNIт
 
Сообщения: 81
Зарегистрирован: 24 янв 2014, 15:58

Re: Почему serializedObject.FindProperty возвращает null?

Сообщение samana 08 окт 2022, 22:05

NapalmRain писал(а):Так как он содержит список сложных самописных классов, которые Unity, что логично, отображать в инспекторе не умеет

А вы помечали этот самописный класс атрибутом [System.Serializable] ? Тогда он будет отображаться в инспекторе (точнее все его поля, которые могут сериализуются по-умолчанию).

https://docs.unity3d.com/ScriptReferenc ... zable.html
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Почему serializedObject.FindProperty возвращает null?

Сообщение NapalmRain 08 окт 2022, 22:36

samana писал(а):
NapalmRain писал(а):Так как он содержит список сложных самописных классов, которые Unity, что логично, отображать в инспекторе не умеет

А вы помечали этот самописный класс атрибутом [System.Serializable] ? Тогда он будет отображаться в инспекторе (точнее все его поля, которые могут сериализуются по-умолчанию).


Да, пробовал, забыл упомянуть об этом, там другой баг вылезает: некорректно работает раскрывающийся список для перечислений.
Во-первых там есть совершенно ненужные мне None и Everything, во-вторых при выборе некоторых элементов, Юнька решает, что я выбрал как раз ту самую "Все", и выбирает всё подряд.
NapalmRain
UNIт
 
Сообщения: 81
Зарегистрирован: 24 янв 2014, 15:58

Re: Почему serializedObject.FindProperty возвращает null?

Сообщение samana 09 окт 2022, 09:38

NapalmRain, дело в том, что ваше свойство RandFactor это авто-свойство, то-есть компилятор "под капотом" всё равно создаст приватное поле, и методы к получению и установке значения в это приватное поле, только имя этого поля не угадать. А приватные поля в Unity по умолчанию не сериализуются.
Поэтому вам нужно отказаться от автосвойства, тем более если оно ничего не делает, а просто меняет значение напрямую, без проверок и тп. И создать приватное поле с атрибутами [SerializeField, HideInInspector] чтобы явно сериализовать это поле и скрыть его в инспекторе если нужно.
То-есть что-то вроде этого:
Синтаксис:
Используется csharp
using UnityEngine;

public class NPCActionsQueue : MonoBehaviour
{
    [SerializeField, HideInInspector]
    private int _randomFactor;

    public int RandomFactor
    {
        get => _randomFactor;
        set => _randomFactor = value;
    }
}


Тогда в кастомном инспекторе обращайтесь к свойству напрямую через target, и для того, чтобы приватное поле так же сохраняло своё значение - помечайте текущий объект как "изменённый, грязный", чтобы Unity пересохранила все сериализованные данные при закрытии сцены.

Синтаксис:
Используется csharp
using UnityEditor;

[CustomEditor(typeof(NPCActionsQueue))]
public class NPCActionsQueueEditor : Editor
{
    NPCActionsQueue _target;

    private void OnEnable()
    {
        _target = (NPCActionsQueue)target;
    }

    public override void OnInspectorGUI()
    {
        EditorGUI.BeginChangeCheck();

        _target.RandomFactor = EditorGUILayout.IntField("RandFactor", _target.RandomFactor);

        bool changed = EditorGUI.EndChangeCheck();

        if (changed)
        {
            // для того, чтобы сцена узнала об изменениях и запросила пересохранение всех данных перед закрытием
            EditorUtility.SetDirty(_target);
        }

    }
}
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Почему serializedObject.FindProperty возвращает null?

Сообщение NapalmRain 09 окт 2022, 21:58

samana писал(а):NapalmRain, дело в том, что ваше свойство RandFactor это авто-свойство, то-есть компилятор "под капотом" всё равно создаст приватное поле, и методы к получению и установке значения в это приватное поле, только имя этого поля не угадать. А приватные поля в Unity по умолчанию не сериализуются.
...
Тогда в кастомном инспекторе обращайтесь к свойству напрямую через target, и для того, чтобы приватное поле так же сохраняло своё значение - помечайте текущий объект как "изменённый, грязный", чтобы Unity пересохранила все сериализованные данные при закрытии сцены.

Огромное спасибо! Особенно не просто за ответ, как исправить, а за объяснение!
NapalmRain
UNIт
 
Сообщения: 81
Зарегистрирован: 24 янв 2014, 15:58


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 10