Почему Unity игнорирует инициализированное значение нестатического открытого поля?

я использую InvokeRepeating() для вызова метода в игре. Я зову InvokeRepeating() на Start() метод одного из GameObject классы. Установить на InvokeRepeating(), Я передаю ему общественное поле под названием secondsBetweenBombDrops.

Unity игнорирует значение, которое я указываю для secondsBetweenBombDrops в коде и вместо этого использует какое-то значение по умолчанию (т. е. 1) когда secondsBetweenBombDrops объявлен без модификатора static:

public float secondsBetweenBombDrops = 10f;
void Start() {
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}

однако, как только я добавлю static модификатор secondsBetweenBombDrops, код ведет себя так, как ожидалось, и используется правильное значение 10:

public static float secondsBetweenBombDrops = 10f;
void Start() {
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}

почему это поле требует static модификатор для использования соответствующего значения?

в инспекторе Unity компонент скрипта показывает, что secondsBetweenBombDrops is 1. Это значение по умолчанию 1 присутствует независимо от того, создаю ли я экземпляр prefab при запуске игры или создаю экземпляры prefab во время игры.

1 ответов


обоюдоострый меч сериализации

Unity хочет сделать вещи проще для всех, в том числе людей с ограниченными знаниями кодирования (начинающих, дизайнеров).

чтобы помочь им, Unity отображает данные в инспекторе. Это позволяет кодеру кодировать, а дизайнеру проектировать, настраивая значения без открытия среды IDE MonoDevelop/an.

существует два способа отображения значений в инспектор:

public int myVar = 10;
[SerializeField] private int myOtherVar = 0; // Can also be protected

второй лучше, поскольку он соответствует принципу инкапсуляции (переменные являются частными / защищенными и модифицированными с помощью методов или свойств).

при отображении переменной в Редакторе, значение, указанное в скрипте используется только при перетаскивании скрипта. Unity затем сериализует эти значения и больше не заботится о какой-либо модификации скрипта. Это может привести к путанице, если, например, myVar установлено значение 20 внутри скрипта после того, он не будет использоваться. Сериализация в файл сцены.

две строки в Примере работают точно так же.

возможные решения

можно заставить Unity учитывать новые значения в скрипте, нажав Reset на колесе настроек компонента скрипта. Это также сбросит все другие переменные компонента, поэтому делайте это только в том случае, если это предназначено.

сделать переменная private и пропуск атрибута [SerializeField] отключит процесс сериализации, поэтому Unity больше не будет искать в файле сцены значение для отображения - вместо этого значение будет создано во время выполнения скриптом.

при добавлении компонента в Unity создается новый объект типа компонента. Отображаемые значения являются сериализованными значениями из этого объекта. По этой причине могут отображаться только значения членов, а статические переменные-нет, поскольку они не сериализуемы. (Это спецификация .NET, не строго специфичная для Unity.), Потому что Unity не сериализует статические поля, вот почему добавлять static модификатор, казалось, решил проблему.

объясняя OP

в случае OP, основываясь на комментариях, ваше открытое поле показывало значение 1 в Редакторе. Вы думали, что это значение по умолчанию, когда это было фактически значение, которое вы, скорее всего, дали полю, когда изначально заявляя об этом. После добавления скрипта в качестве компонента вы сделали значение 10 и подумали, что оно глючит, поскольку оно все еще использует значение 1. Теперь вы должны понять, что он работал просто отлично, как и планировалось.

что такое сериализация Unity?

по умолчанию Unity сериализует и отображает типы значений (int, float, enum и т. д.), а также string, array, List и MonoBehaviour. (Можно изменить их внешний вид с помощью скриптов редактора, но это не по теме.)

следующее:

public class NonMonoBehaviourClass{
   public int myVar;
}

по умолчанию не сериализуется. Здесь снова это спецификация .NET. Unity сериализует MonoBehaviour по умолчанию как часть требования к движку (это сохранит содержимое в файл сцены). Если вы хотите отобразить "классический" класс в редакторе, просто скажите:

[System.Serializable]
public class NonMonoBehaviourClass{
   public int myVar = 10;
}

очевидно, вы не можете добавить его в игровой объект, поэтому вам нужно использовать в MonoBehaviour:

public class MyScript:MonoBehaviour{
     public NonMonoBehaviourClass obj = new NonMonoBehaviourClass();
}

это отобразите объект в инспекторе и разрешите изменения в myVar переменная в экземпляре NonMonoBehaviourClass. И снова любые изменения в myVar внутри скрипта не будет рассматриваться после сериализации значения и сохранения его в сцене.

Дополнительные советы по отображению вещей в инспекторе

для завершения интерфейсы не отображаются в инспекторе, поскольку они не содержат переменных - только методы и свойства. В режиме отладки, свойства по умолчанию не отображается. Вы можете изменить этот режим с помощью кнопки с тремя линиями в правом верхнем углу инспектора. Первые два параметра-Normal / Debug. Первый-по умолчанию, второй также будет отображать закрытую переменную. Это полезно для просмотра их значений, но не может быть изменено из редактора.

поэтому, если вам нужен интерфейс для отображения, вам придется рассмотреть абстрактный класс, поскольку он предлагает аналогичную функциональность (за исключением нескольких наследований) но может быть скрипта.

ссылки:

http://docs.unity3d.com/ScriptReference/SerializeField.html

http://docs.unity3d.com/Manual/script-Serialization.html

https://www.youtube.com/watch?v=9gscwiS3xsU

https://www.youtube.com/watch?v=MmUT0ljrHNc