Por qué entender esto#
Muchos comportamientos "raros" de Unity dejan de ser un misterio cuando entiendes qué pasa por debajo al darle a Play. No necesitas saberlo para hacer un juego, pero te convierte de usuario en alguien que comprende la herramienta.
El motor es C++, tu código es C##
El núcleo de Unity (render, física, audio) está escrito en C++, por rendimiento. Tu código está en C#. Entre ambos hay un puente: cada vez que llamas a transform.position o a GetComponent, estás cruzando de C# a C++ y volviendo. Ese cruce tiene un pequeño coste, y explica consejos como "cachea GetComponent" o "evita miles de Update vacíos": cada uno es una llamada a través de ese puente. Tu C# se compila y se ejecuta mediante un scripting backend (Mono en el editor, IL2CPP —que lo traduce a C++— en muchas builds finales).
Paso a paso: del botón al primer fotograma#
Cuando pulsas Play, en orden aproximado:
- Se recompila el código si hiciste cambios (verás un pequeño "spinner"). Unity necesita tu C# actualizado.
- Se carga la escena: Unity crea en memoria todos los GameObjects y sus componentes a partir de los datos guardados.
- Se deserializan los valores: cada campo que pusiste en el Inspector se "inyecta" en el objeto (ver más abajo).
- Arranca el ciclo de vida: para todos los objetos,
Awake, luegoOnEnable, luegoStart(ver el ciclo de vida). - Empieza el bucle de juego: fotograma tras fotograma, Unity llama a
FixedUpdate(a ritmo fijo),UpdateyLateUpdate, intercalando física, entrada y render. - Al pulsar Stop, se destruye todo lo creado y se restauran los valores de antes de Play.
Al entrar en Play, Unity toma una 'foto' del estado de la escena. Todo lo que ocurre en Play sucede sobre copias en memoria. Al pulsar Stop, Unity descarta esas copias y restaura la foto original. Por eso mover un objeto en Play y darle a Stop lo devuelve a su sitio: nunca tocaste los datos guardados, solo una copia temporal.
La serialización: el pegamento invisible#
Cuando declaras [SerializeField] private float velocidad = 5f;, Unity serializa ese campo: guarda su valor junto a la escena/prefab y lo muestra en el Inspector. Al cargar, lo deserializa de vuelta al objeto. Esto ocurre antes de Awake, por eso en Awake ya tienes los valores del Inspector listos. También explica por qué Unity serializa campos y no propiedades, por qué los tipos deben ser serializables, y por qué a veces, tras cambiar un script, un valor "se resetea": cambió la forma en que se serializa.
Por qué MonoBehaviour no tiene constructor#
En C# normal, new MiClase() llama al constructor. Pero un MonoBehaviour lo instancia Unity, a veces al deserializar y en momentos donde el objeto aún no está conectado al motor (transform o gameObject podrían no estar listos). Por eso escribir lógica en el constructor da problemas: Unity te ofrece Awake como su "constructor seguro", llamado cuando el objeto ya vive en la escena. Es el mismo motivo por el que no usas new para crear componentes: usas AddComponent o Instantiate.
El bucle de juego (PlayerLoop)#
Internamente, Unity ejecuta cada fotograma un PlayerLoop: una secuencia fija de fases (entrada → FixedUpdate/física → Update → animación → LateUpdate → render → fin de frame). Tus métodos del ciclo de vida son "ganchos" que Unity llama dentro de esas fases. Cuando entiendes que existe esa secuencia, el orden entre Update, física y render deja de ser magia.
Lo que esto te enseña#
- Cachea referencias: cada cruce C#↔C++ cuesta; hacerlo en
Updatese multiplica. - Inicializa en Awake/Start, no en el constructor: el objeto no está listo antes.
- No confíes en cambios hechos en Play: son copias temporales.
- Los valores del Inspector ganan a los del código: se deserializan encima al cargar.
Resumen#
Al pulsar Play, Unity recompila tu C#, carga la escena, deserializa los valores del Inspector, ejecuta Awake/OnEnable/Start y entra en el bucle de juego (FixedUpdate/Update/LateUpdate + física + render), sobre copias que descarta al parar. Tu C# habla con un motor en C++ a través de un puente con coste. Entender esto explica el ciclo de vida, la serialización, por qué no hay constructor y por qué los cambios en Play no perduran.