Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the wp-plugin-bluehost domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home1/spotsail/public_html/martra/wp-includes/functions.php on line 6114

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893

Warning: Cannot modify header information - headers already sent by (output started at /home1/spotsail/public_html/martra/wp-includes/functions.php:6114) in /home1/spotsail/public_html/martra/wp-includes/rest-api/class-wp-rest-server.php on line 1893
{"id":1103,"date":"2017-09-24T16:49:26","date_gmt":"2017-09-24T16:49:26","guid":{"rendered":"http:\/\/martra.uadla.com\/?p=1103"},"modified":"2020-11-24T14:17:05","modified_gmt":"2020-11-24T14:17:05","slug":"incorporemos-niveles-a-nuestro-juego","status":"publish","type":"post","link":"https:\/\/martra.uadla.com\/incorporemos-niveles-a-nuestro-juego\/","title":{"rendered":"Incorporemos niveles a nuestro juego."},"content":{"rendered":"\n

Ir avanzando por el juego, superando niveles, asumiendo nuevos retos y descubriendo nuevos mundos, es una de las sensaciones que mas les gustan a los jugadores. Da lo mismo el tipo de juego que estemos haciendo, tanto si es un Infinite Runner, un RPG, o un Arcade, los niveles esta ah\u00ed. Pueden estar camuflados en forma de nuevos peligros, nuevas misiones, o nuevos enemigos finales. No importa, en cualquier juego el jugador tiene que sentir que avanza, que aprende y que llega a nuevos niveles.<\/strong><\/p>\n\n\n\n

Este post forma parte del tutorial de desarrollo de Unity<\/a>. En los post anteriores hemos creado un arcade completo que permite recolectar monedas, y existen unos enemigos que acaban con nosotros. Lo \u00fanico que le falta para tener todos los b\u00e1sicos de un Buen Arcade es incorporar niveles, as\u00ed que vamos a ello! Pod\u00e9is obtener el proyecto de Unity con todas las modificaciones anteriores en este link: megafastball-gameover<\/a>.<\/p><\/blockquote>\n\n\n\n

Creando el nuevo nivel.<\/h2>\n\n\n\n

Lo mejor es empezar creando un nuevo nivel, y haciendo que sea m\u00e1s complicado, pero no imposible. No tenemos que empezar desde 0, ya tenemos nuestro Level1 creado, por lo que ya partimos con una buena Base. Para aprovecharlo lo mejor es duplicar nuestro nivel: Level1.<\/strong> Lo seleccionamos en la secci\u00f3n Project<\/em> y pulsamos Cmd+D<\/em> o Ctrl+D<\/em> en Windows. Estos nos crear\u00e1 un Level2.<\/p>\n\n\n\n

\"Los<\/a>
Hemos duplicado el Level1 y nos ha creado el Level2.<\/figcaption><\/figure><\/div>\n\n\n\n

Arrastramos el nuevo nivel a la secci\u00f3n Hierarchy<\/em><\/strong>, ahora tendremos cargados dos niveles. Vemos que en nuestra pantalla donde editamos el nivel visualmente se produce un efecto raro, esto es porque intenta mostrar los dos niveles a la vez. Tenemos que seleccionar el primer nivel y seleccionar Unload Sccene<\/em> en el men\u00fa contextua<\/strong>l.<\/p>\n\n\n\n

\"Menu<\/a>
Tenemos que descargar la primera escena.<\/figcaption><\/figure><\/div>\n\n\n\n

Ya con la primera escena fuera del editor podemos empezar a trabajar con nuestra segunda escena, creando mas muros, mas monedas, y mas enemigos. Para hacerlo, seleccionamos los objetos que queremos duplicar en la ventana de escenario, o en la lista de hyerarchy<\/em>, y los duplicamos. Podemos jugar en la ventana scene<\/em> con los controles para mover o cambiar el tama\u00f1os de los objetos duplicados.<\/p>\n\n\n\n

\"\"<\/a>
Mi Level 2 con muchas paredes, monedas y enemigos.<\/figcaption><\/figure><\/div>\n\n\n\n

En la parte superior izquierda de la imagen est\u00e1n los botones que os permitir\u00e1n seleccionar las herramientas para mover o cambiar de tama\u00f1o los diferentes objetos.<\/strong> Para la creaci\u00f3n del segundo nivel he creado mas muros, y he intentado crear un mini laberinto. He duplicado las monedas, ahora tenemos muchas mas y he aumentado los enemigos a seis. Es en resumen lo mismo que el primer nivel pero con mas objetos. Podr\u00edamos dejarlo as\u00ed y retrasar la introducci\u00f3n de sorpresas para los niveles siguientes.<\/p>\n\n\n\n

Crear un Canvas nuevo para cambiar de nivel<\/h2>\n\n\n\n

De la misma forma que creamos un Canvas para mostrar nuestro GameOver ahora tenemos que crear uno para mostrar el cambio de nive<\/strong>l. Felicitaremos al usuario y le mostraremos un bot\u00f3n para que al pulsarlo pase al siguiente nivel.<\/p>\n\n\n\n

Para ello lo mas sencillo es duplicar el Canvas del GameOver<\/strong>. Con la escena Level1 cargada, seleccionamos el GameOverCanvas<\/em> y pulsando Cmd+D<\/em> o Ctrl+D<\/em> en Windows conseguiremos un duplicado, cambiamos su nombre y sus elementos.<\/p>\n\n\n\n

\"\"<\/a><\/figure><\/div>\n\n\n\n
\"\"<\/a><\/figure><\/div>\n\n\n\n

Al nuevo Canvas podemos llamarlo PasaNivelCanvas<\/em>. Cambiaremos tambi\u00e9n el nombre y el contenido de su campo texto que se llamar\u00e1 PasaNivelText<\/em> y ponemos el mensaje que queremos mostrar al Jugador cuando supera el nivel.

Tambi\u00e9n modificamos el nombre del bot\u00f3n, para llamarlo PasaNivel<\/em>. Para que cargue el nivel dos tenemos que editar en el Inspector<\/em> el script que tenemos asociado al texto del bot\u00f3n y indicarle el nombre del segundo nivel.<\/strong>
<\/p>\n\n\n\n

Editamos los scripts.<\/h2>\n\n\n\n

Ahora ya tenemos todo lo necesarios para mostrar la pantalla intermedia entre los niveles, solo nos falta que los scripts gestionen el paso de un nivel a otro<\/strong>. Por eso lo primero que tenemos que plantearnos es: \u00bfCuando va a pasar de nivel el jugador? En mi caso he decidido que sea cuando recoja todas las monedas, sin importar la puntuaci\u00f3n realizada.<\/strong><\/p>\n\n\n\n

El primer script a modificar es el GameManager<\/strong>. Vamos a ver por partes las modificaciones introducidas
<\/p>\n\n\n\n

public GameObject pasarNivelCanvas;\npublic int coins2Pass;\nprivate bool bPasarNivel = false;<\/pre>\n\n\n\n

Hempos definido tres nuevas variables. En pasarNivelCanvas<\/em> almacenaremos el Canvas a mostrar cuando el jugador consigue pasar de nivel. En coins2Pass<\/em> guardamos el numero de monedas que el usuario tiene que recoger para dar el nivel como terminado. La ultima variable, bPasarNivel<\/em>, es una variable privada, en la que el script guarda si se ha informado o no el Canvas del siguiente nivel<\/strong>, en caso de no estar informado asume que no existe la posibilidad de pasar de nivel.<\/p>\n\n\n\n

Cada nivel tiene su propio GameManager. Podemos configurar un numero diferente de monedas a recoger en cada uno de ellos. Aunque el script sea \u00fanico la parametrizaci\u00f3n es \u00fanica por nivel.<\/p><\/blockquote>\n\n\n\n

void Start () {\n.......\nif (pasarNivelCanvas != null) {\npasarNivelCanvas.SetActive (false);\nbPasarNivel = true;\n}\n.....\n\/\/Activamos el MainCanvas\nmainCanvas.SetActive(true);\n}<\/pre>\n\n\n\n

En la funci\u00f3n Start<\/em> incorporamos una comprobaci\u00f3n para saber si nos han informado del Canvas<\/em> pasarNivelCanvas<\/em>.<\/strong> En caso afirmativo lo desactivamos y indicamos al GameManager<\/em> que va a poder pasar de nivel poniendo un true<\/em> en la variable bPasarNivel<\/em>. Por \u00faltimo he incorporado una llamada a la activaci\u00f3n del Canvas mainCanvas<\/em>, ya que se quedaba desactivado al pasar de nivel.<\/p>\n\n\n\n

void Update () {\nswitch (gameState)\n{\ncase gameStates.Playing:\n.....\nif (bPasarNivel && coins2Pass == 0) {\ngameState = gameStates.BeatLevel; \/\/Cambiamos el estado del juego a GameOver\nmainCanvas.SetActive (false); \/\/Quitamos el mainCanvas.\npasarNivelCanvas.SetActive (true); \/\/Activamos el pasarNivelCVanvas Canvas.\n}\n}\n....\ncase gameStates.BeatLevel:\n\/\/ en el caso de que tengamos un GameOver no hacemos nada!\nbreak;\n}\n}<\/pre>\n\n\n\n

En la funci\u00f3n update<\/em>, hemos incorporado la comprobaci\u00f3n para saber si se ha pasado de nivel o no.<\/strong> Primero se mira si bPasarNivel<\/em> es true<\/em>, y en caso afirmativo se comprueba si coin2Pass<\/em> ya es 0. Esta variable ser\u00e1 0 cuando el jugador haya recogido todas las monedas, ya que cada moneda que recoge le resta una al valor que le hemos dado en el editor a esta variable. En caso de que el usuario haya pasado el nivel, cambiamos el state<\/em> del gameManager, desactivamos el mainCanvas<\/em> y activamos el pasarNivelCanvas<\/em>.<\/strong><\/p>\n\n\n\n

public void Collect(int amount) {\ncoins2Pass -= amount;\n}<\/pre>\n\n\n\n

Hemos creado una funcion nueva, llamada Collect<\/em>. Esta es la funci\u00f3n que tendremos que llamar siempre que queramos restar alg\u00fan valor a coins2Pass<\/em>.<\/strong>
El escript entero queda as\u00ed:<\/p>\n\n\n\n

using UnityEngine;\nusing System.Collections;\nusing UnityEngine.UI;\n\npublic class GameManager : MonoBehaviour {\npublic static GameManager gm;\npublic GameObject player;\npublic enum gameStates {Playing, Death, GameOver, BeatLevel};\npublic gameStates gameState = gameStates.Playing;\npublic GameObject mainCanvas;\npublic Text textScoreMainCanvas;\npublic GameObject gameOverCanvas;\npublic Text textScoreGameOver;\npublic GameObject pasarNivelCanvas;\npublic int coins2Pass;\nprivate bool bPasarNivel = false;\n\nprivate isLive live;\n\n\/\/Se ejecuta una vez, al iniciar el script.\nvoid Start () {\nif (player == null) { \/\/Si no se ha informado el Player busca un objeto con el Tag Playe.\nplayer = GameObject.FindWithTag(\"Player\");\n}\nif (pasarNivelCanvas != null) {\npasarNivelCanvas.SetActive (false);\nbPasarNivel = true;\n}\nlive = player.GetComponent<isLive>; (); \/\/Recuperamos el script isLive del player y lo guardamos en una variable.\ngameState = gameStates.Playing; \/\/Cambiamos el estado a Playing.\n\n\/\/ Desactivamos el Canvas gameOver, just in case.\ngameOverCanvas.SetActive (false);\n\/\/Activamos el MainCanvas\nmainCanvas.SetActive(true);\n}\n\n\/\/Se ejecuta en cada frame, varias veces por segundo.\nvoid Update () {\nswitch (gameState)\n{\ncase gameStates.Playing:\nif (live.live == false) { \/\/ si la variable live es false el jugador ha muerto.\ngameState = gameStates.GameOver; \/\/Cambiamos el estado del juego a GameOver\nmainCanvas.SetActive (false); \/\/Quitamos el mainCanvas.\ngameOverCanvas.SetActive (true); \/\/Activamos el gameOver Canvas.\n\ntextScoreGameOver.text = textScoreMainCanvas.text; \/\/Copiamos el texto con la puntuaci\u00f3n del MainCanvas al GameOver.\n}\nif (bPasarNivel && coins2Pass == 0) {\ngameState = gameStates.BeatLevel; \/\/Cambiamos el estado del juego a GameOver\nmainCanvas.SetActive (false); \/\/Quitamos el mainCanvas.\npasarNivelCanvas.SetActive (true); \/\/Activamos el pasarNivelCVanvas Canvas.\n}\nbreak;\ncase gameStates.GameOver:\n\/\/ en el caso de que tengamos un GameOver no hacemos nada!\nbreak;\ncase gameStates.BeatLevel:\n\/\/ en el caso de que tengamos un GameOver no hacemos nada!\nbreak;\n}\n}\npublic void Collect(int amount) {\ncoins2Pass -= amount;\n}\n}<\/pre>\n\n\n\n

Para llamar a la funci\u00f3n collect<\/em> hemos utilizado el script Explosion<\/em>, ya lo creamos en el post de explosiones<\/a>, y esta en todos los objetos que explotan. Por ahora tan solo hemos configurado las monedas para que reduzcan la variable coins2Pass<\/em>, pero en el futuro seria muy sencillo configurar cualquier objeto que tenga una explosi\u00f3n para que reduzca esa variable y permita a nuestro jugador pasar antes de nivel.<\/p>\n\n\n\n

using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;<\/pre>\n\n\n\n
public class explosion : MonoBehaviour {\npublic GameObject explosionObject; \/\/Para que se pueda indicar la explosion a ejecutar.\nprivate isLive live;\nprivate GameObject gm;\nprivate GameManager gManager;\npublic int valueCollect = 0;\/\/Variable que indicara cuanto tiene que restar al juagador para que consiga su objetivo de pasaer de nivel.\nvoid Start(){\nlive = GetComponent<isLive> ();\ngm = GameObject.Find(\"GameManager\");\nif (gm != null) {\ngManager = gm.GetComponent<GameManager>(); \/\/\n}\n}\nvoid OnDestroy(){ \/\/Esta funciona se llama cuando el objeto va a ser destruido.<\/pre>\n\n\n\n
if (explosionObject!=null && gManager.gameState == GameManager.gameStates.Playing) { \/\/Comprobamos de que se ha informado la Explosion.\nInstantiate (explosionObject, transform.position, Quaternion.identity); \/\/Se ejecuta la explosion\n}\nif (live != null) {\nlive.live = false;\n}\nif (valueCollect > 0) {\ngManager.Collect (1); \/\/Llamamos a GameManager para que reduzca la cantidad de monedas a recoger.\n}\n}\n}<\/pre>\n\n\n\n

Hemos incorporado una variable p\u00fablica (valueCollect<\/em>) para que se le pueda dar valor desde el editor. <\/strong>Contiene el valor a restar del total que necesita nuestro jugador para pasar de nivel. Es decir, si le damos el valor de 1 a la moneda, restara esa cantidad a la cantidad de monedas que nuestro jugador necesita recolectar. Pero podr\u00edamos crear un objeto nuevo: saco de monedas, y darle un valor de 5, para que el jugador se sienta tentado a recoger objetos nuevos.<\/p>\n\n\n\n

Ya lo tenemos todo, ahora solo hace falta configurar los scripts en los objetos que lo usan.<\/strong><\/p>\n\n\n\n

\"\"<\/a>
Configuraci\u00f3n del GameManager en el nivel 1<\/figcaption><\/figure><\/div>\n\n\n\n

Como veis se ha incorporado el nombre del pasarNivelCanvas y le hemos asignado un valor de 9 a la variable Coins2Pass.<\/p>\n\n\n\n

\"\"<\/a>
En el GameManager del Level2 no hemos informado las variables necesarias para pasar de Nivel.<\/figcaption><\/figure><\/div>\n\n\n\n

En el GameManager del segundo nivel no hemos informado las variables de pasarCanvas ni coins2Pass, por lo que este nivel es el \u00faltimo, no llega a ning\u00fan sitio. Cosa que tampoco es del todo correcta. No costar\u00eda nada darle un final y permitir al usuario volver a cargar el primer nivel para empezar de nuevo.<\/p>\n\n\n\n

\"\"<\/a>
En el Prefab informamos las variables Collect<\/figcaption><\/figure><\/div>\n\n\n\n

Veamos el resultado final del juego:<\/p>\n\n\n\n

Si quer\u00e9is obtener el proyecto entero una vez finalizado el tutorial lo pod\u00e9is obtener en este link: megafastball-final.<\/a><\/p><\/blockquote>\n\n\n\n

Se acaba el tutorial<\/h2>\n\n\n\n

Nuestro juego ya tiene todo lo que tiene que tener, bueno le falta un final, pero lo mas importante es que nosotros ya tenemos lo que tenemos que tener!!!! El juego se tiene y se puede mejorar, pero ya tenemos los conocimientos suficientes como para mejorarlo, y mucho!
Cosa que podriamos hace:<\/p>\n\n\n\n