Pregunta ¿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. Yo lo llamo InvokeRepeating() en el Start() método de uno de los GameObject  clases Para configurar el repeatRate parámetro para InvokeRepeating(), Lo estoy pasando un campo público llamado secondsBetweenBombDrops.

Unity ignora el valor que especifico para secondsBetweenBombDrops en el código y en su lugar utiliza 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 agregue el static modificador a secondsBetweenBombDrops, el código se comporta como se esperaba y se usa el valor correcto de 10:

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

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

En el inspector de Unity, el componente de script muestra que secondsBetweenBombDrops es 1. Este valor predeterminado de 1 está presente independientemente de si instancia el prefabricado en el inicio del juego o crea instancias prefabricadas mientras el juego se está ejecutando.


32
2018-03-02 10:23


origen


Respuestas:


La espada de doble filo de la serialización

Unity quiere facilitar las cosas para todos, incluidas las personas con conocimientos limitados de codificación (principiantes, diseñadores).

Para ayudarlos, Unity muestra datos en el inspector. Esto permite que el codificador codifique y el diseñador lo diseñe ajustando los valores sin abrir MonoDevelop / a 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 mediante métodos o propiedades).

Cuando visualiza 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 le importa ninguna modificación de script. Esto puede llevar a confusión si, por ejemplo, myVar se establece en 20 dentro de la secuencia de comandos después del hecho, no se usará. La serialización está escrita en el archivo de escena.

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

Soluciones posibles

Es posible hacer que Unity considere nuevos valores en una secuencia de comandos presionando Restablecer en la rueda de configuración del componente de secuencia de comandos. Eso también restablecerá todas las demás variables del componente, por lo tanto, solo hazlo si eso es lo que quieres.

Haciendo la variable privada y omitiendo el atributo [SerializeField] deshabilitará el proceso de serialización, por lo que Unity ya no buscará en el archivo de escena un valor para mostrar; en su lugar, el script creará el valor en tiempo de ejecución.

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 este motivo, solo se pueden mostrar los valores de los miembros y las variables estáticas no, ya que no son serializables. (Esta es una especificación .NET, no estrictamente específica para Unity). Porque Unity no serializa campos estáticos, esta es la razón por la adición de static el modificador pareció resolver el problema.

Explicando el OP

En el caso de OP, según los comentarios, su campo público mostraba un valor de 1 en el editor. Creías que este valor era el predeterminado, cuando en realidad era el valor que probablemente le diste al campo cuando lo declaraste originalmente. Después de agregar la secuencia de comandos como un componente, hizo el valor 10 y pensó que tenía errores ya que aún usaba el valor de 1. Ahora debería comprender que funcionaba correctamente, tal como estaba diseñado.

¿Qué serializa Unity?

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

El seguimiento:

public class NonMonoBehaviourClass{
   public int myVar;
}

no está serializado por defecto. Aquí nuevamente, esta es la especificación .NET. Unity serializa MonoBehaviour por defecto 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, solo dígalo:

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

Obviamente, no puedes agregarlo a un objeto del juego, por lo que debes usarlo dentro de un MonoBehaviour:

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

esto mostrará el objeto en el inspector y permitirá modificaciones al myVar variable en el caso de NonMonoBehaviourClass. Y de nuevo, cualquier cambio a myVar dentro de la secuencia de comandos no se tendrá en cuenta después de que el valor se serialice y se almacene en la escena.

Consejos adicionales para mostrar cosas en el inspector

Para finalizar, las interfaces no se muestran en el inspector ya que no contienen ninguna variable, solo métodos y propiedades. En 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. Las primeras dos configuraciones son Normal / Depuración. El primero es el predeterminado, el segundo también mostrará la variable privada. Esto es útil para ver sus valores, pero no se puede modificar desde el editor.

Por lo tanto, si necesita que se muestre una interfaz, debería considerar una clase abstracta, ya que ofrece una funcionalidad similar (a excepción de la herencia múltiple), pero puede ser un comportamiento en mono.

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


32
2018-03-02 20:10