¿Por qué Unity ignora el valor inicializado de un campo público no estático?


Estoy usando InvokeRepeating() para llamar a un método en un juego. Llamo InvokeRepeating() en el método Start() de una de las clases GameObject. Para establecer el parámetro repeatRate para InvokeRepeating(), le estoy pasando un campo público llamado secondsBetweenBombDrops.

Unity ignora el valor que especifico para secondsBetweenBombDrops en el código y en su lugar usa algún valor predeterminado (es decir, 1) cuando secondsBetweenBombDrops se declara sin un modificador estático:

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

Sin embargo, una vez que agrego el modificador static a secondsBetweenBombDrops, el código se comporta como se espera y el valor correcto de 10 se utiliza:

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

¿Por qué este campo requiere el modificador static para usar el valor apropiado?

En el inspector de Unity, el componente script muestra que secondsBetweenBombDrops es 1. Este valor predeterminado de 1 está presente independientemente de si instancio el prefab al inicio del juego o creo instancias prefab mientras el juego se está ejecutando.

Author: Yvette Colomb, 2016-03-02

1 answers

La espada de doble filo de la serialización

Unity quiere hacer las cosas más fáciles para todos, incluidas las personas con conocimientos limitados de codificación (principiantes, diseñadores).

Para ayudarles, Unity muestra datos en el inspector. Esto permite al codificador codificar y al diseñador diseñar ajustando los valores sin abrir MonoDevelop / an IDE.

Hay dos formas de mostrar los valores en el inspector:

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

El segundo es mejor ya que cumple con el principio de encapsulación (las variables son privadas / protegidas y modificadas a través de métodos o propiedades).

Cuando se muestra una variable en el Editor, el valor dado en el script solo se usa al arrastrar el script. Unity luego serializa esos valores y ya no se preocupa por ninguna modificación del script. Esto puede llevar a confusión si, por ejemplo, myVar se establece en 20 dentro del script después del hecho, no se usará. La serialización está escrita en la escena file.

Las dos líneas del ejemplo funcionan exactamente de la misma manera.

Posibles soluciones

Es posible hacer que Unity considere nuevos valores en un script pulsando Reset en la rueda de configuración del componente script. Eso también restablecerá todas las otras variables del componente, así que solo haga esto si eso es lo que se pretende.

Hacer que la variable sea privada y omitir el atributo [SerializeField] deshabilitará el proceso de serialización, por lo que Unity ya no se verá el archivo de escena para un valor a mostrar-en su lugar, el valor será creado en tiempo de ejecución por el script.

Al agregar un componente a Unity, se crea un nuevo objeto del tipo del componente. Los valores que se muestran son los valores serializados de ese objeto. Por esta razón, solo se pueden mostrar los valores de los miembros y las variables estáticas no lo son, ya que no son serializables. (Esta es una especificación. NET, no estrictamente específica de Unity.) Porque Unity no se serializa static fields , esta es la razón por la que agregar el modificador static parecía resolver el problema.

Explicando el PO

En el caso OP, basado en los comentarios, su campo público mostraba un valor de 1 en el editor. Pensaste que este valor era predeterminado, cuando en realidad era el valor que más probablemente le diste al campo cuando lo declaraste originalmente. Después de agregar el script como componente, hizo que el valor 10 y pensó que tenía errores, ya que todavía estaba utilizando el valor de 1. Usted ahora debe entender que estaba funcionando bien, como está diseñado.

¿Qué serializa Unity?

De forma predeterminada, Unity serializará y mostrará los tipos de valores (int, float, enum, etc.), así como string, array, List y MonoBehaviour. (Es posible modificar su apariencia con scripts de editor, pero esto está fuera de tema.)

Lo siguiente:

public class NonMonoBehaviourClass{
   public int myVar;
}

No se serializa por defecto. Aquí de nuevo, esta es la especificación. NET. Unidad serializa MonoBehaviour por predeterminado como parte del requisito del motor (esto guardará el contenido en el archivo de escena). Si desea mostrar una clase "clásica" en el editor, simplemente dígalo:

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

Obviamente, no se puede añadir a un objeto de juego por lo que necesita utilizar dentro de un MonoBehaviour:

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

Esto mostrará el objeto en el inspector y permitirá modificaciones a la variable myVar en la instancia de NonMonoBehaviourClass. Y de nuevo, cualquier cambio a myVar dentro del script no se considerará después de que el valor sea serializado y almacenado en la escena.

Consejos adicionales para mostrar cosas en el inspector

Para terminar, las interfaces tampoco se muestran en el inspector, ya que no contienen ninguna variable, solo métodos y propiedades. En el modo de depuración, las propiedades no se muestran de forma predeterminada. Puede cambiar este modo usando el botón con tres líneas en la esquina superior derecha del Inspector. Los dos primeros ajustes son Normal / Debug. El primero es el predeterminado, el segundo también mostrar variable privada. Esto es útil para ver sus valores, pero no se puede alterar desde el editor.

Así que si necesita que se muestre una interfaz, tendría que considerar una clase abstracta, ya que ofrece una funcionalidad similar (a excepción de la herencia múltiple), pero puede ser un MonoBehaviour.

Referencias:

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

 33
Author: Everts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-11 13:02:47