En este capítulo aprenderemos como usar ui/CocosGUI.h. Nuestro proyecto ha sufrido una completa reestructuración para facilitar la extensión de nuestro juego, la lógica que ya conocemos hasta el momento se mantiene intacta.
Explicaremos el uso de nuevos componentes y la nueva estructura de la aplicación, para ello descarga la carpeta Classes y Resources del proyecto aquí. Estas clases y recursos también serán usadas en el capítulo siguiente.
Queremos que el usuario pueda cambiar el volumen del sonido de fondo y de los efectos como los disparos o explosiones, además queremos guardar cuantos niveles ha superado y así saber cuál es el siguiente a desbloquear, todo esto lo gestionaremos mediante un singleton llamado GameManager que nos facilitará el trabajo. Echemos un vistazo a su implementación.
Como vemos es simplemente una clase que nos provee funciones para guardar datos en persistencia, UserDefault::getInstance() es quien realmente hace el trabajo pues nos permite almacenar datos mediante clave - valor igual que un hasmap en la persistencia de forma transparente a la plataforma en la que el juego se ejecuta, ya sea Windows Android IOS ... etc.
Nuestro GameManager además de permitir guardar estos datos, también lleva la cuenta de la puntuación de la partida, aunque no la guarda en persistencia. Hace persistente el volumen especificado por el usuario, el siguiente nivel que el usuario puede jugar y la máxima puntuación obtenida por el jugador, este último valor se usará en el modo de juego árcade cuya implementación queda opcional para el lector.
Todos nuestros menús heredan de una clase común pues todos tendrán el mismo fondo con un comportamiento idéntico, heredarán de BaseMenuLayer.cpp y crearemos varios menús: MainMenuLayer, OptionsLayer, SelectMenuLayer mostrados consecutivamente abajo.
Veremos las clases que implementan estos menús: la clase BaseMenuLayer de la cuál heredan todas las demás, la clase MainMenuLayer, la clase SelectMenuLayer que hereda de MainMenuLayer y por último la clase OptionsLayer.
Nada que explicar realmente acerca de esta clase más que usa una clase Background, en su init() llamamos al scheduler para lanzar el update. Como ya lo hacemos en la clase padre que es esta, es muy importante no volver a hacerlo en la clase hija, lo que si podemos hacer es un override del método update, sin embargo no nos interesa ya que este update tan solo moverá el fondo del menú, a continuación veremos por qué no necesitamos hacer override del update
MainMenuLayer hereda de la clase anterior y añade a la escena una serie de botones, estos botones pertenecen a ui/CocosGUI.h. Para crearlos, se le indica la imagen de su estado normal, la imagen de su estado al pulsar y la imagen a mostrar cuando inhabilitamos el botón. Como vemos las acciones de los botones se indican mediante call backs con lo que no necesitamos sobrescribir el método update de la clase padre.
Prestemos especial atención al botón Start y al vector de punteros a función, initFunctions es un método que nos permite inicializar un vector con una serie de punteros a funciones, esto nos sirve para saber qué nivel debe lanzar el botón Start pues basta con obtener el número del nivel a lanzar del GameManager y cargarlo en el botón a través del vector _functions _functions.at(GameManager::getInstance()->getNextLevel()).
Los niveles que se deben lanzar en función de la elección del GameManager están sin implementar.Por el momento sólo tenemos el nivel 1, el resto los crearemos más adelante.
Este menú muestra en forma de matriz una serie de botones, que nos dicen qué niveles hemos superado y cuál es el siguiente nivel a jugar. Si superamos el nivel 1, se desbloqueara el 2 y así sucesivamente
En el método initButtons se crean los botones, algo muy importante a tener en cuenta es que cualquier valor absoluto que demos para posicionar objetos debe multiplicarse por el factor de escalado en el eje X ó Y según corresponda para que de esta forma siempre se vea igual al cambiar el tamaño de la pantalla. Sabiendo esto, vemos que este método tan solo itera y coloca botones dándoles su posición además de configurarlos, es decir los coloca y según el número de botón, este ha de hacer una cosa u otra, para cargarle la funcionalidad usamos un vector inicializado con las acciones que su clase padre MainMenuLayer provee.
Por defecto todos los botones creados estarán deshabilitados y mostraran la imagen con el candado cerrado, así que tras añadirlos a la escena, iteramos hasta donde GameManager indique y desbloqueamos todos los niveles que el usuario haya desbloqueado jugando. Por último se crea un botón para volver al menú principal.
En todas las clases de menú usamos ui/CocosGUI.h en el último menú se verá como usar Sliders (otro componente como Button).
Comprendamos el funcionamiento del Slider, por ejemplo el elemento _backGroundVolume que es un slider, vemos que tras crearlo y posicionarlo le añadimos un call back _backGroundVolume->addEventListener(CC_CALLBACK_0(OptionsLayer::actionBackGroundVolumeSlider, this)) gracias a esto, el método actionBackGroundVolumeSlider será llamado cada vez que el valor del slider varíe lo que nos permite actualizar en el GameManager el valor establecido por el usuario.
Presta atención al call back del botón de ir hacia atrás. Ahora no solo vuelve al menú principal sino que además llama al GameManager para guardar los valores establecidos por el usuario.