[Unity 3D] Cambio de nivel o escena

Aloha kākou. Siguiendo con la línea «Unity for Dummies», en esta ocasión mostraré algo que suele ser útil prácticamente en cualquier videojuego: «el cambio de escena o de nivel».

unity_escena_princ2

Cambio de escena


Previo paso a realizar los cambios de escena o de nivel, lo que debemos hacer es marcar a las escenas como parte del todo, o sea del videojuego completo. Para esto vamos a File -> Build Settings...

unity_escena

Podemos ver esa ventana. Seguramente dentro del recuadro Scenes in Build lo veremos vacío. Lo que debemos hacer es pulsar el botón Add Current para agregar la escena sobre la cual estamos trabajando, al proyecto. Estos pasos los deberemos hacer estando parados en cada una de las diferentes escenas/niveles que tendrá el videojuego.
Una vez hecho esto (y asegurándonos que están tildadas las casillas de cada escena en esa ventana) podemos proceder a llamarlas desde código.

CAMBIO DE NIVEL

Cambio de nivel

Cambio de nivel

A veces necesitamos cambiar de nivel y esto es muy sencillo colocando dentro del script. Como ya he mostrado en el «Tutorial de Unity -> Programación» bastará con agregar la línea:

  • Application.LoadLevel(x);

dentro de la función ya sea de colisión con algún objeto, o cuando el personaje llega a determinada posición, etc.
El x lo cambiaremos ya sea por el nombre de la escena entre comillas dobles "NombreEscena" o por el número ( Application.LoadLevel(1) ) que figura en el margen derecho donde se encuentran listadas todas las escenas en la ventana de Build Settings….

Y listo el pollo, tenemos el cambio de nivel andando.

CAMBIO DE ESCENA

Ahora bien, esto se puede complicar un poco más si queremos hacer un cambio de escena. Por ejemplo, nos encontramos caminando en un muy bello paisaje y nos encontramos furtivamente con un Pokémon salvaje. En el videojuego de la serie Pokémon Rojo/Azul/y decenas de otros colores, esto nos llevaba a una nueva pantalla en la cual se libraba la batalla.

Este tipo de cambios lo podemos hacer de dos maneras, la sencilla y que consume muchos recursos, y la «un poco menos sencilla» y que consume menos recursos computacionales.

La sencilla:
En una misma escena hacemos tanto la parte principal del juego, como la parte de batalla (esta parte la hacemos muy alejada de la cámara, cosa que nunca se pueda ver). Entonces cuando se detecta que necesita entrar en batalla, lo que hacemos es cambiar la posición de la cámara a esta otra parte.
Como vimos sería un simple camara.transform.Translate(new Vector3(x,y,z)), siendo camara el gameObject correspondiente a ella.

La «un poco menos sencilla»:
Acudiremos a un nueva función que se llama LoadLevelAdditive y lo que hace es agregar una escena sobre otra ya existente.
A diferencia del caso anterior, crearemos dos escenas, una para la parte principal del juego mientras que la otra para el campo de batalla.
Entonces, cuando detectamos dentro de la escena principal este Pokémon Legendario que nos quiere derribar, llamaremos a

  • Application.LoadLevelAdditive("BattleField");

reemplazando BattleField por el nombre de la escena que se corresponde justamente con el campo de batalla.

¿Qué pasará al hacer esto?
Bueno como antes mencioné se superpondrá la escena principal con la nueva. Sin embargo no queremos esto, sino que queremos que aparezca la nueva, sin la anterior. Para ello debemos desactivar cada uno de los elementos de la escena principal así no se ven, ni interactúan con nada. Si lo hacemos a lo noob nos sucederá que cuando queramos volver a tener la escena, no vamos a poder activarlos directamente (vaya uno a saber por qué). Por lo que una solución a esto será crear un GameObject vacío (En la barra de menú: GameObject -> Create Empty ) e incorporarle a él todos los objetos de la escena. En la ventana de Hierarchy debería verse algo como lo siguiente:

unity_escena2

Luego de hacer esto, pasaremos al código. Supondremos que cuando colisionen 2 objetos se produzca el cambio de escena. Si quisieramos 2 objetos en particular, el script por ejemplo lo pondríamos en el personaje, y dentro del mismo, en la función de colisión preguntaríamos si su colisión se está dando con un determinado objeto.
A continuación se muestra el código que realizará todo lo dicho anteriormente.

unity_escena3

Dentro de la función OnCollisionEnter2D tendremos la llamada a LoadLevelAdditive con la nueva escena. Luego tenemos un bucle de ejecución que dice: a cada hijo del objeto root, desactivarlo. Y justamente hacemos lo que mencionamos.

¿Y que hace esa bandera ahí? Pues esta variable nos permite asegurarnos de lo siguiente: si llamamos a cargar la nueva escena es porque el objeto colisionó en la escena principal, pero ahora cuando queremos volver a la escena principal vamos a retomar donde anteriormente quedamos, y esto es en la colisión, por lo que nuevamente volverá a entrar a la nueva escena y así indefinidamente hasta que nuestra PC explote. Por eso, la bandera nos permite asegurarnos que entre una sola vez a la carga de la nueva escena, y recién cuando el personaje deje de estar colisionando se desactive para luego en otra ocasión volver a entrar a la nueva escena.

Ahora ya fuimos al BattleField. Y supongamos que capturamos al Pokémon salvaje que nos apareció, por lo que queremos volver nuevamente al escenario principal. Lo que debemos hacer en la escena BattleField es lo mismo que hicimos en la principal respecto de crear un nuevo GameObject vacío y agregar como hijos a todos los objetos de la escena.
En cuanto a código, lo que haremos será destruir toda la escena del campo de batalla y activar cada objeto de la escena principal. Como la función LoadLevelAdditive nos ensambla una escena sobre otra, podremos tranquilamente activar los objetos que antes desactivamos de la escena que inicialmente realizamos la llamada a la escena secundaria.
A continuación se encuentra el código del script:

  • void OnCollisionEnter2D(Collision2D col)
       Destroy (GameObject.Find("root2"));
       foreach (Transform child in GameObject.Find("root").transform) {
          child.gameObject.SetActive(true);
       }
    }
    

Observar que solo destruyo root2. Este objeto es el que contiene dentro todos los objetos de la escena secundaria. Como sería el caso de root en la escena principal.

En principio todo esto debería bastar para hacer cambios de nivel o de escena en un proyecto de Unity.

Cualquier duda dejen sus comentarios aquí abajo.

Keep on coding 😉

5 comentarios en “[Unity 3D] Cambio de nivel o escena

  1. Sebastián dijo:

    Muy buen trabajo. Estoy siguiendo el tutorial y me gusta mucho. Por favor continualo porque te apuesto que hay otras personas como yo que gustan de él. Felicitaciones

  2. Johnjolion dijo:

    Qué buen tutorial! Continúa así de bien, hacen falta más tutoriales escritos, esos en video no son muy cómodos para practicar… Muchas gracias por tu esfuerzo!

Deja un comentario