El valor nulo de Unity
Parte de la sección Fundamentos de scripting en Unity del Journey de Unity de Coddy. Lección 46 de 67.
Un objeto de Unity tiene dos mitades: el objeto de C# que conserva tu script y el objeto del motor que hay detrás. Destroy(obj) elimina la mitad del motor al final del fotograma, pero tu variable sigue apuntando a la mitad de C#, así que, en términos de C# puro, no es null. Unity redefine == para contemplar esto: una vez que se destruye el objeto, obj == null es true, al igual que la prueba breve !obj. Esto es el null falso de Unity.
?., ?? e is null no usan ese ==. Comprueban la referencia de C#, que aún existe, así que permiten que se realice la llamada, y acceder al objeto destruido provoca MissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it. Esta etiqueta muestra el nombre del líder de la carrera, que puede quedar fuera de juego (ser destruido):
[SerializeField] private Transform leader;
void Update()
{
// lanza una excepción cuando se destruye leader: string shown = leader?.name ?? "nobody";
string shown = leader != null ? leader.name : "nobody";
Debug.Log("Leader: " + shown);
}Para cualquier cosa que provenga de UnityEngine.Object (GameObjects, componentes, tus scripts), comprueba con == null, != null o if (obj), y reserva ?. y ?? para objetos de C# puros, como las cadenas. Recuerda también que Destroy espera hasta el final del fotograma: hasta entonces, el objeto sigue vivo y == null es false.
Desafío
IntermedioEl dron persigue a su objetivo, y el objetivo se destruye 2 segundos después de comenzar el juego. A partir de entonces, la Consola se llena de MissingReferenceException, porque target?.position no detecta que el objetivo ha desaparecido.
Corrige Update() con la propia comprobación de null de Unity: mientras el objetivo exista, el dron vuela hacia él a speed; una vez que se destruye, el dron se queda donde está, sin errores.
Pulsa Play y observa la Consola, corrige el script y, después, pulsa Check.
Pruébalo tú mismo
using UnityEngine;
public class Chaser : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float speed = 2f;
void Start()
{
Destroy(target.gameObject, 2f); // el objetivo se destruye después de 2 segundos
}
void Update()
{
Vector3 goal = target?.position ?? transform.position;
transform.position = Vector3.MoveTowards(transform.position, goal, speed * Time.deltaTime);
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Fundamentos de scripting en Unity
1Tu primer script
Hola, UnityColoca el cuboMuévete en cada fotogramaGira cada segundoDirige con las teclasRepaso: conduce el cubo4Vectores
Sumar vectoresDireccionesEspacio local y globalVelocidad diagonalDistancia entre objetosVector3 es una estructuraRepaso: piloto de dron7Proyecto: Atrapa la estrella
El atrapadorUna estrella fugaz10El ciclo de vida de los scripts
Awake y StartUpdate y LateUpdateOnEnable y OnDisableEl orden del ciclo de vidaRepaso: registrador del ciclo de vida2El Inspector
Campos del InspectorSerializeFieldNúmeros decimales y MathfAtributos del InspectorRepaso: Ascensor5Transformaciones y jerarquía
Padres e hijosEscalaMirar objetosMoverse hacia un puntoRepaso: Luna en órbita8Encontrar cosas
Buscar por nombreEtiquetasBuscar por tipoLas referencias superan a FindEl valor nulo de UnityRepaso: la moneda más cercana11Proyecto: Esquiva los bloques
El corredorBloques que caen6GameObjects y componentes
Referencias en el InspectorObtener un componenteComponentes faltantesAñadir un componenteRequireComponentMostrar y ocultarRepaso: interruptor de luz