Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
Universidad Politécnica de Madrid Escuela Técnica Superior de Ingenieros Informáticos Doble Grado en Ingeniería Informática y Administración y Dirección de Empresas Trabajo Fin de Doble Grado Desarrollo de un Videojuego Educativo para el Aprendizaje de Mecanografía Autor: Enrique Val Asensio Tutor(a): Antonio Jesús Díaz Honrubia Madrid, Junio 2023 Este Trabajo Fin de Doble Grado se ha depositado en la ETSI Informáticos de la Universidad Politécnica de Madrid para su defensa. Trabajo Fin de Doble Grado Doble Grado en Ingeniería Informática y Administración y Dirección de Em- presas Título: Desarrollo de un Videojuego Educativo para el Aprendizaje de Mecanografía Junio 2023 Autor: Enrique Val Asensio Tutor: Antonio Jesús Díaz Honrubia Lenguajes y Sistemas Informáticos e Ingeniería de Software Escuela Técnica Superior de Ingenieros Informáticos Universidad Politécnica de Madrid Resumen Actualmente, vivimos en una sociedad cada vez más informatizada. La mayoría de puestos de trabajo, así como los estudios de distintos niveles, requiere el uso de sistemas informáticos para su correcto desempeño. El problema radica en que no todas las personas tienen los conocimientos adecuados para el manejo de estos sistemas en materias tan básicas como es la mecanografía. Es por ello que se ha ideado un proyecto de desarrollo de un videojuego cuyo objetivo prin- cipal no es solo entretener a sus usuarios, sino también educarlos en la técnica de la mecanografía. Esto se pretende conseguir de forma orgánica y natural, pues, en vez de simplemente indicarle un texto o una serie de caracteres que de- be introducir sin ningún incentivo, se le ofrece una experiencia lúdica en el que se pone al usuario en situaciones de tensión en las que, inconscientemente, es- cribirá de modo más rápido para sobrevivir a todos los obstáculos y enemigos en la partida que esté jugando. Estos enemigos presentarán retos mecanográficos únicos, divertidos y originales. Para ello, se explicará en detalle las tecnologías que se han empleado para este desarrollo, así como la metodología que se ha decidido seguir. Posteriormente, se explicará la planificación del proyecto, explicando la organización, en cuanto a materias de tiempo y esfuerzo, que se quiere seguir para poder desarrollar las distintas tareas. Estas tareas se corresponderán con las numerosas funcionali- dades que tiene el videojuego, las cuales son explicadas con gran detalle en el apartado de «Desarrollo». Luego, se realizarán ciertas pruebas de usabilidad realizada por usuarios de todas las edades y niveles de mecanografía para comprobar si se cumple con los objetivos principales del proyecto, realizando un análisis exhaustivo de los resultados obtenidos, así como de las opiniones de los usuarios cuestionados. Por último, se valorará el impacto que puede tener este proyecto a distintos niveles, como puede ser el impacto social y económico. Además, se realizarán ciertas conclusiones en contraste con los objetivos inicialmente marcados, así como una conclusión personal y una lista de tareas correspondientes al trabajo futuro. i Abstract Currently, we live in an increasingly computerized society. Most jobs, as well as studies at several levels, require the use of computer systems for a proper performance. The problem is that not everyone has the appropriate knowledge to handle these systems in basic areas such as typing. That’s why a project has been devised to develop a videogame whose main goal is not just to entertain its users, but also to educate them in the technique of typing. This is intended to be achieved organically and naturally. Instead of simply indicating a text or a series of characters that the user must type without any incentive, a fun experience is offered where the user is put in tense situations in which, unconsciously, they will type faster to survive all obstacles and enemies in the game they are playing. These enemies will present unique, entertaining, and original typing challenges. To this end, the technologies used for this development will be explained in detail, as well as the methodology that has been chosen to follow. Subsequently, a project planning will be explained, describing the organization, in terms of time and effort, that is intended to follow in order to develop numerous tasks. These tasks will correspond to several functionalities that the video game has, which are explained in greater detail in the «Development» section. Then, certain usability tests will be carried out by users of all ages and typing levels to check if the main objectives of the project are met, performing a thor- ough analysis of the results obtained, as well as the opinions of the surveyed users. Finally, the impact that this project can have at different levels, such as social and economic impact, will be evaluated. In addition, certain conclu- sions will be made in contrast to the initially set objectives, as well as a personal conclusion and a list of tasks corresponding to future work. iii Tabla de contenidos 1. Introducción 1 1.1. Motivación del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2. Contexto del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.4. Estructura de la memoria . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Tecnologías empleadas 5 2.1. Motor gráfico: Unity . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2. Lenguaje de programación: C# . . . . . . . . . . . . . . . . . . . . . . 6 2.3. Sistema Gestor de Bases de Datos: SQLite . . . . . . . . . . . . . . . 6 2.4. Edición de audio: Audacity . . . . . . . . . . . . . . . . . . . . . . . . 7 2.5. Edición de animaciones: Piskel . . . . . . . . . . . . . . . . . . . . . 8 2.6. Control de versiones: Plastic SCM . . . . . . . . . . . . . . . . . . . . 8 2.7. Gestión de la metodología «Agile»: Jira . . . . . . . . . . . . . . . . . 9 3. Metodología 11 4. Planificación del proyecto 15 5. Desarrollo 17 5.1. Primeras configuraciones y lectura de movimiento del jugador . . . 17 5.1.1. Prefabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 5.1.2. Componentes de un objeto . . . . . . . . . . . . . . . . . . . . 19 5.1.3. Consideraciones relevantes de programación en Unity . . . . 21 5.2. Implementación del movimiento del jugador . . . . . . . . . . . . . . 24 5.3. Implementación de acciones asociadas palabras . . . . . . . . . . . 26 5.3.1. Uso de las Coroutines . . . . . . . . . . . . . . . . . . . . . . . 28 5.4. Aparición de obstáculos de manera aleatoria . . . . . . . . . . . . . 30 5.5. Interfaz del usuario . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 5.5.1. Canvas y elementos de la interfaz . . . . . . . . . . . . . . . . 31 5.5.2. Diccionario y objetos . . . . . . . . . . . . . . . . . . . . . . . . 33 5.5.3. Vidas del jugador . . . . . . . . . . . . . . . . . . . . . . . . . . 34 5.6. Implementación de los objetos . . . . . . . . . . . . . . . . . . . . . . 34 5.7. Implementación de enemigos comunes . . . . . . . . . . . . . . . . . 37 5.7.1. Enemigo Láser . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 5.7.2. Enemigo explosivo . . . . . . . . . . . . . . . . . . . . . . . . . 38 v TABLA DE CONTENIDOS 5.7.3. Enemigo escudero . . . . . . . . . . . . . . . . . . . . . . . . . 39 5.7.4. Enemigo stun . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 5.8. Jefes finales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 5.8.1. Jefe de Agujero Negro . . . . . . . . . . . . . . . . . . . . . . . 45 5.8.2. Jefe Ninja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 5.8.3. Jefe Duelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.8.4. Jefe Final . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.9. Configuración de la Base de Datos . . . . . . . . . . . . . . . . . . . 57 5.10.Implementación de cooldowns . . .. . . . . . . . . . . . . . . . . . . 58 5.11.Spawn de palabras: Cofres . . . . . . . . . . . . . . . . . . . . . . . . 59 5.12.Sistema de control de daño . . . . . . . . . . . . . . . . . . . . . . . . 61 5.13.Spawn Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 5.14.Implementación de elementos de audio . . . . . . . . . . . . . . . . . 65 5.15.Implementación de menús . . . . . . . . . . . . . . . . . . . . . . . . 66 5.15.1.Niveles de dificultad . . . . . . . . . . . . . . . . . . . . . . . . 70 5.16.Implementación del tutorial inicial . . . . . . . . . . . . . . . . . . . 71 6. Evaluación de pruebas de usabilidad 75 7. Análisis de impacto 87 8. Conclusiones y trabajo futuro 89 Bibliografía 91 vi Índice de figuras 2.1. Captura de la pestaña de Plastic SCM dentro del editor de Unity . 9 3.1. Tablero de Jira en el que se muestran las últimas «user stories» . . 12 3.2. Extracto de todos los changesets y ramas creadas en PlasticSCM . 13 4.1. Diagrama de Gantt que contiene la planificación del proyecto . . . 16 5.1. Herramienta Unity Hub . . . . . . . . . . . . . . . . . . . . . . . . . . 18 5.2. Esqueleto de una clase de instanciación de un prefab . . . . . . . . 21 5.3. Código de ejemplo para mostrar el acceso a los componentes de un GameObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.4. Sprite del objeto que proporciona la palabra «laser» al jugador . . . 27 5.5. Esqueleto del código de una Coroutine que espera una determinada cantidad de segundos . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 5.6. Escena del juego en el que aparecen dos asteroides en dos carriles distintos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 5.7. Captura del medidor de velocidad de tecleo medida por palabras por minuto (ppm) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 5.8. Representación en la interfaz de las vidas del jugador . . . . . . . . 34 5.9. Sprite del enemigo láser básico . . . . . . . . . . . . . . . . . . . . . . 37 5.10.Sprites de los distintos modelos de las variantes de enemigo láser . 38 5.11.Sprite que representa al enemigo explosivo . . . . . . . . . . . . . . . 39 5.12.Sprite que representa el prefab de enemigo escudero . . . . . . . . . 40 5.13.Cabecera de la función que encuentra al enemigo más cercano . . . 40 5.14.Captura de pantalla de los distintos tags a escoger en el proyecto . 41 5.15.Captura de pantalla en la que se ve cómo el enemigo escudero pro- tege a un objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 5.16.Sprite que representa el prefab de enemigo stun . . . . . . . . . . . . 43 5.17.Primer frame del sprite animado del Jefe de Agujero Negro . . . . . 45 5.18.Imagen del primer frame del objeto animado del agujero negro . . . 46 5.19.Captura del combate contra el Jefe de Agujero Negro . . . . . . . . . 47 5.20.Primer frame del sprite animado del Jefe Ninja . . . . . . . . . . . . 48 5.21.Captura del combate contra el Jefe Ninja . . . . . . . . . . . . . . . 49 5.22.Primer frame del sprite animado del Jefe Duelo . . . . . . . . . . . . 49 5.23.Captura del combate contra el Jefe Duelo en la que el jugador ha ganado una ronda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.24.Captura de la segunda fase del combate contra el Jefe Duelo . . . . 52 vii Plastic SCM Unity PlasticSCM Unity Hub GameObject ÍNDICE DE FIGURAS 5.25.Sprite del Jefe Final que se corresponde con uno de los frames que representan su animación . . . . . . . . . . . . . . . . . . . . . . . . 53 5.26.Captura del ataque con múltiples láseres del Jefe Final . . . . . . . 53 5.27.Captura del ataque de ráfaga de misiles del Jefe Final . . . . . . . . 54 5.28.Captura del ataque de aturdimiento del Jefe Final . . . . . . . . . . 55 5.29.Captura del escudo del Jefe Final al estar a mitad de vida . . . . . . 55 5.30.Captura de las distintas palabras que un jugador ha recolectado en su diccionario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5.31.Captura en la que aparece un cofre que contiene una de las «pala- bras» que podrá usar el jugador . . . . . . . . . . . . . . . . . . . . . 60 5.32.Captura de la escena en la que el jugador puede ejecutar el coman- do «abrir» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.33.Captura en la que se ha obtenido la palabra «tesla» al abrir el cofre 62 5.34.Captura del menú principal que el jugador verá al abrir el juego . . 67 5.35.Captura del menú con las distintas opciones de configuración . . . 68 5.36.Captura de la pantalla de pausa ejecutada en mitad de la partida . 69 5.37.Captura de la pantalla de derrota por haber perdido todas las vidas 69 5.38.Captura de la pantalla de victoria tras haber derrotado al Jefe Final 70 5.39.Captura de la pantalla que permite seleccionar una de las tres difi- cultades del juego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 5.40.Captura del tutorial inicial del juego en el que se explica el movi- miento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 6.1. Primeras dos preguntas del cuestionario acerca de la información de los usuarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 6.2. Tercera y cuarta pregunta del cuestionario . . . . . . . . . . . . . . 77 6.3. Preguntas del cuestionario relacionadas con la dificultad del juego 78 6.4. Preguntas del cuestionario relacionadas con el tecleo de comandos 79 6.5. Pregunta de respuesta larga sobre el peor elemento de la experiencia 80 6.6. Pregunta de respuesta larga sobre el mejor elemento de la experiencia 81 6.7. Pregunta de respuesta corta sobre el mejor boss del juego . . . . . 82 6.8. Preguntas de valoración numérica relacionadas con los objetivos principales del juego . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 6.9. Gráfico sobre la pregunta acerca de si se ha experimentado algún bug durante la experiencia . . . . . . . . . . . . . . . . . . . . . . . . 84 6.10.Pregunta de respuesta larga sobre la lista de errores que han sufrido 85 viii Capítulo 1 Introducción En este primer capítulo se explicará la motivación del proyecto, qué necesidades satisface, en qué contexto se desarrolla, los objetivos que se persiguen durante su elaboración y, finalmente, la estructura que presentará el resto del proyecto. 1.1. Motivación del proyecto Actualmente es innegable la imperante relevancia de un manejo adecuado y eficiente de las tecnologías de la información y comunicación. Las nuevas ge- neraciones si destacan por algo es por su conocimiento y experiencia nativa de móviles, tabletas y ordenadores. En lo que se refiere a la eficiencia en el uso de las TIC, no solo podemos ha- cer mención del hecho de saber utilizar de forma correcta un navegador web o determinados programas. Entre estas habilidades eficientes también podemos situar un manejo de la mecanografía apropiado, pues escribir, ya sean cortos o extensos textos, con un teclado es de las actividades más básicas y repetidas que hallamos en la informática. Como se analizará en el contexto del proyecto, actualmente no se dispone de una gran variedad de herramientas para el aprendizaje de la mecanografía, pues la mayoría de las opciones que encontramos se basan en aplicaciones web que permiten analizar la velocidad de tecleo. El aprendizaje en estas aplicaciones surge de la voluntad de mejora de la última marca obtenida en lo que se refiere a palabras por minuto. Además, estas herramientas no resultan de por sí entretenidas para el usuario, sino que la persona promedio su aprendizaje se basará en cursos externos de escritura mediante teclado y un posterior análisis de su velocidad usando estas herramientas. Es por ello por lo que se ha decidido diseñar un producto interactivo que resulte entretenido para cualquier persona, independientemente de la edad o experien- cia con el manejo de teclados, y que le permita aprender mecanografía mientras se divierte. 1Capítulo 1. Introducción La manera de hacer este producto innovador es mediante un videojuego para or- denador, en el que toda mecánica dependa de la escritura mediante teclado. De este modo, se consigue atraer a usuarios de todas las edades y con distintos ob- jetivos. Existirá un segmento que quiera aprender (para el cual existirá un nivel de dificultad ajustable que sirva como entrenamiento), pero también tendremos que contar con aquellas personas que busquen simplemente un entretenimiento con el que, además, aprenderán esta habilidad. 1.2. Contexto del proyecto La mecanografía no solo es algo básico en el conocimiento de las TIC, sino que además en algunos países como en Finlandia está ocupando mucha más impor- tancia el aprendizaje de la mecanografía que el de escribir a mano de manera tradicional, incluso llegando a casi reemplazarla [1]. Esto es algo que tiene mu- cho sentido en la sociedad en la que vivimos, pues en la gran mayoría de traba- jos, facultades o incluso escuelas la mayoría de los textos que debemos escribir no lo hacemos a mano, sino mediante el uso de un ordenador. Del mismo modo que los escolares aprenden caligrafía en el colegio mediante el uso de cuadernos dedicados a este tipo de aprendizaje, encontramos algo que se puede asemejar a la mecanografía. La forma que más comúnmente emplean los usuarios para adquirir velocidad en su escritura a máquina son aplicaciones web, las cuales les muestra por pantalla una secuencia de palabras para medir a qué velocidad escribe dicho usuario. La media de un usuario corriente es de 45-60 palabras por minuto, mientras que un profesional puede alcanzar las 150 palabras por minuto [2]. El problema está en que no existe una amplia gama de herramientas para el aprendizaje de la mecanografía y, además, que los programas ya citados previa- mente sirven principalmente para la medición de la velocidad que ya posee el usuario, sirviendo esta propia métrica y el afán por mejorarla como incentivo a conseguir una mejor técnica. Esto implica que los usuarios que sean novatos en la mecanografía o simplemente quieran ejercicios que realmente les enseñen a mejorar, se ven muy limitados en estos ámbitos. Además, esto es una gran oportunidad para poder alcanzar un desarrollo más sostenible a través del apoyo al ODS 4 (educación de calidad) y el ODS 8 (trabajo decente y crecimiento económico). Como se estudiará posteriormente, unos 750 millones de adultos en todo el mundo seguían siendo analfabetos en 2016, sien- do dos tercios de este número mujeres. Aunque la tasa de alfabetización no es igual en todas las regiones, se puede apreciar que todavía queda mucho camino por recorrer para poder obtener unos resultados deseables. 1.3. Objetivos El objetivo general es el desarrollo de un videojuego para el aprendizaje de meca- nografía usando Unity, ofreciendo distintos desafíos que pongan a prueba tanto la velocidad como la precisión del tecleo por parte de los usuarios. 2 Unity 1.4. Estructura de la memoria Para conseguir este objetivo, podemos descomponerlo en diversos objetivos es- pecíficos: 1. Investigación exhaustiva de los distintos métodos de desarrollo de videojue- gos y aprendizaje de las herramientas, motor gráfico y lenguajes a emplear. 2. Definición de las distintas funcionalidades que debería incorporar el video- juego en función a lo que se pretende incluir como mecánicas jugables, así como establecer un sistema de control de versiones. 3. Desarrollo e implementación de las distintas funcionalidades previamente descritas para obtener un videojuego de buena calidad. 4. Implementación de niveles de dificultad adaptativos en función al nivel de mecanografía que puedan tener los distintos usuarios a los que queremos dirigirnos. 5. Elaboración de pruebas unitarias y de integración para comprobar cada funcionalidad desarrollada, así como la puesta en marcha de distintas pruebas de usabilidad con usuarios de todos los niveles de técnica de me- canografía. 6. Evaluación de los resultados de las pruebas de usabilidad para el análisis de apartados a mejorar y para la comprobación del cumplimiento de la premisa de mejora del nivel de mecanografía. 1.4. Estructura de la memoria Los próximos capítulos de la presente memoria seguirán la siguiente estructura: En el capítulo 2, podremos encontrar las distintas secciones que corresponderán con cada una de las tecnologías empleadas en el desarrollo de este videojuego, explicando por qué se han escogido las susodichas en vez de otras tecnologías de características similares. En el capítulo 3 se valorará la metodología que seguirá el desarrollo software. Dentro del capítulo 4 se explorará la planificación de las distintas tareas que se ha elaborado para una correcta organización del tiempo y del esfuerzo para el proyecto expuesto en este documento. El desarrollo del producto software se detallaré en profundidad en el capítulo 5, estructurando este capítulo en función del cometido que tienen los numerosos scripts según su funcionalidad para el juego. Además, se explicarán las cues- tiones que se consideren más relevantes para que el lector pueda comprender los aspectos de Unity más útiles que se han empleado para implementar las funcionalidades que se describan. En el capítulo 6 se analizarán los resultados de las pruebas de usabilidad, dividi- das según el segmento de usuarios en los que podamos seccionar los potenciales clientes según su nivel de mecanografía para poder explorar las tres dificultades 3 Unity Capítulo 1. Introducción con las que cuenta en juego. En la industria de los videojuegos, esto es lo que se denomina la fase de game testing. En el capítulo 7 se evaluará el impacto social y cualitativo que ha tenido el desarrollo de este trabajo. En el capítulo 8 se realizarán ciertas conclusiones en función a los objetivos planteados al comienzo del trabajo y se determinará si se han cumplido los mismos. Finalmente, encontraremos la Bibliografía, que contará con todas las referencias que se citarán en el trabajo y un Anexo. 4 Capítulo 2 Tecnologías empleadas En este capítulo se expondrán las distintas tecnologías empleadas en el desarro- llo de este videojuego, explicando por qué se han escogido estas en vez de otras tecnologías de características similares. 2.1. Motor gráfico: Unity El motor gráfico es la base de cualquier videojuego. Es el encargado de propor- cionar los gráficos, de ensamblar los scripts programados por los desarrolladores y definir sus comportamientos relacionándolos a los distintos objetos del juego, de establecer las reglas para simular la física interna y de generación de luces y sombras. Unity es uno de los motores de uso gratuito más famosos en el sector de desa- rrollos de videojuegos. Las empresas más grandes poseen sus propios motores desarrollados e integrados internamente por expertos en software, lo cual re- quiere unas aportaciones dinerarias de millones de euros. Es por eso que es muy común que las empresas más pequeñas de desarrollo de videojuegos (las llamadas coloquialmente empresas indie) emplean motores gráficos de uso gra- tuito. Unity tiene un competidor muy potente en este mercado, y que suele ser la alternativa para este tipo de empresas a la hora de seleccionar un motor: Unreal Engine. La elección que se ha hecho para este trabajo ha sido basada en el acceso a distintos cursos profesionales de plataformas externas. Previo al comienzo del desarrollo de este trabajo, se han realizado distintos cursos de aprendizaje de Unity y de las tecnologías derivadas para familiarizarse con el entorno gráfico. Además, Unreal Engine suele estar asociado a proyectos de mayor calibre con gráficos de última generación, mientras que Unity es un motor que se suele usar para proyectos más humildes como pueden ser juegos 2D o aplicaciones móviles [3]. 5 Unity Unity Unity Unity Capítulo 2. Tecnologías empleadas 2.2. Lenguaje de programación: C# C# es el lenguaje de programación que emplea Unity para la creación de los scripts que determinaránlos distintos comportamientos que se puedan apreciar en el producto final. La programación de un videojuego en Unity sigue un modelo de programación orientada a objetos, pues crearemos clases que se asociarán a los distintos obje- tos o elementos del juego (por ejemplo, clase Player.cs) y podremos crear estos objetos en el resto de las clases accediendo a sus atributos (siempre que sean visibles para la clase desde la que se llama a estos) de una manera similar a la que se programa en otros lenguajes orientados a objetos, como puede ser Java. Todos estos objetos que crearemos deben derivar de una clase, que incorpo- ran las librerías de Unity, denominada MonoBehaviour. Esta clase incorporará todos los métodos necesarios para poder funcionar en Unity, como puede ser alguno de los más comunes el método Start, que es llamado en el primer frame en el que aparece el objeto con el script atribuido; el método Update, llamado cada frame (por lo que si el juego se reproduce a 60 frames por segundo, será llamado 60 veces cada segundo), o el método OnTriggerEnter2D, el cual nos per- mite realizar comunicaciones entre scripts cuando dos objetos colisionen en la escena del juego [4]. La elección de este lenguaje ha venido determinada por haber seleccionado Unity como motor gráfico del videojuego, ya que, como se ha comentado pre- viamente, es el lenguaje que utiliza por defecto. Si se hubiera escogido Unreal Engine en vez de Unity, se hubiera escogido programar en otros lenguajes. En este caso, el lenguaje sería C++ y Blueprint Visual Scripting[4]. 2.3. Sistema Gestor de Bases de Datos: SQLite Este videojuego emplea también una base de datos embebida que se utiliza para almacenar el progreso del jugador, sus preferencias de configuraciones y tam- bién para almacenar tablas que contendrán palabras y textos que se consultarán para extraer un texto aleatorio para distintas mecánicas del juego. Esta última funcionalidad también se podría haber implementado mediante un archivo simple de texto que contuviera una palabra o un texto por cada línea, y el script que lo tuviera que llamar leyera el archivo y seleccionara una palabra o texto de forma aleatoria. Se ha decidido emplear la implementación basada en la base de datos en busca de mejorar el rendimiento del juego. Se ha escogido el SGBDR SQLite antes que otros sistemas gestores de SQL más populares, como MySQL o MariaDB, por diversas razones [5]: 1. La primera razón es porque sus transacciones no requieren ningún servidor ni configuraciones para poder ejecutarse. 6 C# Unity Unity Player cs Unity Mono Behaviour Unity Unity Unity C++ Blueprint Visual Scripting 2.4. Edición de audio: Audacity 2. Al tratarse realmente de una biblioteca de C de código abierto que imple- menta un SGBD, el tamaño que ocupa es mucho menor que el resto de las opciones. Este aspecto cobra mucha importancia en un videojuego, debido a que son productos software que ocupan normalmente mucho espacio, por lo que una cuestión crítica es la reducción del tamaño y la búsqueda del rendimiento. 3. Atendiendo a esta búsqueda del mayor rendimiento, también podemos be- neficiarnos de las consultas eficientes y rápidas que ofrece SQLite. Además de todas estas razones, existe un plug-in en la tienda comunitaria de Unity (Unity Asset Store) que facilita las conexiones de una base de datos de SQLite llamada «SimpleSQL» [6]. Este plug-in incorpora una clase en la bibliote- ca del juego llamada «SimpleSQLManager», la cual implementa diversos métodos que permiten realizar transacciones de manera sencilla. La conexión con la ba- se de datos queda realmente simplificada también, pues solo tendremos que arrastrar el archivo que contiene la misma en una sección que nos creará este plug-in. 2.4. Edición de audio: Audacity Toda acción, elemento o animación cuenta con una pista de audio única. Ade- más del elemento sonoro más importante: la música. La mayoría de las pistas de audio han sido extraídas de plataformas online que sirven como repositorios gratuitos de sonidos. Algunos de los que se han usado para este proyecto han sido Zapsplat [7], Soundbible [8] o Freesound [9]. Otros sonidos y, principal- mente, la música de fondo ha sido extraída de la ya mencionada Unity Asset Store. La cuestión reside en que muchas de estas pistas de audio deben ser tratadas previamente a su inclusión en el proyecto. Un ejemplo de esto sería la música que sonaría de fondo, pues esta debe tener una introducción que solo sonaría una única vez, pero debe estar seguida de una pista que suene naturalmente como su continuación, pero que sea un bucle, pues no podemos estimar cuánto tiempo va a estar el usuario jugando. Es por ello por lo que una de las mayores labores que se han llevado a cabo en cuanto a edición de audio se refiere ha sido hacer esta división entre introduc- ción y la parte que se repite (también llamada loop), así como la propia creación de un bucle que sonara natural y que el usuario no notara la vuelta al inicio de la pista. Un proceso similar se ha tenido que ejecutar con sonidos de acciones o de elementos, pues algunos debían también ser un sonido cíclico. Para realizar todo este procedimiento de edición de audio se ha usado el pro- grama Audacity, software de uso gratuito que tiene su origen en el año 2000. Este programa permite al usuario la grabación, edición y exportación de audio de gran calidad de forma sencilla. 7 Unity Unity Asset Store Zapsplat Soundbible Freesound Unity Asset Store Audacity Capítulo 2. Tecnologías empleadas Se ha elegido este software frente a otros competidores, como pueden ser, por ejemplo, AdobeAudition o AVSAudioEditor, por su fácil accesibilidad y fami- liaridad debido a que es un programa que suele ser estudiado en materias de la Educación Secuandaria como Tecnologías de la Información y Comunicación. Además, Audacity, como ya se ha comentado antes, es de uso gratuito, mien- tras que los dos programas competidores mencionados son herramientas profe- sionales que exigen una compra de licencia para su uso. 2.5. Edición de animaciones: Piskel Al igual que algunas pistas de audio, muchos sprites han sido obtenidos de la Unity Asset Store, algunos de ellos siendo gratuitos y una gran mayoría con un determinado coste. Por otro lado, la mayoría de las animaciones de distintos elementos que compo- nen el juego han sido animados desde cero. Esto ha supuesto un determinado aprendizaje sobre la creación de imágenes y de animaciones siguiendo el estilo pixel art. Para ello, se ha usado el software gratuito de creación de sprites y animaciones especializado en el estilo que se buscaba (el ya mencionado pixel art) denomi- nado Piskel. Este programa ofrece diversas herramientas, al igual que com- petidores como pueden ser Adobe Photoshop o Aseprite, para la edición de imágenes. La primera diferencia, nuevamente, es el precio, debido a que estos dos compe- tidores requieren la compra de una licencia de uso. Por otro lado, Piskel ofrece una versión muy simplificada de la creación de animaciones mediante una he- rramienta que permite la edición de imágenes por fotogramas. El usuario irá creando sprites, uno por cada fotograma, y en la esquina superior derecha se irá mostrando como quedaría la animación resultante. 2.6. Control de versiones: Plastic SCM El proyecto se ha trabajado en local por ciclos, como se comentará en el apartado 3. Cada vez que se cumplía el objetivo del ciclo, se subía a una plataforma en la nube para mantener los cambios. Esto se asemejaría en gran medida al llamado GitFlow, el cual determina el procedimiento que llevaría el desarrollo software y su gestión de versiones y ramas mediante el uso de Git+GitHub. La mayor diferencia es que en vez de usar este control de versiones tan am- pliamente extendido, se ha decidido usar otro tipo de software. Durante todo el proyecto, se ha usado Plastic SCM. La razón de ello se debe a que es un software muy similar a GitHub, pero es propiedad de Unity, por lo que es algo que se puede encontrar integradoen la propia plataforma del editor de Unity. Esto es, al realizar los cambios que cumplan de manera satisfactoria lo que se buscaba en el ciclo, solo habrá que 8 Adobe Audition AVS Audio Editor Audacity Unity Asset Store Piskel Adobe Photoshop Aseprite Piskel Git+GitHub Plastic SCM GitHub Unity Unity 2.7. Gestión de la metodología «Agile»: Jira darle a un botón, en una pestaña del propio editor llamada «Plastic SCM», que dice lo siguiente: «Checkin changes». Con esta acción, automáticamente se guardará un «changeset» en la rama en la que se esté trabajando, como se puede apreciar en la Figura 2.1. Figura 2.1: Captura de la pestaña de Plastic SCM dentro del editor de Unity Como se ve en la imagen, se seleccionarán los archivos cuyos cambios se deseen subir a la nube. Se comentará esto en mayor profundidad en el apartado 3. 2.7. Gestión de la metodología «Agile»: Jira Al igual que se ha comentado en el apartado 2.6, esta sección se expondrá en profundidad en el capítulo 3. Jira es un software online de gestión de un proyecto «agile». En él se crean las llamadas «user stories», las cuales son divisiones de los ciclos que se han comentado anteriormente. Estas corresponden con los requisitos software de manera atomizada. Además, también permite la generación de un calendario de cumplimiento de estas «user stories» en el llamado «planning». Existen diversos competidores ampliamente usados, como puede ser Rally. Su cometido y funcionalidad es muy similar, pero la ventaja que ha determinado el uso de Jira frente a Rally es que la primera dispone de una aplicación móvil que permite su uso de forma muy accesible en cualquier momento. Aparte de esto, ofrece de manera muy sencilla la organización de las tareas y los equipos encargados de ellas. 9 Plastic SCM Unity Jira Rally Jira Rally Capítulo 3 Metodología Como se ha anticipado en el apartado 2.7, se ha optado por una metodología «Agile» para el desarrollo de este proyecto. Esto se debe a la facilidad de atomizar los requisitos software que debe incorporar el videojuego. Se ha adaptado este tipo de metodología para un equipo con un solo desarrollador. Esto implica que en la gestión de esta metodología no se le ha dado importancia a la distribución de tareas entre miembros del equipo, sino que lo primordial ha sido establecer las correspondientes tareas y asignarles una fecha límite de implementación. El procedimiento que se ha seguido ha sido el siguiente: 1. Determinar nuevas «user stories», categorizarlas (como se explicará más adelante) y asignarles una fecha límite en función a los requisitos software. 2. Creación de nuevas ramas para funcionalidades que pudieran alterar la funcionalidad base de la aplicación. 3. Desarrollo de las nuevas funcionalidades. 4. Elaboración de pruebas exhaustivas. 5. Marcar el desarrollo de las «user stories» en Jira. 6. Cuando se obtiene un resultado satisfactorio, se realizará un «merge» desde la rama creada (si procede) a la rama principal (denominada «main»). Esto implica que la funcionalidad desarrollada es algo definitivo y se traslada a la base del juego. 7. Cada dos semanas, se generaba un ejecutable provisional del juego en for- ma de DEMO para su comprobación de la funcionalidad y satisfacción de los resultados del ciclo. 8. Repetir el proceso de forma recursiva. En la Figura 3.1 se puede apreciar cómo es el «Tablero» que muestra Jira para resumir las «user stories» que quedan por hacer, las que están en curso y las completadas. Debido a que esta última categoría de tareas completadas se vacía cada cierto tiempo, se pueden ver en la imagen solo 2 tareas completadas. 11 Jira Jira Capítulo 3. Metodología El número de cada «user story» es indicativo de la existencia de al menos 68 tareas anteriores. Figura 3.1: Tablero de Jira en el que se muestran las últimas «user stories» Con la generación de nuevas «user stories», procede una correcta categorización para una posterior creación de ramas en Plastic SCM. Distinguimos cuatro tipos distintos de tareas: Feature: Referido a tareas que suponen la implementación de nuevos ele- mentos en el proyecto. Es la categoría más recurrida por su naturaleza a la hora de categorizar nuevas implementaciones. Animation: Con Feature nos referimos a nuevas implementaciones en cuan- to a software se refiere. La gran mayoría de elementos software, en el con- texto del desarrollo de un videojuego, deben contener un componente visual en forma de animación. Es por ello por lo que muchas tareas categorizadas como Feature se corresponden posteriormente con otra tarea independiente categorizada como Animation. Bugfix: Tareas nacidas de las pruebas o «testeos» de nuevas implementa- ciones en los ciclos ya mencionados. Si se encuentra un error o comporta- miento no deseado (más conocido como «bug»), se genera una nueva tarea con esta categoría que queda pendiente de ser arreglada. Config: Referido a las tareas de configuración externa de nuevos elementos o plug-ins. Ejemplo de ello sería la conexión con la base de datos SQLite, o la agregación del corpus (sobre el cual se hablará en profundidad en el capítulo 5. 12 Plastic SCM SQLite En cada rama encontramos los ya mencionados changesets, que son atomiza- ciones de cambios realizados en la rama correspondiente. En la Figura 3.2 se puede observar una pequeña sección de todo el flujo de las ramas usadas en el desarrollo de este proyecto, pues se han producido tantos changesets que es imposible mostrar todas las ramas instanciadas. Figura 3.2: Extracto de todos los changesets y ramas creadas en PlasticSCM En la imagen se pueden ver distintos «puntos», que representan los changesets. Cada punto cuenta con un mensaje escrito por el desarrollador que debe indicar el cambio que se ha realizado en ese momento. También se pueden observar las derivaciones de unas ramas a otras y luego sus convergencias en diversos puntos. Esto se debe a que, por ejemplo, al implementar una funcionalidad resulta nece- sario introducir un mecanismo descrito por otra «user story» antes de terminar la primera. Una vez ya realizadas una serie de pruebas para comprobar su correcto fun- cionamiento, se hará «merge» con la rama padre, es decir, incorporar todos los cambios de forma definitiva en la rama que se estaba trabajando previamente. 13 PlasticSCM Capítulo 4 Planificación del proyecto Primeramente, antes de la elaboración de cualquier producto software, y en es- pecial a los que llevan tanto tiempo de desarrollo y esfuerzo como son los video- juegos, cabe realizar una planificación del proyecto que se va a realizar. Se han definido distintas tareas que comprenderán diversos grupos de funcio- nalidades. Estas son: Implementación de bases mecánicas: Comprende distintos aspectos que servirán como base del juego para el usuario. Incluye las acciones que puede usar el jugador, la interfaz, los obstáculos básicos y los gestores de aparición de los distintos elementos del juego, también llamado Spawn Manager. Implementación de enemigos comunes: Estos son los enemigos que apa- recerán de forma concurrente a lo largo del juego. Cada uno poseerá un comportamiento único y diferente al resto. Son cuatro: el enemigo láser, el explosivo, el escudero y el enemigo stun. Implementación de jefes finales: Son los mayores retos mecanográficos que pondrán a prueba el nivel de tecleo del usuario, tanto en aspectos de su velocidad como en su precisión. Cada uno ofrecerá una experiencia original y diferenciada entre ellos. Estos son cuatro también: el Jefe del Agujero Negro, el Jefe Ninja, el Jefe Duelo y el Jefe Final. Se puede observar en la Figura 4.1 la planificación basada en estas agrupacio- nes de las funcionalidades las distintas tareas principales y más notorias del desarrollo del videojuego. 15 Capítulo 4. Planificación del proyecto Figura 4.1: Diagrama de Gantt que contiene la planificación del proyecto 16 Capítulo 5 Desarrollo Como se ha visto en el apartado 3, se han desarrollado muchas implementacio- nes de diversostipos distribuidas en distintas «user stories». Es por ello por lo que el desarrollo de la aplicación se va a estructurar según las funcionalidades que cumplan estas «user stories». Se escogerán las tareas más relevantes de cada ciclo y se irá explicando su fun- cionamiento para poder obtener al final una visión con la mayor profundidad posible para poder entender los elementos por lo que está compuesto este video- juego educativo. Para mantener la cohesión en la redacción de este documento, se explicarán las tareas por orden de implementación. Pero al incluir una «user story» que pertenezca a un tipo de funcionalidad del producto que se asemeje a otras tareas posteriormente realizadas, se explicarán estas también en el mismo apartado (ignorando en este caso el orden cronológico) en aras de mantener una correcta organización. Debido a que esta es una memoria sobre un trabajo de desarrollo software, se omitirán las «user stories» de categoría Animation. De forma análoga tampoco se incluirán, a no ser que sea necesaria su explicación, las tareas de Bugfix, pues resultan ser de poca relevancia para dar un contexto del funcionamiento del producto final. 5.1. Primeras configuraciones y lectura de movimiento del jugador Los tres primeros cambios («changesets») realizados correspondían a dos tareas iniciales. Una de ellas era la configuración inicial del proyecto. Esto implicaba la creación del proyecto mediante la herramienta llamada Unity Hub, la cual es una aplicación de gestión de todos los proyectos de Unity. En esta herramienta se selecciona el tipo de videojuego que se desea crear (ya sea 2D, 3D, o siguiendo una plantilla por determinado), como se puede apreciar en la Figura 5.1. 17 Unity Hub Unity Capítulo 5. Desarrollo Figura 5.1: Herramienta Unity Hub Una vez creado el proyecto, se importaron los Assets que se estimaron necesa- rios para el comienzo del proyecto. Entre estos Assets se pueden destacar los materiales del background o del fondo. También se incluyeron algunos sprites iniciales, muchos de los cuales sirvieron como placeholders para implementar las funcionalidades correspondientes a ellas para que, cuando el proyecto ya hubiera avanzado lo suficiente, se cambiarán estos placeholders por sprites fi- nales. Además de esto, también se estableció la conexión con el servicio de Plastic SCM. Para ello, se tuvo que crear una cuenta en dicho servicio y enlazarla con el proyecto recién creado. Dentro de Unity, hubo que instalar un plug-in que permitiera las opciones de control de versiones de este servicio. Además de este plug-in, también se instalaron otros que resultaban esencia- les para el desarrollo del videojuego, como puede ser el paquete denominado TextMeshPro, el cual incorpora en un proyecto Unity opciones avanzadas de incorporación y edición avanzada mediante código de textos y otros elementos de UI, como pueden ser botones, dropdowns o sliders. Una vez realizada la configuración inicial del proyecto, se procedió a los primeros scripts. El primero que se creó fue el llamado Player, el cual controla todas las acciones del jugador y se puede considerar la clase principal del videojuego, pues cuenta con la mayor densidad de código de entre todos los scripts. Antes de entrar en mayor profundidad en lo que se incluyó en este primer chan- geset, hay que explicar ciertas funcionalidades sumamente importantes que in- cluye Unity: los «prefabs» y los «componentes». 5.1.1. Prefabs Como ya se ha comentado, el lenguaje de programación que utiliza Unity es C#, y el paradigma de programación que se sigue es la Programación orientada a 18 Unity Hub Plastic SCM Unity TextMeshPro Unity Unity Unity C# 5.1. Primeras configuraciones y lectura de movimiento del jugador objetos (POO). Se creará, por lo general, una clase distinta para cada elemento del juego que se considerará un objeto. Cabe remarcar la diferencia entre objeto de programación (asociado a una clase o script) y un objeto del editor (para el cual no es necesario que le corresponda un script). Un ejemplo con el que esta distinción queda evidenciada sería la cámara principal («Main Camera»), la cual es creada automáticamente con la configuración inicial del proyecto, y mediante ella el jugador podrá observar la escena en curso. Esta cámara es un objeto del editor Unity, la cual no tiene ningún tipo de programación detrás por parte del desarrollador. En el editor de Unity, cuando se quiere implementar un nuevo elemento, se crea un nuevo objeto a partir de un sprite arrastrando este a la escena. A partir de ese momento, este elemento ha sido creado como una especie de objeto que tiene unos determinados atributos o comportamientos que determinemos para ello. El problema es que, con este procedimiento, el objeto ha sido creado como un elemento único (de una sola instancia) que existe en esa escena hasta que se destruya. Por ejemplo, si pensamos en un enemigo común (los cuales serán desarrollados más adelante en esta memoria), al ser creado con su sprite y su comportamiento, al derrotarlo desaparecerá (según hayamos determinado en su respectivo script) y no podremos volver a utilizarlo, pues ya no existe en la escena. Es por ello por lo que Unity incorpora una funcionalidad básica para poder instanciar todas las veces que necesitemos un determinado objeto. Esto es lo que llamamos un prefab[10]. Para crear un prefab, simplemente arrastraremos desde el editor el objeto que hemos creado en la escena a una carpeta del proyecto que debemos crear lla- mada «Prefabs». A partir de ese momento, el motor gráfico reconocerá el objeto de manera distinta. A partir de ese momento, cuando traigamos un prefab a escena, podremos hacer cambios en este y Unity nos preguntará si queremos aplicar estos cambios a todas las instancias posteriores (lo que se denomina «Override»). 5.1.2. Componentes de un objeto Una vez tenemos un objeto (ya fuera de tipo prefab o no) en la escena, pode- mos determinar los comportamientos o propiedades que puede tener añadiendo los ya mencionados componentes. Existe una cantidad abrumadora de compo- nentes en el motor de Unity[11]. Algunos ejemplos de ellos para ilustrar esta funcionalidad básica son: Transform: Es la propiedad más básica que puede tener un objeto. Incluso cuando creamos un objeto vacío (Empty Object), siempre se le asigna este componente por defecto. Indica la posición en los ejes X, Y, Z (siempre en este orden). Además, también indica la rotación que presenta el objeto. Sprite Renderer: Permite poder visualizar el sprite que se le haya asociado, así como cambiar determinadas configuraciones. Ejemplos de estas son el 19 Unity Unity Unity Unity Unity Capítulo 5. Desarrollo color, la transparencia (denominada «alfa»), el material... Cuando se crea un objeto directamente a partir de un sprite, como se ha descrito antes, este componente se configura automáticamente. Script: Cuando se ha programado el comportamiento que se quiera para un determinado objeto, por ejemplo, el jugador, se le deberá asignar un componente «Script» para que pueda ejecutar lo que se ha puesto por códi- go. RigidBody: Es el componente básico con el que el motor gráfico ejecuta las físicas que incorpora. Es necesario agregarlo a cada elemento que que- ramos que tenga cualquier comportamiento físico básico. Se referenciará muchas veces para poder ejecutar acciones elementales mediante código, como el movimiento del jugador o de los enemigos. Tiene propiedades físi- cas como la masa, el multiplicador de gravedad, la aceleración... Collider: Permite una de las formas más básicas y usadas de comunica- ción entre distintos scripts. Por ejemplo, cuando un asteroide (el cual se explicará más adelante), el cual se mueve en línea recta hacia abajo, im- pacte con el jugador, gracias al componente Collider podemos coordinar los dos objetos implicados en la colisión (como puede ser dañar al jugador o destruir el asteroide). AudioSource: Permite que un objeto sea una fuente de audio. A través de él, se podrá hacer que suenenelementos de la clase AudioClip incorpora- dos por MonoBehavour. Este AudioSource puede ser escuchado por otros objetos que contengan el componente AudioListener, el cual suele estar incluido en la ya citada Main Camera. Animator: Como se comentó en el apartado 3, la gran mayoría de objetos o elementos en Unity suelen ir acompañados por una animación corres- pondiente para darle un cierto nivel de calidad al producto. Todas las «user stories» de este proyecto han derivado en un tipo de archivo denominado «animaciones» (*.anim). Estos archivos se han guardado en una carpeta del proyecto llamada «Animations». Todas estas animaciones han sido asigna- das a un objeto mediante el uso de este componente. Al crear una nueva animación, se generan dos tipos de archivos: 1. Animation: Contiene los fotogramas que componen la animación. Acce- diendo a ello, se puede cambiar la propia animación modificando cada fotograma, cambiar la velocidad de reproducción o estableciendo si es una animación en bucle o no. 2. Animator Controller: Controla el flujo de estados en una animación, como si se tratara de un autómata de estados finitos. Se pueden esta- blecer reglas para tratar mediante código el cambio entre «Animations». Por ejemplo, si se quiere añadir una animación en bucle que indique al jugador que está dañado, habrá que tener una animación para cuando está en estado default (también llamado idle) y, mediante el uso de una 20 Collider AudioClip MonoBehavour AudioSource AudioListener Unity 5.1. Primeras configuraciones y lectura de movimiento del jugador using Unity.Engine; public class EjemploInstantiate: MonoBehavour { [SerializeField] private GameObject _player; ... public void InstantiatePlayer(){ Instantiate(_player, new Vector3(0,0,0), Quaternion.identity); } void Start(){ InstantiatePlayer(); } void Update(){ InstantiatePlayer(); } } Figura 5.2: Esqueleto de una clase de instanciación de un prefab variable booleana, cambiar a la animación nueva cambiando el valor a true. LineRenderer: Otro componente que se ha usado en varias ocasiones en este proyecto ha sido el llamado LineRenderer. Este es capaz de crear una línea recta mediante código que una dos puntos que se indiquen en el script correspondiente. Ejemplo claro de ello es el comportamiento del enemigo stun, del cual se hablará en el apartado 5.7.4, pues este lanzará al jugador un «gancho» que, en caso de colisionar con el jugador, le obligará a escribir una determinada palabra extraída de una base de datos. 5.1.3. Consideraciones relevantes de programación en Unity Estos prefabs se pueden instanciar mediante código usando una función que incorpora MonoBehavour: Instantiate. A continuación se muestra un ejemplo simplificado de programación de una clase que llama a un prefab del jugador. Se expondrán ciertas consideraciones muy relevantes para este tipo de progra- mación. Con el código anterior se puede apreciar distintos aspectos de la programación de videojuegos mediante Unity en C#: Toda clase debe incorporar la librería Unity.Engine para poder imple- mentar la clase padre MonoBehavour. Si se crea el script dentro del propio editor, esta librería y la correspondiente herencia de la clase padre se in- corporarán de forma automática. 21 true LineRenderer MonoBehavour Instantiate Unity C# Unity.Engine MonoBehavour Capítulo 5. Desarrollo Siguiendo el paradigma de POO, la clase EjemploInstantiate tiene un atributo denominado «_player», el cual es de tipo GameObject. Esta es una clase objeto básica de MonoBehavour. Hace referencia a cualquier tipo de objeto en Unity de forma genérica. Por ejemplo, al declarar el atributo como este tipo de dato, se puede acceder a los métodos de la clase, como puede ser SetActive(boolean), el cual permite activar o desactivar el objeto mediante código. Es importante recalcar que, sabiendo que _player contendrá un objeto pre- fab que representará al Player (con su script homónimo correspondiente), no podemos acceder a los métodos públicos de este citado script, pues per- tenecen al tipo de dato Player, y no GameObject. Para poder acceder al script de Player, se deberá hacer lo siguiente: Player player = _player.GetComponent<Player>(); Se seguirá de forma análoga este procedimiento para cualquier tipo de com- ponente de un objeto. Por ejemplo, para obtener el componente LineRender de un enemigo stun, se ejecutará lo que se puede ver en la Figura 5.1.3. [SerializeField] private GameObject _stunEnemy; ... LineRenderer lineRenderer= _stunEnemy.GetComponent<LineRenderer>(); Figura 5.3: Código de ejemplo para mostrar el acceso a los componentes de un GameObject Una convención que se ha decidido adoptar en el desarrollo de todo el código de este proyecto es que las variables que sean declaradas como private deberán empezar por el carácter «_». De este modo se podrá saber con facilidad su estado de visibilidad con respecto a otras clases mientras se está desarrollando el software. Es por esto por lo que se han creado variables como _player o _stunEnemy. Una línea que ha aparecido en los códigos de ejemplo hasta ahora y no se ha explicado su funcionalidad es [SerializeField]. Bien es sabido el uso de las declaraciones public/private de los atributos de una clase en POO. Esta declaración de visibilidad de los atributos tiene algunas implicaciones más en la programación orientada a Unity. En el Inspector del editor es donde podemos observar y editar todas los propiedades y componentes de un determinado objeto. En el componente de «Script» aparecerán los atributos públicos, pero no los privados. Que un atributo aparezca en el editor nos permite asignarle un valor mediante el editor (sin uso del código), simplemente arrastrando el elemento que queramos o escribiendo su valor en caso de ser un tipo básico de dato. 22 POO EjemploInstantiate GameObject MonoBehavour Unity SetActive(boolean) Player Player GameObject Player Player player _player.GetComponent<Player>(); LineRender GameObject [SerializeField] public/private Unity 5.1. Primeras configuraciones y lectura de movimiento del jugador Pero existen ocasiones en las que queremos asignar un determinado ele- mento al valor de un atributo que necesitamos que sea privado mediante el editor debido a que no podemos acceder al susodicho por código. Es pa- ra esto mismo para lo que sirve la declaración [SerializeField] antes de un atributo de clase. El dato seguirá siendo privado para el resto de scripts, pero podremos verlo en el editor para su monitorización o asignación de un valor. Para el ejemplo en el que declarábamos el GameObject de un atributo lla- mado _player, simplemente tendríamos que arrastrar el prefab correspon- diente a Player hasta el campo que se muestra en el componente script. La función Instantiate recibe tres parámetros: 1. El GameObject a instanciar. Normalmente se trata de un prefab. 2. La posición en la que aparecerá el objeto. Este parámetro suele ser con un nueva posición (expresada como un nuevo objeto de tipo Vector3 (int x, int y, int z) o un elemento transform. Este último es un atributo público de todo objeto GameObject, y hace referencia a su componente «Transform». Este elemento es una clase en sí, y tiene como uno de sus atributos otra clase denominada «Position», la que devuelve la posición (que sería un tipo de dato Vector3) en la escena del GameObject al que está aso- ciado. Es por ello por lo que en este segundo parámetro podríamos es- cribir object.transform.position en vez de crear otro Vector3 nue- vo. 3. El último parámetro que recibe la función es la rotación del objeto. Si queremos que no rote, entonces pondremos la rotación por defec- to (Quaternion.identity). Si quisiéramos una determinada rotación (por ejemplo, que un láser que dispare el enemigo rote 90 grados, de- bido a que el sprite asociado esté en horizontal cuando queremos que este se desplace hacia abajo), escribiríamos Quaternion.Euler(0,0, 90). Lo que hará esta función será crear un clon del prefab que se le pasó como primer objeto en laposición y con la rotación indicada. Start y Update son dos funciones que se implementan de forma automáti- ca (solo las cabeceras de las funciones, sin nada en el cuerpo) al crear una clase que derive de MonoBehavour. Es por ello por lo que resulta relevante una breve descripción de cada una. Start es la función que se ejecuta en el primer frame en el que aparece el objeto que contenga el script. Normalmente usado para inicializar variables o para determinar comportamientos por defecto en un inicio. Por ejemplo, si quieremos que el jugador aparezca en la posición (0,-4,0), en Start deberemos escribir transform.position= new Vector3(0,-4,0). 23 [SerializeField] GameObject _player Player Instantiate GameObject Vector3 (int x, int y, int z) GameObject Vector3 GameObject object transform position Vector3 Quaternion identity Quaternion Euler (0,0,90) (0,0,90) Start Update MonoBehavour Start (0,-4,0) Start transform.position= new Vector3(0,-4,0) Capítulo 5. Desarrollo Update es una función de absoluta importancia en este tipo de progra- mación. Determina el comportamiento que debe tener un objeto de forma continua, ya que se ejecuta cada frame. Esto es, si un juego está ejecután- dose a 60 fps, implicará que la función Update será llamada 60 veces cada segundo. Esta función obliga a cambiar en cierto modo la forma clásica de pensar para incorporar algoritmos a como estamos acostumbrados en otros len- guajes de programación como Java o C. Por ejemplo, el código anterior sería catastrófico para nuestro juego, pues lo que haría sería que instan- ciaría una copia del prefab del jugador, no solo en el primer frame (por el método Start), sino porque crearía 60 copias cada segundo. 5.2. Implementación del movimiento del jugador Una vez explicados los conceptos necesarios en los anteriores apartados, pode- mos entrar en mayor profundidad en lo desarrollado acerca de la primera «user story» de tipo Feature: el movimiento del jugador. Cabe remarcar que, al ser un juego educativo que pretende enseñar mecanogra- fía, el movimiento del usuario no es uno que sea libre y mediante cuatro teclas, como suele ser el caso en la amplia mayoría de videojuegos. En esta ocasión, el usuario debe moverse escribiendo la dirección en la que se quiere desplazar. Por ejemplo, el jugador siempre empieza el juego en la posición 0,-4,0. Por lo que, si se quiere desplazar hacia la izquierda, deberá escribir por teclado la palabra izquierda y presionar la tecla «Enter». Si lo ha escrito correctamente, la nave que representa al jugador debe desplazarse a la izquierda hasta llegar a la posición (-5,-4,0. Si intenta volver a escribir «izquierda», sonará un indicador de error, pues entonces se saldría de la pantalla. Esto se debe a que la pantalla se puede decir que se estructura en tres carriles: Carril izquierdo: Posición (-5,y,0) Carril central: Posición (0,y,0) Carril derecho: Posición (5,y,0) El código de este nuevo comportamiento del jugador se compone de diversas partes que se incluyen en la clase Player.cs. Lo que se desarrolló en esta pri- mera implementación se ha mantenido hasta el producto final. Se compone de diversas partes que se incluyen en la clase Player.cs: 1. Por un lado, se ha decidido poner como atributo de clase una lista que contiene diversos datos de tipo «string». Cada dato de esta lista se refiere a una acción ejecutable por el usuario. Es por ello por lo que esta lista se denomina diccionario. Lo primero que ha sido incorporado en el diccionario para esta primera implementación del movimiento han sido las siguientes palabras: 24 Update Update Java C Start 0,-4,0 izquierda (-5,-4,0 (-5,y,0) (0,y,0) (5,y,0) Player.cs Player.cs 5.2. Implementación del movimiento del jugador Izquierda Derecha Arriba Abajo 2. Otro atributo que se ha incluido es el llamado «action», el cual es un «string» que va recopilando lo escrito por el usuario. Para ello, se hace uso de Input.inputString dentro del método Update de la clase Player. Esto es algo que incorpora MonoBehavour, y permite guardar en un «string» la tecla que haya presionado el usuario. Sabiendo esto, lo que se ha hecho es que cada frame se analiza si ha escri- to algo el usuario (Input.inputString!=""), y, en caso afirmativo, se le suma a lo que ya tenía almacenada la variable «action». Es entonces cuando se espera que el usuario presiona la tecla «Enter» pa- ra ejecutar la acción escrita. De esto último es de lo que se encarga una función fundamental en el código de Player: ReadAction. Esta función, debido a su importancia desde estos primeros changesets hasta los últimos creados, merece una descripción en más detalle de su funcionamiento: Lo primero que se procesa es una transformación del campo action para ponerlo en letras minúsculas (para que dé igual cómo escriba el usuario) y se quitan los espacios en blanco innecesarios (usando la función Trim(). Posteriormente a esta transformación, se compara con todos los ele- mentos del diccionario del usuario mediante un bucle exhaustivo. Si encuentra una entrada del diccionario que se corresponda con la acción, entonces se procesa mediante un switch y se determina cuál es el comando a ejecutar. Aquí es donde encontramos las redirecciones correspondientes a todos los métodos de la clase Player que contienen los distintos comportamientos o acciones del jugador. Si no encuentra la acción escrita por el usuario en el listado dicciona- rio, entonces comprobará si se encuentra en otro atributo denominado objetos, también de tipo List<string>. Esto se explicará en profun- didad en el apartado 5.6. En caso de no cumplirse ninguna de las anteriores condiciones, enton- ces simplemente se reproducirá, haciendo uso de la referencia corres- pondiente al componente AudioSource de Player, un sonido de error para notificar al usuario de su fallo al escribir. 3. Una vez se reconozca mediante la función recién descrita una dirección en la que el jugador se desee mover, se realizará un mismo procedimien- to para cualquier dirección (solo cambiarán los valores numéricos de las posiciones). 25 Input.inputString Update Player MonoBehavour Input.inputString!="" Player ReadAction Trim() switch Player List<string> AudioSource Player Capítulo 5. Desarrollo Este procedimiento consiste en, primeramente, comprobar si se puede eje- cutar la acción en función de la posición del jugador, pues no podemos permitir el movimiento si este supondría la salida de la escena. Es por ello por lo que se comprueba que el eje X o Y no exceda un número en concreto. En caso de que se permita ejecutar la acción, entonces simplemente se procederá a dar un valor adecuado a otro atributo de Player, denominado «target». Este parámetro es de tipo Vector3, y es usado en el método Update en una función MoveTowards. Esta función recibe por parámetro un vector al que desplazarse a una determinada velocidad. La velocidad que hay que usar en la función es determinada por otro atri- buto de la clase: _speed. Sabemos, gracias a su nomenclatura, que es de tipo private. Es importante la mención de este parámetro, pues será men- cionado en otras funcionalidades de la clase Player, pero también será un campo que todo objeto susceptible a un movimiento deberá poseer. 5.3. Implementación de acciones asociadas palabras El siguiente requisito software que se implementó tras desarrollar el movimiento del jugador y, consecuentemente, el reconocimiento de comandos escritos por el usuario, fue la implementación de la primera palabra o acción: láser. Para ello, se creó un nuevo objeto de tipo prefab con un nuevo script correspon- diente. Lo único que se programó en un primer momento en esta clase Laser recién creada fue un movimiento vertical a una determinada velocidad (paráme- tro _speed). Como este comportamiento se quiere incluir desde el primer frame en el que se instancie un clon del láser, se incorporó este código en el método Start. Posteriormente, se le añadió un componente Collider al nuevo prefab para que se pueda detectar cuando impactecontra los futuros enemigos u obstáculos. Finalmente, para terminar la implementación de esta funcionalidad, solo queda- ba reconocer la palabra cuando la escribiera el usuario. Es por ello que se agregó un nuevo caso en el ya mencionado switch de ReadAction. Este ejecutaba una nueva función Laser(), la cual simplemente instanciaba una copia de un nuevo atributo de tipo GameObject llamado «_laserPrefab». Pero para reconocer esta palabra, como se ha visto en el apartado 5.2, debe estar incluida la palabra «laser» en el diccionario. Para hacer esto, se creó otro objeto prefab llamado «Laser_palabra». Este objeto presenta una animación que será similar para el resto de palabras. El primer frame de esta animación se ve representado por la Figura 5.4. Este nuevo elemento tenía un sprite y animación correspondiente, ambos crea- dos correspondiéndose a unas determinadas «user stories» de tipo Animation. Se han eliminado los acentos de las palabras de acción por motivos de la fuen- te que se usa para representar estas palabras, por lo que en este documento las palabras que se mencionen no se les incluirá acento para remarcar que se 26 Player Vector3 MoveTowards Player Laser Start Collider switch ReadAction Laser() GameObject Animation 5.3. Implementación de acciones asociadas palabras Figura 5.4: Sprite del objeto que proporciona la palabra «laser» al jugador trata de un comando, como por ejemplo «laser» o «cañon». Las tildes se pueden practicar en otros apartados, como las palabras de aturdimiento (ver apartado 5.7.4). También contaba con un componente Collider y con un nuevo script: Palabra. En este se tiene un atributo de clase llamado «wordID», el cual se le da valor mediante el editor. Luego, se analiza mediante un switch(wordID) cuál es el elemento que ha recolectado (colisionando con él) el jugador. Dependiendo del elemento del que se tratara, se añade un string u otro en el diccionario del jugador. Tras cierto tiempo y debido a razones de diseño, se decidió finalmente incor- porar la palabra «laser» en el diccionario inicial del jugador, por lo que ya no serviría en principio el objeto «Laser_palabra» para su uso. Sin embargo, sí ser- viría como modelo de diseño para el resto de palabras que posteriormente se implementarían: Misil: Un proyectil con mayor daño y tamaño, lo que implica un mayor área (llamada comúnmente hitbox) de activación otrigger del Collider. Produce también al impactar un tipo de prefab denominado «explosion_misil», el cual también tiene un Collider para poder impactar a enemigos cercanos. Cañón: Un ataque que atraviesa toda el eje vertical y atraviesa dañando todo lo que esté por en su rango. Tesla: Una acción no dirigida al daño, sino a la estrategia, pues, duran- te sus cinco segundos de duración, todo lo que entre en contacto con su Collider será paralizado. Pulso: Una secuencia de tres proyectiles de gran velocidad, pero poco daño. Escudo: Activa un objeto hijo de Player, mediante el uso de la ya men- cionada función SetActive de la clase GameObject, que sirve como pro- tección del daño contra el jugador. Esto es algo que se desarrollará en el apartado 5.12. 27 Collider Palabra switch(wordID) Collider Collider Collider Player SetActive GameObject Capítulo 5. Desarrollo Curación: Simplemente sirve para curar al jugador. Al igual que el ante- rior elemento Escudo, también se explicará en mayor profundidad en el apartado 5.12. Varias de estas palabras se agruparon en una categoría internamente tratada de manera similar. Son los llamados Proyectiles, y son las palabras Laser, Misil y Pulso . Se ha creado una nueva clase llamada Proyectil de la que, median- te herencia de clases, derivan las otras respectivas clases. El motivo de esta agrupación será desarrollado en el apartado 5.6 Algunos de estas acciones a las que llama son simples usos de la función Instantiate, como es el caso de Laser() o Missile(). Sin embargo, otras acciones hacen uso de una funcionalidad clave en el desarrollo de videojuegos mediante Unity que necesita ser desarrollada, pues es utilizada en la gran mayoría de clases del proyecto. Se trata de las «Coroutines». 5.3.1. Uso de las Coroutines Las Coroutines o corrutinas son una funcionalidad clave para la programación de distintas funcionalidades en Unity. Permiten ejecutar en segundo plano las acciones que se le indiquen. Ofrecen características de concurrencia que pueden ayudar a mejorar conside- rablemente el flujo de ejecución del código. Sin embargo, como suele ocurrir con accesos concurrentes a determinados datos compartidos, se debe proceder con cuidado al usar estas funcionalidades. Además, hay que tener también en cuenta que en este tipo de programación tan singular los objetos asociados a los distintos scripts pueden desaparecer en cual- quier momento mediante el uso de la función Destroy de la clase GameObject. Esto quiere decir que, si tenemos por ejemplo un enemigo_laser (explicado en el apartado 5.7.1) y este llama a una corrutina, puede ocurrir que el jugador ataque al enemigo y este se vea obligado a destruirse. Esto provocará que la corrutina llamada por la clase Enemigo_laser se vea abortada de forma repentina. Una característica también que resulta relevante en la materia de las corrutinas es que no son funciones void, sino que deben retornar siempre un tipo de dato IEnumerator. Esto implica que la función debe contener una línea de yield return. Los datos IEnumerator que se devuelven en las corrutinas están rela- cionados con distintos tipos de funciones que obligan al programa a esperar en el background. La que más se ha usado en el desarrollo de este proyecto es la función WaitFor- Seconds(float seconds), que, como indica su nombre, espera una determinada cantidad de segundos que se le pasen por parámetro, y será entonces cuando continúe el flujo del código del resto de la corrutina. En la Figura 5.3.1 se puede apreciar cómo es el esqueleto más usual de una corrutina y su funcionamiento. 28 Proyectil Instantiate Unity Unity Destroy GameObject Enemigo_laser void IEnumerator yield return IEnumerator 5.3. Implementación de acciones asociadas palabras using Unity.Engine; public class EjemploCoroutine: MonoBehavour { public int test; void Start(){ test = 0; StartCoroutine(Test()); } void Update(){ Debug.Log(test); } IEnumerator Test(){ test = 1; yield return new WaitForSeconds(5.5f); test = 2; } } Figura 5.5: Esqueleto del código de una Coroutine que espera una determinada cantidad de segundos Lo que se muestra en esta clase EjemploCoroutine tiene el siguiente funciona- miento: Se ha declarado un atributo test que va a ser mostrado por pantalla 60 veces por segundo al estar en el método Update. Al instanciarse el objeto que contenga este script, es decir, cuando se llame al método Start, se le dará un valor inicial a test de 0. Además, se llamará a la corrutina declarada en la misma clase denominada Test. Al igual que la llamada a toda corrutina se realiza con el método Start- Coroutine, se puede suspender en cualquier momento su funcionamiento con StopCoroutine, o incluso detener todas las corrutinas de la clase con StopAllCoroutines. Lo que hace esta corrutina es asignar el valor de test a 1. Entonces, tras 5.5 segundos de espera, cambiará el valor de este campo a 2. Sabiendo estos datos, podemos conocer el resultado de lo que se imprime por pantalla gracias al uso de Debug.Log. Podemos suponer que se im- primará 60x5.5=330 veces el número 1 y después, una vez transcurridos cinco segundos y medio, solo se mostrará el número 2. 29 EjemploCoroutine Update Start test 0 Test test 1 5.5 2 Debug.Log 60x5.5=330 2 Capítulo 5. Desarrollo 5.4. Aparición de obstáculos de manera aleatoria El objetivo que se planteó con el diseño del videojuego desde su concepción fue crear una herramienta de aprendizaje de la mecanografía de una manera poco convencional a lo que podemos encontrar hoy en día. La idea de mejora de esta técnica vendría de poner al usuario en situaciones de tensión en el que se veaobligado a escribir cada vez más rápido debido a un incremento constante de la dificultad. Esta dificultad se refiere realmente a la aparición de distintos enemigos y obs- táculos. Los enemigos serán tratados más adelante en el apartado 5.7. Sin em- bargo, una vez implementados los controles básicos del jugador, llegó el mo- mento de desarrollar situaciones que obligaran al usuario a moverse, es decir, a tener que escribir las palabras correspondientes al movimiento o a diversos ataques para poder sobrevivir. Estas situaciones serían primeramente creadas gracias a los obstáculos ya men- cionados. Estos obstáculos son asteroides que irán apareciendo cada determi- nado tiempo (como se tratará en el apartado 5.13). Como se quiere conseguir forzar al usuario a realizar movimientos de forma continua, se decidió generar estos prefabs de los asteroides por pares. Se generó una corrutina que, cada determinado tiempo, generara de forma aleatoria un asteroide que ocupara uno de los tres carriles de la pantalla. Una vez sabido cuál es este carril ya ocupado, se crea seguidamente un segundo prefab del asteroide en otro carril distinto de forma aleatoria. En la imagen que se muestra en la Figura 5.6 se puede apreciar cómo sería una situación real de la escena cuando aparecen dos asteroides de forma aleatoria. En este caso en el carril izquierdo y central, por lo que el jugador debería escribir «derecha» para poder esquivar estos obstáculos. Figura 5.6: Escena del juego en el que aparecen dos asteroides en dos carriles distintos 30 5.5. Interfaz del usuario 5.5. Interfaz del usuario Lo siguiente que se realizó fue un primer boceto de lo que más tarde sería la interfaz final del usuario o UI (User Interface). Es por ello por lo que, en aras de la claridad, se va a proceder a desarrollar todos los elementos gráficos que forman esta interfaz. Antes de presentar cualquier elemento de UI, se necesita explicar el concepto de Canvas. 5.5.1. Canvas y elementos de la interfaz Unity incorpora diversas herramientas de interfaz. Entre estas podemos encon- trar: Texto: Nos permitirá escribir lo que deseemos en la pantalla, ya sea desde el editor o desde código. Es algo que se utilizará en gran medida a lo largo de este proyecto. Panel: Definirá un elemento gráfico rectangular normalmente usado como fondo (y como elemento padre) de otros elementos de UI, como puede ser el texto. Por decisión de diseño, en este videojuego se ha decidido usar un panel en la gran mayoría de casos en los que se ha incorporado un elemento de texto. Image: Permite la incorporación de sprites como parte de la UI. Se puede acceder a un componente homónimo mediante código para poder tener un elemento visual que vaya cambiando en función a un determinado com- portamiento. Botón: Son herramientas ya configuradas por Unity para poder hacer click sobre ellas. El desarrollador deberá especificar los comportamientos deriva- dos de accionar estos botones. Para ello, se deberá referenciar un elemento cualquiera y usar una función de sus respectivas clases. Por ejemplo, estos botones son utilizados en el menú principal para ofrecer diferentes opciones al usuario. Si queremos generar un botón .Opcionesçon el que se despliegue un menú de configuración, debemos entonces referen- ciar el panel que contenga estas opciones y llamar a su función SetActive (true) para que se muestre, a la vez que el panel de Main Menu se debe ocultar usando SetActive (false) para evitar el despliegue de dos menús de forma simultánea. Slider: Son una herramienta también desplegada por Unity que permite, desde su creación, poder arrastrar una barra lateral. Tienen un funciona- miento similar a la barras de desplazamiento verticales y horizontales de las páginas web para poder navegar a través de ellas. Este elemento de UI ha sido empleado en el proyecto para definir una op- ción de ajuste del volumen general del juego. 31 UI Unity Unity SetActive (true) SetActive (false) Unity Capítulo 5. Desarrollo Cabe recalcar que Unity adquirió en 2017 un paquete creado por la comunidad (antes solo disponible en la Unity Asset Store) de elementos UI denominado TextMeshPro, el cual es realmente una mejora directa de estos elementos UI, pues presentan una mejora visual, son más fáciles de configurar y de acceder por código. Es por ello por lo que en este proyecto se han usado elementos UI derivados de este paquete. Expuestos los elementos que suelen componer cualquier interfaz, debemos co- nocer el concepto de Canvas. Este es un GameObject generado automáticamente cuando queremos incorporar nuestro primer elemento de UI, pues es obligatorio que todo elemento de interfaz sea hijo de este objeto. Este GameObject tiene un componente también llamado Canvas que permite la impresión o pintado de los distintos elementos descritos por pantalla. Se debe establecer un orden de pintado [12], el cual es determinado por el orden jerárquico que sea establecido en el editor. También se mostrarán tres modo de renderizado de los elementos de UI: Espacio de la pantalla - Superposición (Overlay): Establece los elementos de UI de forma superpuesta encima de la propia pantalla. Lo más impor- tante que se debe remarcar de este modo de renderización es que, en caso de cambiarse el tamaño de la pantalla, también se modificará el tamaño del Canvas. Espacio de la Pantalla - Cámara: Funciona de manera similar al anterior pero, en vez de que su funcionamiento dependa de la propia pantalla, se establecerá una dependencia con la cámara que se esté usando. World Space: Este modo de renderización hace que los elementos hijos pertenezcan al propio mundo, es decir, a la escena. Esto es útil si se de- sea incorporar la UI en 3D como parte del juego más que como elementos gráficos 2D. Conocido todo el entorno de User Interface que proporciona Unity, podemos describir los elementos de la interfaz con los que cuenta este proyecto. Primeramente se diseñó un elemento que se estimó de necesidad superlativa pa- ra una herramienta de mecanografía: un panel que mostrara el input del usua- rio. Este traducía la ya mencionada variable action (consultar apartado 5.2) en un entorno gráfico, para que el jugador conozca en todo momento lo que está escribiendo. Además, justo debajo existe un elemento de texto que muestra la velocidad de tecleo medida en palabras por minuto (PPM). Esto se le muestra en pantalla con un contador de las palabras que escribe por minuto, como se puede ver en la Figura 5.7. Esta velocidad de tecleo se calcula haciendo la media aritmética de lo que el usuario ha tardado en escribir cada una de las palabras y objetos, es decir, cualquier comando válido, a lo largo de toda la partida. Este es un gran incentivo para que el jugador pueda mejorar su velocidad. 32 Unity Unity Asset Store GameObject GameObject Unity 5.5. Interfaz del usuario Figura 5.7: Captura del medidor de velocidad de tecleo medida por palabras por minuto (ppm) El ya mencionado panel en el que se muestra lo que el jugador va escribiendo es simplemente un panel UI que tiene un hijo de tipo TextMeshPro Text. Este texto se inicializa como vacío y, mediante código, se irá editando en función a lo que contenga la variable action descrita en el apartado 5.2. El script Player se comunicará con otro script denominado UIManager, el cual se encargará de todos los elementos gráficos que se incluyan. Este nuevo script tiene una función ShowInput (stringinput) que modificará el texto del panel. Esta función es llamada en el Update de Player, la cual recibirá por parámetro la variable action. 5.5.2. Diccionario y objetos El diccionario, explicado en el apartado 5.3, sabemos que es una lista de datos de tipo string. Lo mismo ocurre con los objetos, los cuales todavía no se han tratado en esta memoria. Se consideró un requisito software necesario poder ofrecer al usuario qué pa- labras o comandos puede ejecutar de forma visual por pantalla. Para ello, se crearon dos paneles situados abajo en la pantalla, uno a la derecha (diccionario)
Compartir