BK Programación acaba de recibir un inusual encargo: la realización de un videojuego para la promoción de una marca comercial de prendas deportivas.
Ada, socia fundadora de la empresa, es designada como directora técnica del proyecto. De hecho, quiere empezar a trabajar en él cuanto antes para aprovechar la estancia de Ana en BK Programación como alumna en prácticas, ya que posee conocimientos de diseño gráfico y multimedia que serían muy útiles. El equipo de desarrollo será coordinado por Juan, su tutor laboral, y que está encantado de introducirse en el mundo de los videojuegos a pesar de carecer de experiencia previa como programador en dicho campo. Por supuesto, Ada les proporcionará toda la ayuda y formación necesaria para llevar el producto a buen puerto.
Juan no tiene experiencia en la programación de videojuegos, aunque se confiesa un ávido consumidor de juegos de videoconsolas.
La empresa editora que ha realizado el encargo les ha dado libertad creativa, ya que no tienen una idea clara de cuál puede ser el mejor enfoque para promocionar la marca. Por ello, antes de juntar a su equipo, Juan decide ponerse manos a la obra e investigar el origen de los videojuegos para buscar inspiración, estudiando de paso los distintos tipos y géneros que existen y viendo cómo trabaja un equipo de desarrollo.
Todos tenemos una idea intuitiva más o menos clara de lo que es un videojuego. Como puedes deducir, hoy en día un videojuego no deja de ser más que un tipo de aplicación más que puede ejecutarse en un ordenador, dispositivo móvil o consola.
¿Te has parado a pensar qué es lo que diferencia las aplicaciones de videojuegos de otros tipos de aplicaciones? ¿Dónde está la frontera entre una y otra?
Podemos definir un videojuego como un juego electrónico que interactúa con uno o varios jugadores con el fin de que se consigan ciertos objetivos y que muestra visualmente una respuesta a sus acciones.
Un videojuego tiene que informar mediante algún mecanismo al jugador o jugadores del resultado de sus acciones, ya sea visualmente, acústicamente, mediante vibraciones, etc. Normalmente, esa realimentación se realiza mediante la proyección de una imagen de vídeo en una pantalla, de ahí el nombre: videojuegos.
Puede llamarte la atención que no hayamos incluido el requisito de que sea entretenido o divertido. Eso es correcto, aunque es deseable, un videojuego no tiene por qué ser divertido de jugar al igual que ocurre, por ejemplo, al ver una película. Al cine se puede ir a pasar miedo (películas de terror), a ver historias tristes (dramas) o para estar en tensión constante (acción). ¿Quiere decir que esas películas no son buenas? Nada más lejos de la realidad: lo importante es que sea una experiencia agradable, que te deje con ganas de repetir. Lo mismo ocurre con los videojuegos, como veremos más adelante cuando analicemos los géneros.
El desarrollo de un videojuego incluye todo el proceso desde su inicio hasta su lanzamiento. Este proceso incluye muchas disciplinas, donde la programación tiene un papel importante, pero no es la única, ya que también intervienen diseñadores gráficos, diseñadores de interfaces, músicos, escritores, matemáticos etc. Antes de realizar un videojuego hay que hacer un trabajo previo de diseño y creatividad. Hay que definir muy bien el contenido del juego, cómo interactúa el usuario con el juego, cuáles son las reglas y otros aspectos que servirán de guía durante el proceso de desarrollo del juego.
El sector de los videojuegos se encuentra en continua expansión y dedicarse profesionalmente a programar videojuegos precisa de un alto grado de formación, pero por contrapartida tendrás unos conocimientos que te permitirán competir dentro del mercado laboral.
Es difícil poner una fecha exacta al origen de los videojuegos, pero podemos comenzar en 1947. Fue en ese año cuando se registró una patente en Estados Unidos acerca de un dispositivo de entretenimiento que consistía en disparar a aviones en una pantalla de tubo de rayos catódicos (CRT). Thomas T. Goldsmith, Jr. y Estle Ray Mann aparecen como sus autores. Bien pudieron ser los padres del concepto de videojuego.
El Nimrod, construido en 1951, se considera primer ordenador diseñado exclusivamente para jugar al Nim, un juego donde jugador y máquina se alternaban para retirar palitos de unos montones.
Poco después, en 1952, Alexander S. Douglas programó una versión de las tres en raya (Noughts and Crosses) que se ejecutaba en el ordenador EDSAC de la Universidad de Cambridge en 1952. No tuvo mucha repercusión dado que solamente podía ejecutarse en el ordenador de dicha universidad.
William Higinbotham podría considerarse como el creador del videojuego multijugador. Su "tenis para dos" permitía a dos jugadores competir en el mismo juego. Se exhibió públicamente durante unas jornadas de puertas abiertas celebradas en su empresa. Aunque fue disfrutado por cientos de personas, no llegó al público adecuado y por tanto no condicionó la aparición de otros videojuegos.
En 1961, un estudiante del MIT de nombre Stephen Russell desarrolló un videojuego para dos jugadores llamadoSpacewar! que funcionaba en ordenadores PDP-1. Posteriormente el juego fue mejorado por otros compañeros de Stephen, distribuyéndose como software de dominio público a través de la ARPAnet, la antecesora de Internet.
El problema es que los juegos estaban al alcance de unos pocos porque se necesitaban ordenadores muy potentes y caros, ya el ordenador PDP-1 en aquella época costaba 120.000 dólares. Además el juego había que desarrollarlo desde cero, en aquella época no había motores de juego e hicieron falta 200 horas para desarrollar el juego Spacewar!. Además la distribución del videojuego a usuarios que no eran investigadores era un proceso caro porque se distribuían en cintas.
Pero no fue hasta comienzos de los años 70 cuando se extendió el uso de los videojuegos en las casas y en los salones de máquinas recreativas. Los responsables fueron Ralph Baer y Nolan Bushnell, el primero mediante el diseño y la comercialización de la primera consola de videojuegos: la Magnavox Odyssey, y el segundo por la fundación de una de las empresas de videojuegos más influyentes de la historia: Atari. Esta compañía creó innumerables máquinas recreativas y la primera consola que fue un éxito de ventas: la Atari 2600. También aparecieron los primeros cartuchos que permitían la distribución de los juegos para consolas. Su fabricación era cara, pero tenían la ventaja de poder incluir chips y piezas especiales dentro del propio cartucho que ampliaba las capacidades de la consola. Posteriormente cuando la tecnología CD se perfeccionó la mayoría de las empresas, salvo Nintendo que resistió en solitario, optó por este soporte, ya que eran más baratos y tenían una capacidad mayor.
Si tienes curiosidad por saber en qué consistía el juego de Nim, puedes visitar este enlace. Concretamente, la versión que jugaba el Nimrod era el conocido como "juego de Marienbad".
Mucho ha cambiado en el campo desde los tiempos de esos primeros videojuegos. Los equipos tecnológicos actuales son muy potentes (procesadores con varios núcleos), con gran capacidad de almacenamiento y memoria, con tarjetas gráficas GPU que garantizan la máxima calidad del juego. En cuanto al software existen multitud de herramientas que permiten crear videojuegos como Unity, Unreal Engine o Game Maker Studio entre otros eincluso sin conocimientos en programación como es el caso de Scratch y Gdevelop.
Hoy en día, la industria de los videojuegos está centrada en 3 grandes plataformas: los ordenadores personales o PC, las consolas y los dispositivosmóviles. Gracias a Internet los juegos están al alcance de todo el mundo, ya que estas plataformas permiten su descarga. Hace unos años tendríamos que haber mencionado las máquinas recreativas, pero las anteriores plataformas han terminado por dejarlas prácticamente en el olvido. Los PC y las consolas por su potencia, oferta en juegos, la opción de personalizar nuestro jugador y finalmente poder medir tus talentos con otros jugadores en partidas multijugador. Los dispositivos móviles, que cada vez son más potentes, nos ofrecen entretenimiento en cualquier lugar, da igual donde estemos. Además independientemente del sistema operativo, iOs o Android, podemos encontrar en sus tiendas online juegos de cualquier temática totalmente gratuitos.
Programar para una de estas plataformas implica una serie de ventajas y de inconvenientes respecto a las demás. Veamos algunos aspectos interesantes:
Consolas: son dispositivos diseñados exclusivamente para ejecutar videojuegos. Su hardware evoluciona con cada iteración (que en ellas se llama "generación"), lo que suele suceder cada varios años. Generalmente, las capacidades de una consola en el momento del lanzamiento son punteras aunque permanecen constantes durante la vida del producto. Eso implica que con el paso del tiempo se quedarán obsoletas, dando paso a una nueva generación. La gran ventaja desde el punto de vista de la programación de videojuegos es que el hardware no varía durante este tiempo lo que permite concentrar los esfuerzos en una única plataforma. De cara al usuario final, su uso es mucho más simple que el de un ordenador personal. La generación actual de consolas a la fecha de escribir este texto está formada por la Sony PlayStation 4, la Microsoft Xbox One y la Nintendo Switch.
Ordenadores personales: dado que son dispositivos de propósito general, los ordenadores personales han sido una de las primeras plataformas en permitir la ejecución de juegos. Dado que continuamente están saliendo al mercado nuevos procesadores, tarjetas gráficas, memorias, etc., se produce un crecimiento lento pero firme en las capacidades de los ordenadores. Por ello, los equipos de última generación casi siempre van a superar a las consolas en potencia y memoria ya que adaptan las nuevas tecnologías con mayor velocidad. La cruz de la moneda es que los videojuegos tienen que soportar un abanico muy amplio de hardware ya que la configuración de dos ordenadores personales pueden ser muy distintas y eso necesita una inversión extra de tiempo y dinero durante el desarrollo.
Dispositivos móviles: los últimos en llegar han sido los dispositivos móviles. Si bien hace años que existen las videoconsolas portátiles (Nintendo Gameboy, Atari Lynx, Sega Game Gear, Nintendo DS, Sony PSP, etc.) el concepto ha evolucionado para dar soporte a teléfonos móviles y a otros dispositivos similares (por ejemplo, reproductores de música). Concretamente, la aparición de los smartphones con grandes capacidades gráficas y con un sistema operativo de grandes prestaciones (iOS, Android, etc.) ha disparado el consumo de videojuegos en este tipo de dispositivos.
Los videojuegos mueven más que la industria del cine y la música juntos, no es de extrañar que los estudios de videojuegos hayan dado el salto y lancen cortometrajes, series y películas. Hablamos de los videojuegos cinematográficos que por su desarrollo parecen estar pensados para ser una película interactiva como puedes ver en el cortometraje Adam. El límite entre el cine y un videojuego está difuminado adoptando referencias del cine clásico como pasa con el género Western o bien se basa en películas de gran éxito como Entrevista con el vampiro en el videojuego Vampyr o con series comoPrision Break en el videojuego A way Out.
No existe una clasificación unificada de los géneros de videojuegos, ni siquiera los expertos se ponen de acuerdo. De hecho, lo normal es que un juego moderno tenga un género principal y pinceladas de otros géneros o subgéneros. La clasificación de un videojuego dentro de un género o varios es a veces una cuestión un tanto subjetiva, aunque normalmente se decide bajo dos criterios:
Tipo de experiencia que quiere transmitir al jugador, ya sea a través de su jugabilidad, estética o narrativa.
Por su mecánica de juego, es decir las reglas definidas que producen una experiencia de juego o jugabilidad satisfactoria al usuario. Entre las mecánicas más utilizadas en los videojuegos están los puntos, los niveles, retos o desafíos, adquisición de bienes virtuales, los rankings de jugadores, etc.
Por lo general un videojuego pertenece a un sólo género, o a dos si se integran bien entre sí. También es posible que tenga varios géneros, aunque es muy poco común o se le suele asociar a otro que los englobe (p ej. el género Sandbox), en caso de tener mecánicas de otros juegos se suele referir a ellos como componentes más que como género adicional.
La decisión del género o géneros de un videojuego se suele llevar a cabo en la fase de preproducción, durante el diseño, y puede cambiar a lo largo de su desarrollo.
Acción: este género incluye la lucha, peleas y disparos por lo que su contenido suele ser violento. Se base en realizar movimientos o combates rápidos mediante ejercicios de repetición, por ejemplo, pulsar un botón para que el personaje ejecute una acción .
Aventura: este género incluye hazañas y peligros. El protagonista del juego debe atravesar grandes niveles, luchar contra enemigos y recoger objetos de valor en base a un argumento extenso y enrevesado. Estos juegos suelen tener una duración larga donde la toma de decisiones influyen en la trama del juego.
Arcade: este género incluye plataformas, laberintos y aventuras. Su nombre viene de las máquinas recreativas donde el personaje se desplaza por planos o plataformas. El ritmo del juego es rápido y requiere tiempos de reacción mínimos ya que puede perder vidas, por ejemplo, por una caída desde una plataforma.
Deportivo: este género incluye el fútbol, tenis, baloncesto, golf, boxeo, conducción, etc. Recrean diversos deportes y requieren habilidad, rapidez y precisión con lo cual el jugador debe practicar muchas horas. Suelen tener un alto grado de competitividad ya que el juego se desarrolla en ligas.
Estrategia: este género incluye el rol y juegos de guerra. Se debe planificar las acciones o definir una estrategia para superar al contrincante. Suele ser normal perder en las primeras partidas e ir progresando a medida que se juega y se superan los niveles del juego aplicando la inteligencia.
Simulación: este tipo de juegos imitan la experiencia de manejar vehículos, aviones, armas, instrumentos o bien simuladores de una situación. Este tipo de juegos pueden requerir de periféricos específicos que suelen tener muchos controles como un volante de carreras con lo cual requiere de muchas horas de juego para alcanzar cierta destreza. Suelen ser muy satisfactorios y reales ya que podemos vivir volar un avión o bien conducir un coche de F1.
Juegos de mesa: este género incluye juegos de cartas, habilidades, preguntas y respuestas. Se llaman así por los juegos tradicionales que tienen un tablero, cartas y fichas. En este caso el adversario es otro jugador con lo cual son ideales para jugar en familia y amigos.
Juegos musicales: este género incluye juegos de baile, ritmo y mezcla de sonidos. El jugador interactúa con la música de alguna forma, ya sea para seguir la letra o notas de una canción o realizar una serie de movimientos en base al ritmo de la música. Estos juegos ofrecen muchas posibilidades de socialización.
RPG: significa Rol Playing Game, es decir, juego de Rol. El jugador adopta el papel de un personaje en un tipo de aventura donde se desarrolla una historia. Es imprescindible que el personaje mejore sus atributos y habilidades mediante la experiencia. El personaje tiene libertad absoluta para moverse y realizar diversas acciones en un escenario más o menos amplio como puede ser comprar o vender objetos en tiendas, usar ataques especiales, etc.
Además de clasificar un juego por su género también se realiza una clasificación por edades recomendadas analizando el contenido del videojuego. Esta clasificación es responsabilidad de los gobiernos, con lo cual nos encontramos diferentes sistemas utilizados para la clasificación de videojuegos por edades. En Europa se utiliza el sistema PEGI y en EEUU el sistema ESRB. Puedes ver la diferencia entre ambos sistemas en el siguiente enlace Clasificación de los videojuegos por edades.
Finalmente nos basamos en la inversión económica para la última clasificación de los videojuegos, para aquellos que son producidos y distribuidos por un distribuidora importante, y tienen un marketing similar al lanzamiento de una película. Este tipo de juegos se les denomina Juego AAA o Triple A ya que cuentan con un alto presupuesto. Por poner un ejemplo, se ha estimado que Halo 3 tuvo un coste de de 30 millones de dólares, y un presupuesto de marketing de 40 millones de dólares. En contraposición están losvideojuegos independientes o indie games que son creados por empresas con un equipo de desarrollo de cuatro a diez personas, que no cuentan con apoyo financiero y la distribución del juego es a través de Internet.
LRM Esquema fases de un videojuego (Dominio Público)
Ya hemos mencionado la estrecha relación de los videojuegos con el cine y el ciclo de vida de un videojuego también está relacionado con el proceso de producción de una película, que se puede englobar en tres ciclos: Pre-Producción, Producción y Post-producción. Como muestra la imagen cada ciclo engloba diferentes fases que explicamos a continuación:
Fase de concepción: en esta fase sale la idea del juego. Se suele utilizar la lluvia de ideas o brainstorm y bocetos para que nazca una idea buena que se pueda llevar a cabo. Antes de pasar a la siguiente fase sería deseable hacer un testeo para conocer si el proyecto tendría una buena aceptación mediante encuestas y valorar el potencial de nuestra idea con respecto a otros juegos que ya están en el mercado. Esta fase finaliza con la realización del documento High Concept Document (HCD) que contiene una serie de puntos sobre los que se trabajará posteriormente: concepto, público final, género, plataforma, historia, descripción y requisitos hardware. Sería el currículum vitae de nuestro juego.
Fase de diseño: ya tenemos la idea del juego, con lo cual ahora hay que diseñarlo y desarrollar un documento de diseño o GDD que permite al lector conocer bien la idea del juego sin tener que entrar en aspectos técnicos. En este documento se explica el juego en su totalidad: la historia que va a servir de punto de unión de todo el juego, el estilo del juego, los personajes que van a interactuar, aspectos de jugabilidad, niveles, describir lo que el jugador puede hacer y cómo puede hacerlo, los efectos de sonido, etc. Este documento será la guía para las futuras fases del proyecto, pero estará sujeto a cambios, ya que no se puede saber todo desde el principio o puede que cambien cosas del juego posteriormente. Puedes consultar Documentación de un videojuego que describe con más detalle las partes de este documento.
Fase de planificación: si se cuenta con presupuesto se suele realizar esta fase donde todas las ideas y conceptos se dividen en tareas que tienen una duración estimada. Se obtiene por tanto una primera imagen de lo que podría ser el videojuego.
Fase de producción: el objetivo más inmediato de esta fase es tener un prototipo jugable y posteriormente el desarrollo de todo el videojuego. Aquí entran todas las áreas de especialización que permiten toda la programación: los artistas o animadores que se encargan de crear los escenarios, personajes, objetos, menús de navegación, etc. El Game Designer encargado de definir el estilo del juego y valorar el resultado del juego (en el cine estaríamos hablando del director de la película), los programadores, los músicos, ...
Fase de pruebas: donde se corrigen los fallos del juego y se mejora la jugabilidad a medida que se prueba el juego. Las primeras pruebas llamadas Alpha suele realizarlas un grupo de personas relacionadas con el proyecto para detectar errores graves y solucionarlos (fixing). La segunda fase llamada Beta suele realizarla los Tester. Estas personas son ajenas al proyecto, pero tienen muchas habilidades y destrezas con los videojuegos, de forma que saben en qué situaciones se podrá encontrar el usuario final y comprobar si la respuesta del juego es la deseada. Los tester mediante sus conocimientos y aportaciones permiten mejorar la experiencia del juego. Cuando esta fase termina se obtiene la copia definitiva o Gold Mastery que se enviará a la fábrica para realizar las copias que se distribuirán.
Fase de distribución y marketing: si nos centramos en un juego Triple A esta fase incluirá un gran marketing que empezará mucho antes de la distribución del juego con múltiples lanzamientos a lo largo de todo el mundo, unido al merchandising de los personajes del juego. En cuanto a la distribución en los juegos Indie suele publicarse en plataformas digitales como Steam pero también se pueden crear copias del juego y venderlo en tiendas físicas.
Fase de mantenimiento: se suele realizar mediante parches o actualizaciones. Esta fase es importante, ya que el juego debe adaptarse a las últimas novedades en lenguajes de programación y software. Se suele tener muy en cuenta la opinión de los usuarios para decidir qué se modifica.
El merchandising son técnicas y estrategias de promoción de un artista, un grupo o una marca. En este caso se lanza una serie productos publicitarios para promocionar un videojuego como pueden ser figuras de los personajes, objetos del juego...
Si bien en los años 70 y 80 los videojuegos eran diseñados e implementados por una persona o un grupo reducido, hoy en día lo normal es que un proyecto se lleve a cabo por decenas de personas. Como se puede deducir, en ellos no solamente hay programadores y artistas sino que también intervienen editores, productores, distribuidores, escritores, probadores, publicistas, gestores económicos, soporte técnico, etc. Tan solo tienes que fijarte en los títulos de créditos de un videojuego moderno, ¡aparece tanta gente como en una película!
La etapa de producción es la más costosa por el número de personas que involucra. Para conocer las áreas relacionadas con el perfil profesional de este módulo nos centraremos en la parte de producción, y dentro de ella, en los equipos de diseño y programación.
Todas esas secciones forman el equipo típico de desarrollo de un videojuego moderno de gran presupuesto y está liderado por el director o Game Designer que se encarga de revisar todo el proceso de desarrollo del juego.
Cada persona que participa posee un área de especialización, aunque no siempre la aplica trabajando en lo más obvio. Por ejemplo, un programador puede estar echando una mano en gestión de calidad o en soporte técnico ya que sus conocimientos benefician el funcionamiento de esa parte del proyecto.
A continuación vamos a desglosar la fase de producción para ver las áreas que participan:
Diseño del juego: se da por finalizada la primera versión del GDD y todos los miembros del grupo conocen los elementos que componen el juego.
Diseño artístico: en este apartado se trabaja todo lo que tenga apariencia en el juego y con lo que el jugador interactúa. Es el director de arte o diseño el encargado de supervisar las siguientes fases:
Historia: para que un videojuego sea bueno es necesario que el jugador entre en la historia de los personajes y del mundo donde sucede el juego. El jugador debe entender el antes y ver que hay un buen guión. Toda esta narrativa se conoce como la Biblia y es realizada por los guionistas del videojuego.
Sonido: se diseña la banda sonora BSO del juego (sonidos, voz del narrador o diálogos, música de fondo y efectos). Suele estar formado por el director de sonido.
Interfaz: se describe la forma en que el jugador verá el menú de la aplicación o GUI o el panel de información de nuestra partida o personaje también llamado HUD. Es este panel se informa al jugador de la vida restante, mapa con la ubicación, munición, objetos en uso, etc. Esta tarea la realiza el diseñador de interfaces que es experto en usabilidad.
Gráficos: se diseñarán los elementos gráficos que forman un escena, entre los que se incluye el conjunto de cámaras y luces. Esta tarea la realiza el diseñador de niveles que sabe crear ilustraciones en 2D y modelado en 3D.
En estas fases se genera un documento conocido como Biblia del Arte del juego.
Diseño Mecánico: aquí nuestros personajes cobran vida. Se debe establecer el conjunto de acciones básicas que puede realizar el jugador y las reacciones del sistema. Por ejemplo, cuando el jugador presiona la tecla de agacharse, el sistema debe activar la mecánica de agacharse. Es lo que se llama Gameplay o jugabilidad y define lo que el jugador puede hacer de forma que hace que el juego sea interesante o no. Estas normas o reglas lo forman un conjunto de algoritmos y estructuras de datos que se utilizan en el juego gracias a la Inteligencia Artificial (IA) del juego y el motor físico que permite generar elementos del juego como explosiones, disparos, caídas, etc.
Cada mecánica hace pensar al jugador ¿Qué pasa si me agacho?... Y si paso por este túnel... ¿Qué ocurre?
Motor del juego (game engine): es el framework o conjunto de herramientas que permiten el diseño, la creación y el funcionamiento de un videojuego. Las herramientas deseables que debe tener un motor son: motor de renderizado, física de videojuegos y detección de colisiones, scripting, motor de sonidos, inteligencia artificial y administradores de memoria. Contar con un buen motor hace que los programadores se dediquen a otras tareas.
Diseño técnico: lo que estaba en papel se debe pasar a software y hay que escoger la plataforma en la que desarrollar el juego. Para tomar esta decisión hay que tener en cuenta la plataforma de destino del juego ya sea un móvil, un PC, una consola o un juego online. Si bien es cierto que se programa pensando en una plataforma posteriormente se puede portar (porting) a otro tipo de hardware. Normalmente un juego se lanza primero a consola y meses después a PC ya que hay que readaptar prácticamente la totalidad del código.
Implementación: tiene como función principal crear el producto en base a la documentación generada de manera coherente. Es el programador quien convierte las ideas y las especificaciones de los diseñadores de juegos en código. La programación se divide en una serie de tareas, y cada una se otorga a un programador diferente en base a sus conocimientos. Por ejemplo el Programador de IA tiene que tener conocimientos de física para asegurarse de que los objetos se mueven y reaccionan con naturalidad.
Fase de pruebas: en esta fase participan los Tester que ya se han mencionado anteriormente, que prueban el juego para detectar fallos. Hay un perfil más profesional que se llama QA Tester (Quality Assurance) que tiene como objetivo garantizar la calidad del producto. Este tipo de perfil actúa en todas las fases, no sólo en la fase de pruebas.
Scripting es un tipo de lenguaje que para integrarse con otros lenguajes de programación que realizan una pequeña función dentro del programa.
¿Existe hueco en la industria actual para desarrolladores de pequeño tamaño? ¿Cuáles de los videojuegos a los que has jugado últimamente estaban hechos por desarrolladores independientes?
Juan quiere ponerse ya manos a la obra y empezar a utilizar los nuevos conceptos de una forma práctica. Para ello es imprescindible decantarse por un motor de juegos 2D y 3D que se ajuste a sus necesidades, pues dependiendo de su elección tendrá a su disposición un determinado conjunto de herramientas u otro. Dado que ya tiene experiencia previa trabajando con el entorno Android Studio, decide restringir la búsqueda del motor a aquellos que funcionen correctamente con esta plataforma de desarrollo. Tras indagar durante un rato en Internet y leer páginas de comentarios en unos cuantos foros, decide finalmente probar con Unity.
Juan no tiene conocimientos previos en Unity, con lo cual va a necesitar una buena documentación. Se da cuenta que Unity tiene una gran comunidad de desarrolladores y buenos tutoriales en español. ¡Está deseando comenzar con este nuevo proyecto!
Existe una gran cantidad de motores 2D y 3D, algunos de los cuáles son de código abierto, otros simplemente gratuitos y, cómo no, también de licencia comercial. Es posible encontrar motores que incorporan sus propios lenguajes de programación y editores de recursos integrados en un entorno de desarrollo. Otros son simplemente librerías que se pueden usar en los entornos de desarrollo que nosotros queramos. No menos importante es tener en cuenta la cantidad y fecha de sus últimas actualizaciones, pues muchos motores llevan meses o años abandonados a su suerte.
Como imaginarás, la elección de un motor depende aún de muchos otros factores:
Editor potente que nos permita trabajar con las escenas.
Lenguaje de programación a usar.
Recursos que nos ofrece y que podemos importar a nuestros proyectos.
Plataformas a las que queremos destinar el producto final, incluso móvil.
Conjunto de scripts que incorpora junto con un buen editor que permite modificarlos.
Que permita juegos 2D y 3D.
Documentación completa.
Que tenga una gran comunidad de desarrolladores, no sólo en los foros de Unity sino en todo Internet.
Por todas las características mencionadas hemos escogido Unity. Nosotros vamos a empezar la aventura de construir nuestro propio videojuego y la curva de aprendizaje en Unity para crear juegos básicos y sencillos en 2D y 3D es rápida. Utiliza C# como lenguaje para los scripts y aunque no lo conozcamos en profundidad tiene muchas similitudes con Java que ya conocemos. Unity cuenta con la tienda más completa de complementos para los juegos llamada Asset Store y cuenta con una documentación actualizada y extensa en castellano centralizada en su página donde se pueden ver el Manual de Usuario y la documentación de la API de programación o de scripting.
Entre las desventajas que tiene Unity está que en las actualizaciones muchos elementos e instrucciones se marcan como obsoletos, con lo cual si el juego es complejo es un poco tedioso. De todas formas Unity cuenta con un Sistema de Actualización de API Obsoleto que detectará usos de código obsoleto en los scripts, y reescribe el código usando la versión actualizada del API. Otro inconveniente son las tarifas de las licencias en sus versiones Plus, Pro y Enterprise, pero ofrece una versión Personal gratuita a la que han añadido ciertas herramientas que permiten crear un juego de calidad y es la que a continuación instalaremos.
¿Deseando comenzar la aventura de construir tu propio videojuego?
Unity es una herramienta de desarrollo de videojuegos 2D y 3D creada por la empresa Unity Technologies y actualmente es el software más utilizado para el desarrollo de juegos por las características que ofrece y su fácil manejo. Está disponible para Windows Microsoft,Mac OS y finalmente Linux con su última versión 2019.3.
Podemos decir que su principal ventaja es ser multiplataforma, permite implementar tu juego en un gran número de plataformas: dispositivos móviles, consolas, ordenadores, televisores, web, realidad aumentada, realidad virtual, etc.
El Editor de Unity permite organizar y trabajar fácilmente con las escenas de un proyecto. Es desde las escenas que se crea el contenido del juego y se programa sus acciones mediante un lenguaje de scripts, que puede ser JavaScript, C# o Boo. Su uso es intuitivo y fiable. No obstante se pueden instalar extensiones al editor para añadir nuevas funcionalidades a medida que las necesites.
Unity no se centra en el código, sino en los recursos o Assets, vamos construyendo nuestro juego con estos bloques que son archivos de imagen, modelos 3D, archivos de sonido, etc. Unity ofrece herramientas para poder construirlos como Animator Controller, Audio Mixer o Render Texture o bien puedes adquirirlos desde su tienda virtual llamadaAsset Store. Puedes consultar la guía de Unity donde te explican la cantidad de recursos que puedes encontrar. También puedes importar modelos y animaciones desde la mayoría de programas 3D (Blender, Maya, 3ds Max, Modo, Cinema 4D, etc.)
Te mostramos a continuación un vídeo donde podrás comprobar cómo a través de un paquete de recursos podemos construir el escenario de un juego:
Crear un escenario a partir de un paquete de recursos en Asset Store
En el caso de tener alguna duda Unity dispone de una excelente documentación, la cual se puede consultar en Documentación oficial de Unity , además añade guías y tutoriales para desarrolladores. Existe además una gran comunidad de desarrolladores que nos permitirá compartir nuestros conocimientos o dudas con usuarios expertos.
Que haya conseguido ser el lenguaje más utilizado tiene que ver con el esfuerzo y trabajo de Unity Technologies para evolucionary mejorar tanto en forma de actualizaciones y parches para solucionar fallos detectados en las versiones publicadas, como en publicar nuevas mejoras para programadores y artistas. Un ejemplo es la versión 5 donde se añadieron nuevos sistemas de simulación de físicas, efectos gráficos, efectos volumétricos y herramientas cinemáticas que permitió la realización del cortometraje Adam.
Además Unity ofrece ciertos servicios que complementan el desarrollo y la gestión del videojuego.
Unity Cloud Build:permite compilar y desplegar automáticamente tu juego en la nube.
Unity Analytics: visualiza los datos de tu juego en un panel de control permitiendo modificar la jugabilidad para conseguir una mayor experiencia al jugador.
Unity Cloud Diagnostics: permite llevar un registro de lo que están experimentando tus usuarios, responder a sus comentarios y corregir problemas rápidamente.
Unity Ads: permite insertar publicidad en los videojuegos.
Veamos a continuación cómo instalar Unity en nuestro ordenador y trabajar con su editor.
Herramienta que permite al desarrollador decidir qué animaciones utilizar, cuándo y cómo mezclar las animaciones para una transición entre estas de un personaje o de un objeto.
Esta herramienta permite mezclar audio , crear efectos de sonido y modificar los parámetros de los efectos entre otras acciones.
El editor de Unity 3D es uno de los más sencillos y potentes del mercado, puedes ver en el siguiente enlace las razones por las cuales utilizar Unity para el desarrollo de juegos:
Vamos a instalar a continuación el Editor de Unity que está disponible para Microsoft Windows, Mac OS y Linux desde su versión 2019.1 aunque se debe cumplir una serie de requisitos que puedes consultar los Requisitos de Linux para comprobar si puedes instalar el editor.
Desde la versión del 2019, Unity facilita un instalador general llamado Unity Hub que gestionará por nosotros la descarga del Editor de Unity, las versiones instalaciones del editor, nuestra cuenta de usuario junto con su licencia y la jerarquía de proyectos creados con Unity. Para ello realizaremos los siguientes pasos:
Descargar el instalador, y para ello debemos entrar a laWeb de Unity.
Pulsamos sobre el botón Get Started, elegimos el plan Individual y el tipo de licencia Personal.
En la página "Comienza a crear con Unity" (Start creating with Unity) pulsamos sobre el botón Start here y aceptamos los términos de la licencia.
Finalmente se descarga el instalador.
Otra opción es ir directamente a la página de descarga y seleccionar Descarga Unity Hub.
Al ejecutar por primera vez Unity Hub aparece la ventana License Management que nos pide activar la licencia de Unity si la tuviéramos o solicitar una licencia. Consulta el siguiente enlace en el caso que tengas dudas en el proceso de activación de la licencia.
Cuenta de usuario (Account): donde podremos gestionar entre otras opciones nuestras organizaciones y licencias.
Preferencias (Preferences): en esta opción podemos cambiar el directorio de las diferentes versiones del editor de Unity. Tenemos que tener en cuenta que una instalación puede ocupar 8 GB.
Listado de opciones: proyectos que estamos realizando (Projects), diferentes tutoriales y proyectos de ejemplos (Learn) y las versiones del editor que tenemos instaladas (Install).
Es en la pestaña Install donde tendremos los Instaladores oficiales de las versiones de Unity:
En este caso instalaremos la última versión, la 2019.3. En esta pantalla se muestras las versiones que aún están en fase beta y las estables.
En la pestaña Add modules to your install se deben seleccionar los módulos adicionales. Por defecto no se instalan los módulos necesarios para exportar el juego a otras plataformas. En nuestro caso necesitamos que incluya el SDK de Android con lo cual marcaremos la casilla Android Build Support.Otra opción es descargar la documentación en local para no tener que acceder a la web.
Finalmente se pulsa sobre el botón Done, y se procederá a instalar el editor. Es un proceso que lleva su tiempo.
Una vez tengamos un editor instalado, a su derecha tenemos un menú que nos ofrece añadir nuevos componentes a nuestra instalación, se puede establecer como versión preferida a la hora de crear un proyecto y la opción de desinstalar.
Para crear un proyecto o bien abrir uno ya creado pinchamos en la opción Project. Crear un proyecto nuevo es una tarea fácil:
En primer lugar pulsamos sobre el botón New. En el desplegable de la derecha aparecen los editores que tenemos instalados. Si no se selecciona ninguna versión lo hará en la instalación predefinida.
A la derecha nos pide el nombre del proyecto que será también el nombre del directorio donde queremos guardar el proyecto.
A la izquierda Unity nos ofrece una serie de plantillas de proyectos donde 2D y 3D son las opciones más comunes. La opción 3D con extra contiene una serie de ejemplos que permiten al programador aprender más sobre el uso de Unity. Finalmente existen otros tipos de proyectos que se centran en plataformas específicas como la realidad virtual (High Definition RP) o plataformas con un hardware de gama baja donde se necesita obtener unos resultados más efectivos (Universal Render Pipeline). Estas dos plantillas suelen tener nuevas funcionalidades que permiten obtener mejores resultados sobre elementos como la iluminación, los colores, los materiales o mejorar el rendimiento en el procesamiento de las imágenes.
Una vez que se ha creado el proyecto, se abre en el Editor de Unity. Recuerda que siempre puedes abrir un proyecto ya creado desde la opción ProjectsdeUnity Hub.
Crea un proyecto 3D llamado Modelos3D y otro proyecto en 2D llamado UFOGame. Estos dos proyectos los utilizaremos en próximos apartados para conocer las características de Unity.
Una vez finalizado el proceso de creación de nuestro primer proyecto, nos mostrará el Editor de Unity que se divide en las siguientes secciones:
Una barra de título que muestra el nombre del proyecto, el nombre de la escena activa, la plataforma destino del proyecto y la versión de Unity, junto con la versión de la librería gráfica (en Linux OpenGL). Suele ser útil cuando el proyecto contiene muchas escenas y ver en cuál estamos trabajando.
Una barra de menú en la parte superior con distintas categorías: File, Edit, Asset,…
Una barra de herramientas justo debajo, con botones para acceder a distintas opciones.
El resto de la pantalla se divide en distintas vistas o secciones: Hierarchy, Scene, Game, Project, Inspector.
Al igual que otros IDE las vistas son configurables en ubicación, tamaño, posición, etc. Es lo que se conoce en Unity como Layout (que se encuentra a la derecha de la barra de herramientas marcado con un óvalo amarillo). Mediante esta opción se puede escoger diferentes distribuciones de ventanas dos por tres (2 by 3), división (4 split) o guardar una distribución personalizada.
Para crear una distribución personalizada simplemente hay que pulsar sobre la vista que se quiere mover y arrastrar la vista a una de las ubicaciones que mostramos en la imagen en diferentes colores. Si existiera ya una vista pestaña, se añadiría como una opción más y si en el área no hubiera una vista, la crea. Si quiere guardar esta distribución de vistas lo puede realizar desde el menú Layout > Save Layout. Le pones el nombre al diseño y pulsa sobre el botón Save. Se puede recuperar escogiéndolo en el desplegable de la pestaña Layout.
Es posible que necesitemos maximizar una vista para ello se pulsa de forma simultánea la tecla Shift+barra espaciadora. Para volver al tamaño inicial de la vista se pulsa las misma teclas.
Abre el proyecto Modelos3D y crea una vista o Layout con las vistas escena y juego juntas tal como muestra la siguiente imagen. Guarda el Layout con el nombre que consideres oportuno.
Partimos del proyecto Modelos3D y vemos que a la izquierda se encuentra una vista que muestra una jerarquía de objetos llamado Hierarchy. Todo en Unity es un objeto del juego o GameObject: un cubo, un personaje, una escena, etc. ¿Cómo se distinguen estos objetos?
Pues por según los Componentes que contengan, ya que son los que realmente implementan la funcionalidad o el comportamiento de un objeto. Por lo tanto los GameObject son objetos contenedores.
Por defecto en esta jerarquía tenemos una escena de ejemplo (SampleScene) que contiene por defecto dos GameObject: una cámara (Main Camera) que es el objeto captura y muestra el mundo al jugador y una luz (Directional Light). Esta jerarquía nos muestra la relación entre los objetos, ya que se puede crear relaciones padre e hijo.
A través de este panel podremos realizar las siguientes opciones:
Añadir nuevos objetos.
Realizar operaciones de la escena: salvar, descartar cambios, añadir una nueva escena, acceder a los recursos de la escena, etc.
Operaciones con los propios objetos de la escena: eliminar, renombrar, pegar, pegar como un hijo, etc.
Si seleccionamos uno de los objetos en la jerarquía se puede ver cómo cambia la vista Inspector y aparecen los componentes que lo forman. Selecciona el objeto Main Camera y explicaremos a continuación sus componentes:
El primer componente muestra las propiedades del objeto en sí:
Si se quiere añadir una etiqueta específica, destacará este objeto dentro de la vista central llamada Scene.
Si el objeto está activo o inactivo.
El nombre del objeto que aparece en la jerarquía de objetos.
Si queremos que sea un objeto estático, es decir que no se mueva en la escena. Se puede seleccionar los sistemas a los que se quiere avisar. Un ejemplo puede ser una pared compuesta por diferentes objetos estáticos y que a la hora de renderizar el juego se tratasen todos los objetos como un único objeto llamado batch.
El Tag que lo distingue de otros GameObjects de la escena. Esta opción es útil cuando se programa, ya que se puede realizar alguna función si el objeto tiene asignado un determinado Tag.
Seleccionar una capa o Layer, para agrupar objetos y realizar funciones apropiadas para cada grupo.
En la siguiente división está el componente Transform, que es el que indica su posición, rotación y escala en la escena. Todos los objetos tienen un componente Transform.
En la siguiente división se muestra el componente Camera con todas las propiedades que contiene. Aquí hemos marcado el icono de la ayuda donde podemos consultar la documentación de este componente en Unity y al que haremos referencia cuando queramos conocer las propiedades de un componente. El siguiente icono que hemos marcado es el menú de opciones del componente que nos permite entre otras cosas duplicar y eliminar un componente.
Y por último el componente Audio Listener que indica que la cámara puede actuar como un micrófono, recoger los sonidos de la escena y reproducirlos en un dispositivo de salida.
Si queremos añadir una funcionalidad a un objeto tendremos que añadir el componente correspondiente mediante la opción Add Component.
Una de las vistas más importantes es la vista proyecto o Project. Tenemos que tener en cuenta que un videojuego está formado por muchos recursos o Assets (modelos 3D, objetos 2D o sprites, texturas, archivos de sonido, código fuente, etc.) que se guardan en nuestro proyecto como ficheros y carpetas y esta organización se va a implementar en la vista de proyecto. Mantener un orden será de gran utilidad a la hora de buscar un recurso. Consulta el siguiente enlace para ver las operaciones que se pueden realizar con las carpetas y cómo buscar recursos dentro de esta vista Operaciones con carpetas y recursos.
Si te vas al explorador de directorios y archivos verás que un proyecto contiene las siguientes carpetas:
Assets: es la carpeta raíz de todos nuestros recursos. En general trabajamos con esta carpeta a través de la vista Project y es aquí donde se copiarán los archivos de los recursos que importemos. En este caso mantendremos la misma estructura de directorios que traiga el recurso en sí para tenerlo encapsulado bajo el mismo contexto.
Project Settings: en esta carpeta se guarda la configuración de nuestro proyecto y del entorno Unity. Puedes acceder visualmente a la configuración de las herramientas que contiene (Settings Manager) mediante la opción del menú Edit > Project Settings.
Library: los recursos de la carpeta Assets no se utilizan tal cual en la versión ejecutable, sino que se procesarán y optimizarán para un hardware o plataforma.
Temp: en esta carpeta se guardan ficheros temporales necesarios a medida que desarrollamos el juego.
Packages: es un conjunto de ficheros que podemos importar o exportar en otros proyectos y son encapsulados siguiendo un formato a través del cual Unity será capaz de descomprimirlos de forma automática, fácil y clara. Este es el formato oficial que Unity usa para la importación de ficheros dentro de un proyecto.
Unity viene con muchos recursos de serie, y también pueden descargarse gran cantidad de ellos en internet veremos a continuación cómo hacerlo.
Podemos gestionar los paquetes de nuestro proyecto mediante la herramienta del Administrador de Paquetes de Unity(Window > Package Manager). Mediante esta herramienta podemos instalar, eliminar o actualizar paquetes para cada proyecto.
Cuando queramos instalar un paquete hay que desplegar la lista "All packages" e incluir todos los paquetes disponibles, mediante la opción All. La lista ahora muestra todos paquetes, independientemente de si ya están instalados en el proyecto. Ya en el campo de texto de la derecha (marcado en azul) podremos buscar y filtrar los paquetes. Introducimos la palabra sprites y en el listado aparecerá el package 2D SpriteShape que es el que queremos instalar mediante la opción Install. Como puedes ver han aparecido una serie de carpetas dentro del directorio Package. Para que podamos utilizarlos en nuestro proyecto, tenemos que seleccionar la opción Import Into Project. Mostramos a continuación la imagen con el proceso entero:
Los pasos a seguir son similares, salvo que la búsqueda la realizaremos desde la herramienta Asset Store (Window > Asset Store). Nos abre una nueva vista donde podemos descargar directamente los paquetes. Es aconsejable utilizar la opción Filtersy después realizar la búsqueda enSearch.
Siempre que tengamos que instalar un paquete de terceros tenemos que tener la garantía de que es correcto. De todas formas nunca está mal realizar una copia de seguridad. Si utilizas Github siempre podrás volver a un commit anterior o si no, copia las carpetas Assets (junto con los ficheros .meta de cada recurso) y Project Settings de la carpeta raíz del proyecto antes de instalar un paquete no verificado. A continuación realiza los siguientes pasos:
Abre el administrador de paquetes y pulsa sobre el icono añadir
A continuación debes seleccionar la opción Add package from disk button.
Selecciona el paquete desde el disco y haz doble clic sobre el fichero package.json
Independientemente de la opción que hayamos escogido, es recomendable ver si a la hora de instalar un paquete obtenemos algún tipo de error o advertencia en la vista consola o Console. Posteriormente cuando realicemos nuestro código mostraremos nuestros mensajes en la consola para comprobar el resultado obtenido.
Es un objeto 2D que es controlado por el motor gráfico. Un sprite puede moverse, rotar, chocar con otros sprites y cambiar de aspecto para producir animaciones
Es en la ventana Scene donde se encuentra el conjunto de objetos o GameObject que forman el mundo virtual junto con las cámaras, las luces y demás elementos. Es en esta pantalla donde editamos el juego y se explicará en detalle posteriormente, pero nos centraremos aquí en la ventana donde se representa el juego ya finalizado o renderizado.
Es en la ventana Game donde se abre una previsualización del juego, es decir, muestra lo que el jugador observaría mientras esté jugando y es debido a una o varias cámaras. Es por eso que Unity añade siempre a un proyecto una cámara de nombre Main Camera. Si pulsamos sobre ella podemos ver que aparece una vista denominada Camera Preview que nos muestra cómo el usuario vería el juego, es decir, lo mismo que si reproducimos el juego en la vista Game.
Es en esta vista donde podremos reproducir el juego mediante los botones de control de la barra de herramientas que permiten reproducir el juego, pausar o saltar hacia delante en el juego.
Para ejecutar el juego se pulsa sobre el botón reproducir y para pararlo de nuevo se pulsa sobre el mismo botón. También se puede utilizar la tecla de acceso rápido Ctrl + P (Windows/Linux) o Cmd + P (macOS).
La opción de pausa es interesante cuando queremos parar el juego en un momento dado y detectar posibles errores en la edición de la escena.
La opción saltar nos permite evaluar el juego frame a frame.
Cuando se reproduce el juego se oscurece la pantalla para que nos demos cuenta que estamos en modo PLAY. Ese color se configura en Edit > Preferences > Colors > General > Playmode Tint.
Hay que tener cuidado porque Unity nos permite modificar los objetos en la vista de escena cuando estamos en modo PLAY, pero una vez finalizado, todos los cambios se descartan.
Otra opción interesante es seleccionar la opción Maximice on Play en la barra de control de la vista de juego o bien seleccionar una dimensión de aspecto en la opción Free Aspect.
Al igual que otros objetos podemos cambiar la posición de la cámara para simular varias perspectivas en la ventana Game o bien rotarla en cualquiera de sus tres ejes accediendo a su propiedad Transform. Si después de practicar queremos tener una visualización correcta del juego debemos poner los siguientes valores en Position: X=0, Y=0, Z=-10 de la cámara.
Otra opción es establecer a los valores por defecto de un componente mediante la opción Reset del menú de opciones del componente.
Unity integra una serie objetos primitivos en 3D como son: Cube, Sphere, Capsule, Cyclinder, Plane y Quad. Antes de ver las características de cada uno veremos las características de un objeto 3D.
Un objeto 3D tiene tres dimensiones y, por tanto, pueden moverse en el espacio con total libertad. Esto intenta imitar la visión del ser humano, que también es tridimensional. El problema es que la gran mayoría de los monitores sólo son capaces de representar imágenes 2D. Para solucionarlo podemos realizar una operación llamada proyección, que transforma esa imagen 3D en una 2D. Ese proceso de generar las imágenes recibe el nombre de renderizado y es tarea del motor gráfico 3D que integra Unity.
Normalmente, los objetos 3D están constituidos por vértices que juntos forman polígonos, generalmente de tres o cuatro lados. A continuación, en la imagen de la derecha, mostramos un cubo junto con su componente Transform:
Los vértices son los puntos donde confluyen las líneas. La flecha roja indica el eje-x, la verde el eje-y y la azul el eje-z. Vemos que su posición está formada por los valores X=0, Y=1, Z=0, el cubo está elevado ya que está generando una sombra en el plano, ¿pero cuánto? Pues en Unity asume la unidad del espacio del mundo que corresponde a un metro desde el eje del cubo de donde salen las tres flechas.
Inicialmente el objeto no ha sido rotado porque todas las coordenadas en Rotate valen cero. El tamaño del cubo se muestra en Scale y efectivamente todos sus lados valen lo mismo, un metro: X=1, Y=1, Z=1. Se trata de un cubo grande de forma que el motor de física tendrá que tenerlo en cuenta cuando se le aplique algún tipo de simulación.
A continuación mostramos una esfera de un diámetro de una unidad (por tanto un radio de 0.5). A esta esfera se le ha aplicado una textura metálica:
Sobre los polígonos se pueden aplicar texturas para darle un aspecto más realista. Simplificando mucho, podemos considerarlas como unas pegatinas que se pegan a su superficie. Fíjate que algunas áreas se ven en un color más claro que otras. Todo ello es debido a la iluminación de la escena, en nuestro caso por el componente Directional Light.
Otro componente es el plano o Plane que aparece en la primera imagen con el cubo. El plano se ubica en el plano XZ y tiene 10 unidades por cada lado. Este componente es muy útil porque simula el suelo. Cambiando las coordenadas se puede construir paredes. A veces es interesante poner un plano vertical que simule por ejemplo una pantalla, en este caso será de utilidad el objeto Quad con una unidad de largo en el plano XY.
Con forma cilíndrica está el cilindro o Cylindre y la cápsula o Capsule. Ambos tienen una unidad de diámetro y dos de alto. La única diferencia es que la cápsula tiene dos tapas hemisféricas al final.
Es el motor gráfico 3D quien simplificará el trabajo con los objetos tridimensionales permitiendo al código específico realizar operaciones con ellos independientemente del hardware sobre el que se esté ejecutando el juego. Entre estas operaciones está la de crear objetos, moverlos, escalarlos, rotarlos, deformarlos, animarlos, cambiarles las texturas, etc. Para ello el objeto es rodeado de una malla y es el componente Mesh Renderer del motor de Unity quien toma la geometría del filtro de malla y lo representa.
Es el proceso de transformar una vista 3D en una imagen 2D que puede ser mostrada en un monitor.
Consiste en generar una imagen a partir de una escena.
Un punto tridimensional que forma parte de un objeto (X,Y,Z).
Área encerrada por los vértices de un objeto. Puede tener aplicada una textura.
Una coordenada 3D tiene tres componentes: X, Y y Z. Un conjunto de vértices definen un polígono. El proceso de proyección permite pasar una escena 3D a 2D. Las texturas nos permiten definir el aspecto del polígono.
Para este apartado crearemos un proyecto 2D. Podrás ver cómo ha cambiado la vista Scene, y por tanto nuestra experiencia, ya que hemos perdido la perspectiva. Sólo tenemos un único GameObject y es la cámara que nos muestra el eje-x con el eje-y.
Los juegos 2D son aquellos en los que los dibujos tienen dos dimensiones, ancho y alto, pero no profundidad. Para entendernos, son formas planas que se mueven por la pantalla. Podemos dibujarlas más grandes para parecer que están más cerca y más pequeñas para parecer que se alejan, pero siguen siendo planas.
Normalmente, un juego 2D consiste en una o varias capas de imágenes en el fondo sobre las que se pueden dibujar figuras geométricas (líneas, rectángulos, círculos, etc.) o bien objetos 2D como puede ser el jugador, los enemigos, monedas, obstáculos, disparos, etc.
Los objetos gráficos en 2D son conocidos como sprites. El motor controla todos los que estén activos en un momento dado, almacenando la posición en la que están, si hay que dibujarlos rotados, si están o no animados, etc. Los sprites son renderizados por el componente Sprite Rendererde Unity, como los objetos no tienen geometría tridimensional, se evita aplicar ciertos algoritmos.
Las animaciones en los juegos 2D se producen cambiando el dibujo del sprite rápidamente de manera que haya pequeñas diferencias entre uno y otro, lo que produce en el cerebro una sensación de continuidad. Observa las siguientes imágenes y verás cómo cada dibujo está un poco más girado que el anterior: si se dibujara uno tras de otro (de izquierda a derecha y de arriba a abajo) en la misma posición el efecto que captarías es que el avión estaría girando en el sentido de las agujas del reloj.
Unity da soporte a los sprites a través de su Sprite Editor ofreciendo herramientas para escalar, rotar y mover objetos por la pantalla con comodidad como veremos en el siguiente proyecto.
Cuando dos sprites se superponen el resultado final dependerá del orden en que se dibujen. Dicho orden normalmente se denomina plano o capa. Hay que elegir el plano de cada sprite cuidadosamente para que se produzca el efecto que deseamos.
En algunos motores gráficos podemos representar mundos que sean varias veces más grandes que el tamaño de la pantalla. El motor se encargará de mostrar solamente aquella parte que le indique el código específico. Esto permite, por ejemplo, seguir al jugador a lo largo y ancho de un nivel.
Otro elemento gráfico que poseen muchos motores 2D es el de tilemap (celosía o mapa de baldosas), que es una composición de imágenes pequeñas del mismo tamaño. Este recurso es muy útil para dibujar fondos, mapas y niveles.
Es un objeto 2D que es controlado por el motor gráfico. Un sprite puede moverse, rotar, chocar con otros sprites y cambiar de aspecto para producir animaciones.
Es como una celosía hecha de pequeños baldosines (tiles) de pequeño tamaño. Cada uno de ellos puede tener un aspecto cualquiera de entre los diseños disponibles (incluso transparente); el código específico del juego puede alterar el diseño en cualquier momento. Eligiendo bien los tiles pueden formarse mapas de tamaño gigantesco
La velocidad de creación de imágenes se mide en FPS. Las capas nos permiten determinar el orden en que se superponen los sprites. Los tilemaps permiten implementar mapas de forma sencilla. Por último, las imágenes 2D tienen altura y anchura, pero no profundidad.
Dado un objeto queremos que sea controlado por el motor de física, de forma que simule un comportamiento real. Para ello tenemos que usar el componente Rigidbody. El comportamiento de un objeto en el mundo real puede ser alterado modificando propiedades como la fricción, masa o la elasticidad.
El comportamiento de este componente en un objeto 2D es similar a un objeto 3D salvo que sólo puede moverse en el plano XY, es decir, no existe la profundidad y sólo puede rotar en un eje perpendicular a ese plano. Es por ello que en el estudio de los tipos de movimientos o colisiones entre objetos utilizaremos como ejemplo un proyecto 3D al existir el componente profundidad y haremos referencia a documentación o tutoriales que muestran cómo realizarlo en 2D.
Vamos a la jerarquía de objetos y desde el icono añadir o bien pulsando el menú secundario creamos dos objetos 3D: el primero será del tipo 3D Object > Plane y el segundo 3D Object > Cube.
Una vez que hemos elevado el cubo sobre el plano dale al PLAY del control de reproducción y haz clic sobre la vista Game.
¡No sucede nada! ¿Está bien el juego?
Sí, es correcto. El cubo permanece inmóvil, flotando, porque no le hemos aplicado ningún elemento de la física.
Vamos a ver qué sucede cuando al cubo se le aplique una masa. En el mundo real todo objeto tiene una masa y es influenciado por la gravedad, que es un fenómeno natural por el cual los objetos con masa son atraídos entre sí. Es decir, en cuanto al cubo le apliquemos una masa debe simular el mundo real y caer al suelo. Para que esto suceda tenemos que agregar el componente Rigidbody al cubo (puedes consultar las propiedades de este componente en el siguiente enlace Documentación componente Rigidbody). Por defecto tenemos que Use Gravity está activado.
Pero si nosotros no hemos escrito ningún código, ¿cómo es posible?
Gracias al motor de físicas de Unity que es quien "aplica” las leyes físicas a nuestros objetos, y si un objeto tiene masa se verá afectado por la gravedad. Otro ejemplo es cuando un objeto choca contra otro objeto que está inmóvil. Para ver si el segundo objeto se desplaza se tendrá en cuenta la velocidad del primero y las masas de los dos objetos.
La masa es una magnitud física que indica la cantidad de materia que contiene un cuerpo. No confundir con el peso de un objeto, se define como la fuerza de la gravedad sobre el objeto (producto de la masa por la aceleración de la gravedad w = m x g).
Ya hemos visto un ejemplo de cómo actúa la física en un objeto tridimensional te sugerimos el tutorial2D Physics que contiene una serie de vídeos que te muestran las propiedades de la cinemática en un objeto 2D.
Los juegos suelen organizarse en varias escenas que representan las pantallas de información o de niveles dentro del juego. Es común tener una ventana de presentación o splash, pantalla de inicio, una pantalla de configuración, pantallas del juego, del ranking, etc. Por lo tanto son las escenas las que contienen el resto de componentes del entorno del juego: fondos, escenarios, obstáculos, decoraciones, funcionalidades, etc. Es muy fácil pasar datos de una escena a otra de forma que se va construyendo el juego hasta llegar al final de la partida.
Por defecto siempre se crea una escena llamada SampleScene con el icono de Unity a la izquierda y un asterisco a su derecha. Para guardar la escena seleccionada hay que pinchar sobre la opción del menú File > Save Scene, o bien utilizar las teclas de acceso rápido como Ctrl + S(Windows/Linux) o Cmd + S (macOS).
Una escena es un recurso más en Unity (es un fichero con extensión .unity), es por eso que se guardan en la carpeta Assets > Scene en la vista del proyecto. Se suele utilizar esta vista porque contiene todas las opciones a realizar con las escenas, en nuestro caso renombramos la escena que se ha creado por defecto como MainScene como muestra la imagen.
Para crear una escena nueva se puede utilizar la opción del menú File > New Sceneo bien utilizar las teclas de acceso rápido como Ctrl + N (Windows/Linux) o Cmd + N (macOS). Si la escena principal no está guardada te pregunta si quieres hacerlo y a continuación se visualizará una segunda escena llamada Untitle en la jerarquía de de vistas. Finalmente guardamos la escena dentro de la carpeta Assets > Scenecon el nombre SecondScene.
La carpeta Asset > Scene contiene todas las escenas y haciendo doble clic sobre una de ellas se carga la escena en la vista Hyerarchy
Cuando realizas cualquier operación sobre un GameObject o cambias sus propiedades en la vista Inspector estás modificando la escena. Es de utilidad guardar la escena porque además se guarda todo el proyecto. Sin embargo la opción Save Project no guarda los cambios de la escena pero sí cambios que se hayan realizado en los recursos. Puedes consultar el siguiente enlace para ver más información Guardando su trabajo.
Te adjuntamos el proyecto ChangeScene que contiene la práctica realizada en este apartado, pero hemos añadido un script de forma que dando a un botón de la escena MainScene cargue la segunda escena SecondScene.
Comprueba los siguientes aspectos para entender cómo funciona un juego en Unity:
Dentro de la carpeta Assets se ha creado una carpeta Scripts que contiene un script llamado SceneChangeScript que es el que se ejecuta cuando pulsamos el botón en la primera escena y carga la segunda escena.
Se ha creado un GameObject vacío donde se le ha añadido un componte Script que enlaza al script de la carpeta Assets > Scripts. A través de este objeto vacío su script estará disponible para el resto de componentes de una escena.
La escena MainScene contiene un GameObject > UI > Button. Este componente aparece en la vista Hyerarchy dentro de un objeto Canvas. Cuando se pulsa sobre él, se ejecuta el método ShowScene con el nombre de la segunda escena. Para ello hemos realizado la siguiente configuración:
onClick()
Editor And Runtime <strong>-></strong><strong>(Método a ejecutar)</strong> SceneChangeScript.ShowScene
Cuando se ejecuta el script se escriben mensajes en la vista consola.
Es la clase que proporciona los métodos y propiedades para dibujar un gráfico en una interfaz. En Unity todo componente IU debe ser hijo de un GameObject Canvas. Este objeto Canvas es mostrado como un rectángulo en la vista de Escena.
En la vista Scene nosotros somos los espectadores de la escena y podemos ver los objetos desde diferentes ángulos y distancias rotando sobre un objeto. Vamos a trabajar sobre una escena 3D.
Por defecto vemos la escena desde un plano de visión determinado por dos ejes que nos marca el control gráfico que se ubica en la parte superior derecha de la escena llamado gizmo.
En la imagen que te mostramos el gizmo nos indica que estamos viendo el objeto desde el plano (XY) que son las flechas que están activas. Por defecto es el mismo plano de la cámara, si pulsas sobre ella aparecerá la ventana Camera Preview y salvo por nuestra posición en el eje-y estamos viendo la escena desde el mismo plano.
Piensa que como espectadores miramos la escena desde una pequeña ventana. En Unity se suele hacer referencia a cámara de la escena de forma que sólo vemos el plano que nos permite el ángulo de visión de nuestro objetivo. En ambos casos si marcamos desde nuestra visión una línea imaginaria (línea de horizonte) es lo que nos permite interpretar la tercera dimensión o espacio, es decir, realizar un cálculo visual de la distancia entre nosotros y un objeto, o el fondo.
A continuación mostramos varias formas de navegar por la escena, es importante ver la funcionalidad de cada una ellas para después combinarlas. Como todo aprendizaje empezaremos desde lo sencillo y practicaremos con un escena que contiene un único objeto primitivo.
Recuerda que puedes maximizar la vista escena pulsando Shift+barra espaciadora.
La opción más sencilla es movernos por la escena con las flechas del teclado como si estuviéramos caminando:
Las flechas de arriba y abajo mueven la vista hacia el frente y hacia atrás, teniendo en cuenta la perspectiva sobre la escena en la que nos encontremos.
Las flechas izquierda y derecha, nos mueven hacia el lado correspondiente.
Para movernos más rápido se puede mantener pulsado shift y la flecha correspondiente.
Esta herramienta permite desplazarnos por la escena al igual que las flechas. Para activar esta opción o bien pulsamos sobre la tecla Q o pulsamos sobre este icono en la barra de herramientas.
Hay un atajo con el ratón que permite realizar el mismo movimiento que la mano y consiste en pulsar la rueda del ratón, y manteniéndola, movernos por la escena. Al soltar la rueda volvemos al botón que estuviera seleccionado en la barra de herramientas.
Este icono también permite realizar dos acciones más.
La primera es el Modo Orbital, que se consigue pulsando la tecla Alt+clic (Windows) y Ctrl+clic (Linux/macOS). En este momento vemos que la mano cambia por un ojo de forma que podemos rotar alrededor del punto de pivote actual.
Igualmente hay un atajo con el ratón que hacer clic en el botón secundario y mantenerlo pulsado.
La segunda es hacer Zoom,que se consigue pulsando la tecla Alt+clic botón secundario.
Igualmente hay un atajo con el ratón y es girar la rueda del ratón.
Uno de los controles de la vista de escena muy útil es el modo en primera persona. Con este modo es posible volar dentro de la escena en primera persona, ya que podemos rotar por ella. Para usar este modo de vista, se debe:
Mantener presionado el clic derecho del ratón.
Y con eso ya es posible moverse en la escena con las teclas WASD (enfrente, izquierda, atrás y derecha). Y las teclas Q y E para los movimientos de arriba y abajo.
Al igual que en el caso anterior, si se quiere aumentar la velocidad se puede presionar la tecla Shift.
Este modo sólo es posible cuando estamos en modo perspectiva (Persp) . Si se usa el modo isométrico (Iso) sólo nos moveremos alrededor de la vista.
Es probable que hayas perdido los objetos de la escena o bien quieres centrarte en un objeto en concreto. Esta opción es útil cuando la escena es compleja, y para ello puedes:
Hacer doble clic sobre el objeto en la vista Hierarchy.
Seleccionar el objeto en la escena con el ratón (no vale con que esté seleccionado en la vista Hierarchy) y pulsar la tecla f.
Es fácil desorientarse en la escena después de realizar varios movimientos, un truco es hacer doble clic sobre el objeto Plane de la escena
Es el plano formado por el eje horizontal en el plano de coordenadas que se llama eje X y el eje vertical llamado eje Y.
A través de este componente se cambia el ángulo de orientación de la escena. Cuando pulsamos sobre un eje del gizmo se produce una rotación de 90º de la cámara de escena, de forma que la cámara se alinea sobre el eje que se ha pulsado. Este gizmo representa los siguientes ejes:
El eje-x positivo en color rojo. Cuando estemos sobre este eje se muestra la palabra Right o derecha.
El eje-y positivo en color verde. Cuando estemos sobre este eje se muestra la palabra Top o arriba.
El eje-z positivo en color azul. Cuando estemos sobre este eje se muestra la palabra Front o delante.
Hagamos una prueba, si nos situamos delante del plano (XY) mirando hacia el eje-z positivo tal como muestra la imagen del apartado 2.7.1.- Navegando por la escena, y realizamos las siguientes acciones:
Pulsamos sobre el eje-x positivo, el efecto que se produce es que realizamos un giro de 90º hacia el eje que hemos pulsado en el gizmo rotando sobre el eje-y.
Aquí nos encontramos a la derecha, es decir en el eje-x positivo, y pulsamos sobre el eje-z positivo.
Aquí nos encontramos delante y pulsamos sobre el eje-x negativo que no está de color rojo.
Aquí nos encontramos a la izquierda (en contraposición del eje-x positivo que era la derecha) para volver al punto de partida pulsamos sobre el eje-z negativo.
¿Qué ha pasado? Realmente si la cámara hubiera estado grabando hemos obtenido una imagen de 360º de la escena, teniendo el eje-y como eje de rotación.
Fíjate como en todas las imágenes el eje-y permanece inmóvil.
También podemos cambiar el modo de cámara si hacemos clic en el cubo que hay en el centro del gizmo. Hay dos modos Perspectiva (Persp) o Isométrica (Iso). Una proyección isométrica es una representación de un objeto tridimensional en dos dimensiones, ya que las tres direcciones principales (altura, ancho y profundidad) se dibujan utilizando la misma escala. Normalmente la perspectiva Isométrica se utiliza en los juegos 2D ya que si lo realizas en una escena en 3D lo que hará es eliminar la profundidad de la escena, con lo cual se elimina la distancia que hay entre la cámara de escena y los objetos como puedes ver las siguientes imágenes:
En este apartado veremos cómo modificar nuestros objetos a través de los gizmos de objetos que nos permiten desplazar, girar y cambiar la escala de objetos. Ten en cuenta que cuando a través de un gizmo realizamos una operación estamos modificando su componente Transform que es el encargado de almacenar la posición, rotación, escala de un GameObject.
Existen tres tipos de gizmos:
Gizmo Mover: cambia la posición de los objetos seleccionados según un eje o un plano.
Gizmo Rotar: hace girar los objetos seleccionados sobre un eje específico.
Gizmo Escalado: cambia las dimensiones de los objetos seleccionados siguiendo un eje o un plano específico. Si se selecciona el control central se realiza un escalado proporcional en los tres ejes a la vez.
Cada uno de los ejes tiene un color: rojo, verde, azul y amarillo. Los primeros tres corresponden a los ejes X, Y y Z. El amarillo representa el eje seleccionado actualmente. Si aún no se ha seleccionado ningún eje se muestran los tres a la vez, que está representado por el elemento central o círculo externo en el caso de Rotar.
Estas operaciones también se puede realizar a través de la barra herramientas haciendo clic en sus iconos, pero esto se volverá rápidamente tedioso. Una mejor manera es usar las convenientes teclas de acceso rápido ya configuradas:
La tecla t activará la herramienta Rectangular. Aquí hay que explicar que cada objeto en Unity se representa como un rectángulo para fines de diseño y con esta herramienta se puede mover, rotar y escalar el objeto libremente. Se suele utilizar para modificar objetos de la interfaz gráfica (Button, Text, Input Field, etc) en 2D, pero también se puede usar en 3D.
Fíjate cómo al seleccionar una herramienta el gizmo del objeto cambia según la herramienta seleccionada.
Para cancelar una herramienta, presiona q, que te llevará de vuelta a la herramienta de selección predeterminada (este es un truco útil para cancelar cualquier herramienta).
Cuando ya hemos adquirido cierta práctica Unity nos permite activar todos los gizmos del objeto a la vez y poder realizar todas las transformaciones (mover, rotar y escalado) sobre el objeto. Esta opción se realiza pulsando sobre el icono
Modo de dibujo: el primero es un despegable con el valor Shaded. Aquí se pueden seleccionar diferentes modos de visualización de la escena, que no sobre el juego. Esta opción es realmente útil cuando los objetos tienen texturas y se quiere comprobar cómo reacciona la luz con la superficie de un modelo. Esto es fundamental para crear imágenes creíbles.
2D/3D: cambia entre la vista 2D y 3D.
Iluminación: permite activar o desactivar la iluminación de la vista de escena. Si se desactiva la iluminación no se verán tampoco las sombras de los objetos.
Audio: permite activar o desactivar los sonidos de la vista de escena.
Efectos de la escena: permite activar o desactivar mediante el desplegable de la derecha ciertos efectos como el fondo por defecto o SkyBox, la niebla, los efectos de brillo de la cámara y elementos animados.
Objetos ocultos: nos muestra el total de elementos ocultos de nuestra escena. Nos permite mostrar o bien ocultar los elementos ocultos como un todo.
Malla o líneas de cuadrícula: esta opción nos permite mostrar las líneas de cuadrícula y poder ver tanto el tamaño de los objetos como su perspectiva.
Herramientas personalizadas:Unity nos permite implementar herramientas de editor personalizadas. En nuestro caso no tenemos ninguna, con lo cual el despegable no contiene elementos, pero puedes ver el conjunto de opciones en la documentación oficial de UnityUsing Custom Editor Tools.
Opciones de la cámara: contiene opciones para configurar la cámara de vista de escena. A medida que realicemos ejercicios modificaremos opciones de la cámara para ver los diferentes resultados.
Gizmos: nos permite establecer propiedades de los gizmos de los objetos. Hay objetos que tienen un icono personalizado en su control.
Búsqueda: finalmente nos permite buscar objetos dentro de una escena, por defecto es por nombre y tipo, pero se puede cambiar el criterio de la búsqueda pulsando sobre la lupa.
La creación artística es una de las tareas que más tiempo lleva en el desarrollo de un videojuego, ya que el resultado final debe ser real y perfecto. Vamos a ver el trabajo de crear un escenario con un ejemplo muy sencillo: crear una pared. Para ello:
Añadimos un primer cubo y lo posicionamos en las coordenadas X=0,Y=0,Z=0. Recuerda que esta opción también se consigue reseteando el componente Transform de un componente.
A continuación duplicamos el objeto creado en la vista Hierarchy, e intentamos ponerlo al lado del primer cubo.Vemos que no es una tarea fácil, ya que cuando se añade un objeto las coordenadas no son exactas, (por ejemplo X=0.67,Y=0.45, Z=-45). Al final hay que introducir los valores exactos en el componente Transform.
Construir la pared será entonces un tarea más compleja de lo que pensábamos. Vamos a ver cómo Unity nos ofrece la Técnica de Snapping para solventar este problema:
Selecciona la la opción Edit > Grid and Snap Settings. En esta ventana se puede escoger las unidades a utilizar en cada tipo de movimiento de un objeto (por defecto Move: 0,25 unidades, Rotate: 15º , Scale: 0.1 unidades). Recuerda que 1 unidad corresponde a 1 metro cuando hablamos de posiciones y tamaño.
Modificamos el valor Move y ponemos 1 unidad como se muestra en la imagen.
A la hora de añadir un cubo a la escena, si su posición tiene valores decimales podemos seleccionar la opción All Axes de forma que posicionará el cubo a los valores enteros más cercanos.
Otra opción es mover el objeto en base a la unidad introducida, en nuestro caso una unidad 1. Manteniendo la ventana Grid and Snap Settings abierta, pulsamos la tecla Ctrl y movemos unos de los ejes del objeto. Observa cómo da pequeños saltos moviéndose de una unidad en una unidad.
Seguimos copiando el primer cubo (Ctrl+D) y desplazando el cubo (Ctrl+desplazamiento). Al tener como unidad de desplazamiento 1 metro los cubos quedan perfectamente alineados, sin huecos ni solapamiento entre ellos. De todas formas podemos comprobar que es así cambiando la visualización dentro de la vista Scene a Shaded Wireframe.
Siguiendo con el ejemplo anterior donde estamos construyendo una pared. Queremos posicionar el vértice de un objeto en base a un vértice de otro objeto seleccionado previamente mediante la Técnica Vertex Snapping. Para ello seguimos los siguientes pasos:
Añadimos un cubo a la escena, seleccionamos el objeto (hay que asegurarse que la herramienta Move o la herramienta Transform esté activa) y pulsamos la tecla V.
A continuación, sin soltar el cubo, lo acoplamos al vértice del objeto destino.
En el vértice que se ha seleccionado aparece un cuadrado amarillo y el cubo se acopla perfectamente al cubo de su derecha como muestra la imagen:
Hemos visto las opciones que nos ofrece Unity cuando estamos modelando dentro de una escena. Tenemos que tener cuidado para que nos quede correcto, ensamblando correctamente todos los objetos.
Ya hemos visto que crear un posible escenario desde cero es un trabajo que requiere mucho tiempo, por lo que se suele tomar de partida un paquete de recursos de Asset Store que nos puedan simplificar labor. Cuando tenemos ya la pared sólo tenemos que dedicarnos a duplicar objetos, colocarlos y comprobar que no hay huecos ni solapamientos. Mira en este vídeo cómo se construye un escenario.
Crear un escenario a partir de un paquete de recursos en Asset Store
Ya conoce el entorno de Unity y ha echado un primer vistazo a la documentación.
En unas horas, se reunirá con Ana para abordar juntos el aprendizaje de los elementos que componen un juego en Unity. Su idea es realizar un prototipo sencillo de juego para ello Juan se encargará de la parte de programación y Ana realizará el diseño del escenario junto con los personajes usando herramientas específicas que previamente le enseñarán a usar.
Crearemos proyectos sencillos a los que iremos incorporando código y recursos a medida que vamos viendo los elementos que puede contener un videojuego. Todo ello se verá de una forma muy práctica, así que deberías seguir todas las explicaciones en un ordenador que tenga instalado Unity, tal y como se explicó en el apartado anterior. Ten en cuenta que, por falta de tiempo, no vamos a ver todas las posibilidades de Unity, sino que vamos a ver algunas de sus características más básicas, aunque estas servirán de base para que puedas continuar el aprendizaje de este framework.
Finalmente crearemos un juego para un dispositivo Android donde tenemos inicialmente una esfera como personaje principal que se puede mover a través de un tablero. El objetivo de la esfera es destruir a los enemigos representados por cubos en el menor tiempo posible. Una vez haya finalizado mostrará un mensaje al usuario indicando el tiempo que ha tardado en destruir los objetivos.
Tenemos que pensar en el mundo real, donde los objetos están hechos de diferentes materiales: madera, plástico, metal, cristal, etc. Según las características del material la luz se refleja de forma diferente. Para simular en el juego estas características físicas haremos uso de los materiales o Materials. Los materiales son recursos que van asociados principalmente a los GameObject que tienen los siguientes componentes:
Mesh Rendererso renderizador de la malla: es el encargado de recoger la malla o Mesh del objeto y renderizar el objeto en la posición determinada. Una malla es una red de puntos o vértices. Cuando los bordes conectan tres vértices se forma triángulos que definen la forma básica del objeto. Es así cómo el motor de Unity sabe cómo dibujar la superficie del objeto. En Unity, hay dos componentes principales de representación: el Mesh Filter o filtro de malla que almacena los datos de malla de un modelo y el procesador de malla que combina los datos de malla con materiales para representar el objeto en la escena.
Particles System o sistema de partículas: hay objetos en el mundo real que no son sólidos, por ejemplo los fluidos, el humo, las nubes, el fuego, etc. Por ello son muy difíciles de representar utilizando Mesh o Sprite. Para este tipo de objetos se usa el sistema de partículas. Mediante la generación y animación de un gran número de pequeñas imágenes 2D se forma una imagen mayor en la escena. Por ejemplo, una nube estaría formada por un conjunto de pequeños puntos con textura de humo. Cuando hemos dicho animación es porque cada partícula puede cambiar a través del tiempo en base a parámetros como la velocidad, color, tamaño y rotación.
Vamos a crear un proyecto nuevo, donde vamos a crear una pelota de un color sólido. Una vez creado el proyecto:
Vamos a crear una carpeta llamada Materials en nuestro proyecto. Para ello nos vamos a la vista Project > Assets y el menú secundario escogemos Create > Folder.
Seleccionamos la carpeta Materials y crearemos un nuevo material mediante la opción del menú Assets > Create > Material o bien botón derecho Create > Material.
Finalmente para aplicar este material a un objeto sólo hay que seleccionar el material y arrastrarlo al GameObject de la vista Scene para que se aplique el material.
En esta página se explica qué es la Normal: el vector de un vértice o una superficie (perpendicular a la superficie) que ayuda a determinar cómo la luz rebota en el objeto.
En esta página se explican los elementos que forman una malla, aunque esté en inglés es muy recomendable ver sus imágenes:
Todo material tiene un elemento que se llama Shader que es un pequeño script que contiene los métodos matemáticos para mostrar el color de cada píxel renderizado, en base a la iluminación y la configuración del material. Según el shader que se escoja, el material tendrá una opciones u otras. Por defecto Unity nos ofrece Standard Shader que nos permite renderizar la mayoría de los objetos de forma óptima. Puedes consultar otros tipos de shader especializados en el siguiente enlace:
Veamos las propiedades más importantes dentro de un shader:
Indicar el color principal del shader en la propiedad Albedo. Como cualquier herramienta de color se selecciona mediante el gotero que hay a la derecha.
Se puede modificar el aspecto más o menos metálico mediante la propiedad Metallic.
Se puede suavizar el metal modificando el valor de Smoothness.
En el caso que no se le quiera aplicar un aspecto metálico se puede usar Standard (Specular Setup) donde no aparece Metallic y sí Specular que nos permite seleccionar un color para los brillos del material.
En la parte inferior de la vista Inspector se puede ver el resultado de modificar las propiedades anteriores. Además se puede aplicar a diferentes tipos de formas (esfera, cubo, donut, etc) seleccionando el icono que se muestra en la imagen de la derecha.
Los materiales no sólo tienen un color sino que están formados de texturas. En un Unity, una textura es una imagen bitmap que se pega a la superficie de un objeto 2D o 3D. Hay muchas texturas que puedes obtener en Internet, pero te recomendamos lo siguiente:
Se recomienda que la textura tenga forma cuadrada de forma que sea más fácil renderizar la textura en el material.
Usar texturas con tamaño potencia de dos: 64px x 64px, 128px x 128px , 256px x 256px, etc. Facilita el procesamiento de la imagen y el juego tendrá mejor rendimiento.
Usar texturas con formato png hace que la imagen no pierda información aunque su tamaño sea mayor, además permite imágenes con transparencia (canal alfa). No es recomendable usar jpeg aunque ocupe menos espacio, ya que la imagen se degrada al redimensionarla. Recuerda que en Unity se puede utilizar muchos otros formatos como TGA (formato recomendado por Unity), PSD, TIFF, BMP, etc.
Para texturas que se usarán en superficies grandes hay que evitar texturas con costuras ya que se verán las uniones de la textura cuando se replique. Se puede añadir a nuestra búsqueda la palabra seamless (sin costura).
Seguimos con el ejercicio anterior y realizamos los siguientes pasos:
En la vista Hierarchy añadimos varios objetos Sphere y un objeto Plane.
En la vista Project creamos la carpeta Textures
Busca en Internet diferentes texturas. Puedes utilizar la plataforma Pixabay o páginas especializadas como 3D Textures.
Importa las texturas a la carpeta Textures.
Para asignar una textura a un objeto creado simplemente arrastra la textura al objeto en la vista Scene o bien en la vista Hierarchy si previamente ha sido seleccionada. Lo que ha hecho Unity es crear un material y asociar la textura a ese material. ¿Cómo podemos comprobar que esto es así? Comprueba cómo se ha creado un objeto shader dentro del objeto y cómo en la carpeta Materials (que previamente hemos creado) aparece el material que se ha asignado al objeto.
Cuando se aplican texturas hay propiedades que entran en juego como la forma en que se renderiza el material o RenderingMode:
Opaque: es el valor por defecto y sirve para objetos sólidos sin transparencia.
Cutout: es útil cuando ciertas partes de un objeto queremos que sean transparentes, por ejemplo un roto en una tela. Se hace uso del canal alfa para determinar un valor de forma que todos los píxeles de la imagen con un valor inferior al valor alfa indicado se vuelven invisibles.
Fade: se utiliza cuando queremos aplicar efectos del tipo FadeIn (aparecer poco a poco) o Fadeout (desaparecer hasta desvanecerse).
Transparent: se utiliza en materiales del tipo plásticos o cristales cuando se quiere aplicar transparencia a los objetos.
Otra propiedad importante es Tiling-Offset:
Tiling: indica el número de veces que queremos que se repita la textura. Se usa para aplicar texturas a suelos.
Offset: indica un desplazamiento de las texturas sobre el eje-x o eje-y para dar un aspecto diferente.
A continuación mostramos el ejemplo que hemos realizado en este apartado. En la imagen de la izquierda no se ha aplicado la propiedad Tiling y en la imagen de la derecha hemos puesto los siguientes valores: x(10) y(10).
Puedes consultar el siguiente enlace donde se muestra no sólo cómo aplicar una textura bidimensional a un objeto 3D como hemos hecho hasta ahora sino cómo crear texturas especiales a objetos más complejos como un avión, ejemplo que se muestra en el siguiente enlace:
Es una estructura que permite vincular la imagen con la textura a un polígono en el modelo. Cada vértice del polígono es asignado a un par de coordenadas 2D que definen qué parte de la imagen es mapeada. Estas coordenadas 2D se llaman UV, siendo U la coordenada que representa el eje horizontal y V la coordenada que representa el eje vertical. Los valores de UV están entre 0-1.
Un aspecto a tener en cuenta dentro de una escena es la iluminación que puede ser de dos tipos:
Directa: cuando proviene de una fuente de luz (una lámpara de techo, el sol o la luna). Por defecto nuestra escena tiene una luz directa llamada Directional Light o luz direccional. Este tipo de luz se usa en zonas exteriores o estancias grandes.
Indirecta: cuando la luz viene de otro objeto y se quiere iluminar una zona concreta de forma tenue (un foco en un falso techo). En este tipo de iluminación no se localiza de forma precisa el foco de luz.
¿Cómo conseguimos establecer el tipo de luz según la escena?
Modificando la propiedad Type de la luz. Consulta la documentación oficial de Unity donde podrás observar cuándo utilizar un tipo u otro en base al al tipo de luz que queremos crear.
Ya sabemos navegar por la escena de un videojuego, hemos añadido Gameobjects a una escena, les hemos dado una apariencia con las texturas y a través de un Componente le hemos dado un comportamiento. Cambiando las propiedades de un componente mediante la vista Inspector hemos definido ciertos comportamientos del objeto, por ejemplo, al añadir el componente Rigidbody a un objeto le hemos dotado de masa, de forma que comenzará a caer si está desplazado en el eje-y.
En este apartado aprenderemos a programar el comportamiento de los GameObjects, es decir, su función dentro del juego mediante scripts. Hay que tener claro que programar un juego no es lo mismo que programar una aplicación. Un juego lo que hace es ejecutar una serie de fotogramas por segundo de forma que pasan tan rápido que lo captamos como un movimiento, no somos capaces de ver la secuencia de imágenes, con lo cual a mayor número de fotogramas por segundo el juego tiene una mayor fluidez y suavidad.
Esta velocidad de frames se conoce comoFrame Rate y la velocidad por defecto en Unity es de 24 FPS. Por cada frame Unity ejecuta un bucle donde procesa toda la información de una escena. Utilizaremos los métodos de un script para especificar a Unity dentro de ese bucle lo que queremos hacer, para ello debe estar vinculado a un GameObject.
Unity soporta de forma nativa tres lenguajes UnityScript que es un lenguaje inspirado en la sintaxis de Javascript, Booque se basa en Python y C# que es un lenguaje orientado a objetos similar a Java o C++ y es el que utilizaremos.
Actualmente podemos utilizar varios editores, en nuestro caso utilizaremos Visual Studio Code de Microsoft que tiene soporte para Windows, macOS y Linux. También puede usar Visual Studio 2019 si se trabaja con Windows o macOs. También mencionamos el IDERider de JetBrains que se está situando como referente para trabajar en C#, y aunque no es gratuito, permite un período de prueba y licencia educativa gratuita con un correo oficial.
Para entender un poco el comportamiento del juego y cómo crear nuestro primer script vamos a escoger un proyecto que tenga una esfera que haremos rotar.
Volvemos a incidir que dentro del proyecto tenemos que tener una organización de carpetas, con lo cual en la vista Project, crearemos una carpeta llamada Scripts. Un script siempre va asociado a un GameObject al que queremos implementar una determinada lógica. Para ello podemos crear el script de dos formas:
En la carpeta Scripts, pulsamos el botón derecho y seleccionamos la opción Create > C# Script. Con esta opción posteriormente se debe asignar a un objeto. En nuestro ejemplo crearemos un script llamado MoveCube.
Seleccionar el objeto, y seleccionar el botón Add Component al final de la vista Inspector, y seleccionar New Script y el nombre del script.
El nombre de la clase debe coincidir con el nombre de archivo del script C# para que funcione.
Se puede definir el editor por defecto en Edit > Preferences > External Tools > External Script Editor de forma que cuando se pulse sobre el script en la vista Project se abre el editor asignado por defecto con el código del script.
Un objeto puede tener varios script y hay que tener en cuenta que se ejecutarán en orden, de arriba-abajo. Desde la vista Inspector podemos cambiar el orden.
A partir de este apartado aprenderemos a crear scripts y en ellos utilizaremos métodos que permiten mover, escalar o rotar objetos, responder a ciertos eventos del teclado o ratón, detectar colisiones, etc. Aunque en cada apartado te proponemos un ejemplo, en este tutorial de Unity podrás profundizar en todos los conceptos que veremos:
Cuando creamos un script por defecto tenemos el siguiente código:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class <strong>MoveCube</strong> : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
Analicemos el código en base al orden del código:
Espacio de nombres: las tres primeras líneas indican los espacios de nombres que se utilizan en el script. Las clases en Unity se estructuran en paquetes o espacio de nombres. Si usamos una clase y no se ha añadido su espacio de nombres obtendremos un error en la vista consola.
Declaración de clase: el nombre de la clase debe ser el mismo que el archivo que lo contiene y siempre hereda de la clase base MonoBehaviour. Gracias a esta herencia el motor de Unity tendrá en cuenta en el ciclo de ejecución los métodos de este script .
Método Star: este método será invocado antes del inicio del juego y es donde se deben inicializar las variables del script.
Método Update: este método se llama por cada fotograma del videojuego. Es en este método donde irá el código que moverá el objeto en tiempo de ejecución. Tal como hemos mencionado, si la velocidad de Unity es 25 FPS, este método será llamado 25 veces por segundo.
Cuando estamos programando es normal depurar. Para ello en Unity se utiliza la clase Debug que contiene entre otros métodos:
Log: manda un mensaje a la consola de Unity.
LogError: manda un mensaje a la consola precedido del icono de error.
LogWarning: manda un mensaje a la consola precedido del icono de advertencia.
Te proponemos que en el método Start() introduzcas el código siguiente:
if (_transform==null)
Debug.LogWarning("Soy una advertencia", _transform);
Y en el método Update() introduce la siguiente línea:
Debug.Log("Se ejecuta el método update");
Ejecuta el juego durante un periodo de tiempo y después páralo. Obtendrás una ventana similar a la siguiente imagen donde a la izquierda podemos ver 733 mensajes (número de veces que se ha ejecutado el método) y 1 mensaje Warning. Puedes seleccionar estos botones para ver o quitar un tipo de mensaje en concreto.
A la izquierda tienes una serie de opciones que te permiten limpiar la ventana como es Clear o bien Clear On Play que limpia automáticamente la pantalla al ejecutar el juego.
Cuando consultamos la documentación Scripting API de Unity en la parte de la izquierda de la documentación aparecen los espacios de nombres y las clases que contiene. Desde el Editor de Unity puedes acceder a esta ayuda en la opción Help > Scripting Reference.
Si hemos programado en un lenguaje orientado a objetos los elementos de programación nos serán familiares, aunque si consultas la documentación de Unity verás una nomenclatura diferente:
Al principio Unity a los métodos los llama funciones o Functions, puedes encontrar en la documentación que utilice ambos términos. Las funciones en Unity empiezan con una mayúscula.
Lo que conocemos como evento en Unity se llama Callback. Son métodos que el sistema llama de forma automática en todos los componentes del GameObject y ejecutará si existe como es el caso del método Start() y Update().
Las variables y funciones que han sido heredadas se llaman Inherited Members.
La ejecución de un script de Unity ejecuta una serie de funciones de eventos en un orden predeterminado, consulta el siguiente enlace donde podrás ver El ciclo de vida de un script. Si vamos a explicar las diferencias entre los métodos de inicialización y actualización:
La diferencia entre Awake() y Start() es que Start() sólo se llama si la instancia de script está habilitada. Es útil para ordenar la inicialización. Awake siempre se llama primero y en ella se deben inicializar las variables y declarar las referencias entre scripts. Y el resto de inicializaciones de los componentes se retrasa hasta que se inicia el script en su método Start(). Ambos métodos sólo se ejecutan una vez.
Update(), LateUpdate() y FixedUpdate(): LateUpdate() se llama después de que se hayan llamado todas las funciones Update() con lo cual es útil para realizar comprobaciones cuando todos los objetos han ejecutado su método Update(). FixedUpdate() Se llama cuando hay que repetir una operación siempre en un Frame Rate fijo, por eso lo usaremos con Rigidbody con el movimiento de objetos con física. Cuando agregamos una fuerza a un cuerpo rígido, la fuerza ha de ser la misma en cada frame. Y usaremos Update() en movimientos cinemáticos, sin física.
Para definir una variable basta definir su tipo y el identificador y posteriormente asignar un valor. Hay algunas peculiaridades del lenguaje a tener en cuenta:
Algunos tipos requieren un modificador para especificar el tipo como es el caso de float donde se debe añadir una F mayúscula o f minúscula al final del número.
lives=3
distance=8.75F
Por defecto una variable en Unity es pública a menos que se especifique que debe ser privada mediante el modificador private. Cuando una variables es pública se puede ver y editar en la vista Inspector y puede ser accedida desde cualquier script y desde cualquier otra clase. Esta característica hay que tenerla en cuenta y valorar la visibilidad de una variable. Cuando una variable es privada el mantenimiento y el código es más sencillo, ya que nos aseguramos que sólo la propia clase puede modificar su variable.
A continuación vamos a ver cómo se puede acceder a un componente dentro del mismo GameObject de forma que podremos modificar los valores de las propiedades que se han establecido en la vista Inspector mediante la función GetComponent<T> donde T es el tipo de componente. Esta función permite obtener la instancia del componente en el juego y modificar su valor.
Así vamos a modificar el scriptMoveCube.cs, para que mueva el cubo a la izquierda un valor que hemos definido en una variable:
using UnityEngine;
public class MoveCube : MonoBehaviour
{
public float x = 0.02F;
// Start is called before the first frame update
private Transform _transform;
void Start()
{
_transform = GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
_transform.Translate(x,0,0);
//transform.Translate(x,0,0);
}
}
Como comentario se ha puesto cómo se puede acceder de forma directa al componente Transform mediante el objeto transform que ya existe en la instancia del GameObject.
En un juego puede haber diferentes tipos de entrada según la plataforma en la que se juegue. Los dispositivos de entrada más comunes son el ratón, teclado o joysticken un PC y el mando o gamepad en el caso de una consola. Pero no nos podemos olvidar de los móviles, donde tenemos una pantalla táctil o sensores como el acelerómetro.
¿Qué hace Unity para detectar la entrada según el tipo de dispositivo?
Pues ha declarado un conjunto de ejes (Axes) que utilizan los script para comprobar la tecla o el botón pulsado. Posteriormente se asocian estos ejes a los diferentes dispositivos a través de la opción Edit > Project Settings... > Input Manager:
Esta opción permite tanto consultar como modificar los ejes que vienen por defecto en un proyecto. Si se quiere añadir un nuevo eje basta con aumentar en 1 el valor de Size. Verás cómo se ha añadido un nuevo eje (por defecto se crea un duplicado del último elemento de la lista) de forma que mediante la propiedad Name puedes ponerle un nombre al eje personalizado.
Cada nombre usado en el administrador de Input (Input Manager) es un identificador que tiene asociado una o más teclas y que devuelve los valores: 1, 0 o -1 dependiendo de la tecla que tenga asignada en Negative Button y Positive Button. Consulta la Documentación oficial de la clase Input para ver otras propiedades que se pueden modificar.
Entre las opciones que se crean por defecto destacamos las siguientes:
Eje horizontal: para el valor negativo (tecla a o flecha ← ), para el valor positivo (tecla d o flecha →).
Eje vertical: para el valor negativo (tecla s flecha ↓), para el valor positivo (tecla w o flecha hacia arriba↑).
Fire1, Fire2 y Fire3: están asignadas a las teclas Ctrl (lado izquierdo), Alt y Command respectivamente.
Mouse X y Mouse Y: están asignados al movimiento de un Joystick. Si Mouse X es -1 significa que mueves el Joystick hacia la izquierda y si Mouse Y es 1, es que mueves el Joystick hacia delante.
Veremos a continuación algunos de los métodos más frecuentes de la clase Input aunque puedes consultar laAPI de la clase Input.
Para consultar el estado actual de un eje en un script utilizamos el método GetAxis() que recibe por parámetro una cadena que ha debido ser definida en el administrador de Input.
value = Input.GetAxis ("Horizontal");
Para consultar si se ha pulsado una tecla usamos el método GetKey() como el resto de métodos que gestionan la pulsación de una tecla tiene como parámetro una cadena. Esta cadena sólo admite letras en minúscula "a","e","space" etc. Si introducimos un parámetro incorrecto nos dará error por eso recomendamos el uso de la enumeraciońKeyCode que contiene una lista con los nombres que se han asignado a las teclas.
if (Input.GetKey(KeyCode.Space)){
.....
}
Finalmente para saber si se ha presionado uno de los botones del ratón se recibe un valor de tipo int en el método GetMouseButton(): botón izquierdo (código 0), botón derecho (código 1) y central (código 2):
if (Input.GetMouseButton(0)){
.....
}
En este enlace puedes ver otros métodos que ofrece la clase Input para la Captura de Movimientos en base al dispositivo.
Para asignar una tecla a un eje debes conocer la nomenclatura utilizada que puedes consultar en el apartado Teclas dentro de la Documentación oficial en la clase Input.
Ana ha aprendido a asignar materiales y texturas a los objetos y a realizar una correcta iluminación de una escena. Se ha puesto a crear los personajes y editar su diseño.
Mientras tanto Juan ha estado investigando cómo añadir lógica a los personajes mediante el lenguaje script. Después de documentarse descubre que hay varias formas de animar un objeto y se pone de acuerdo con Ana para animar los personajes. ¿Cómo?
Se llama movimiento cinemático de un objeto cuando cambia de posición, tamaño o bien rota mediante programación. Es el programador mediante un script quien controla su cambio en cada refresco de pantalla o frame mediante métodos de clase Transform y las siguientes propiedades:
position para cambiar la posición.
localScale para cambiar la escala.
rotation para cambiar la rotación.
Cuando un personaje se mueve, cambia de tamaño o rota porque el jugador ha pulsado una tecla o bien se ha pulsado un botón, y nosotros tenemos que programar ese movimiento, se llama cinemática. Otro ejemplo son los juegos arcade como el pacman o galaxian donde desplazamos un objeto en una dirección.
¿Cuándo hablamos de un movimiento físico?
Este movimiento no está directamente controlado por nosotros, es el resultado de diferentes fuerzas que se aplican sobre un objeto. Es el motor de físicas quien controla el resultado final del movimiento. Nosotros podemos lanzar un objeto contra otro en un script, pero el resultado final de esta colisión nosotros no lo controlamos, será el motor de físicas quien tendrá en cuenta la velocidad y aceleración nuestro objeto, el movimiento resultante de la colisión en base a si estaba parado o en movimiento, el resultado del impacto en un objeto deformable, etc. Este comportamiento se aplica a los objetos mediante el componente Rigidbodyque ya hemos visto y que estudiaremos en profundidad más adelante.
Vamos a centrarnos en el caso de movimiento cinemático, es decir, cuando nosotros controlamos exactamente la posición, la escala y la rotación. Para cada uno de estos movimientos explicaremos un conjunto de clases que necesitamos para realizar el movimiento como Vector3, Quaternion o Mathf.
Todos los movimientos los gestionaremos dentro del método Update() y utilizaremos los métodos de las clase Input para realizar el movimiento.
Crearemos un proyecto con una esfera y queremos que se mueva en el eje horizontal cuando se pulsa una de las flechas para ello creamos un script asociado a la esfera.
Para realizar un desplazamiento de un objeto utilizamos el método Translate(), una traslación en metros que es la unidad que se utiliza en Unity.
Cuando pulsamos una flecha o tecla asignada al eje horizontal se mueve un metro por frame. Este desplazamiento es muy grande, con lo cual se puede disminuir la velocidad multiplicando el primer valor por un valor mayor a 0 y menor a 1:
Recuerda que si el valor es negativo se invierte el sentido
Lo correcto es poder modificar este valor en diseño, con lo cual vamos a declarar una variable pública de tipo float llamada velocity y asignaremos el valor en la vista Inspector. Además svamos a mover el objeto también en el eje-y, así que lo haríamos de la siguiente forma:
Tal como lo hemos hecho ahora, la velocidad está relacionada con el tiempo que tarda el frame. Esto nos puede dar problemas de rendimiento ya que depende del dispositivo y del hardware subyacente. Lo ideal sería que los objetos de una escena se muevan a un ritmo constante en base al tiempo. Para ello utilizaremos la clase Time que controla los frames por segundo mediante la propiedad deltaTime.
Time.deltaTime representa el tiempo en segundos que tardó en completarse el último frame, es decir el tiempo entre cada frame. ¿Te acuerdas qué era Frame Rate? Efectivamente Frame Rate es el número de frames por segundo, y es la capacidad de nuestro juego para refrescar la pantalla por segundo. Este valor puede variar entre dispositivos, ya que el hardware de un móvil no supera la potencia de una consola o un PC. Además dentro de un juego podemos encontrarnos una escena completa donde haya muchos personales, scripts y componentes actuando, con lo cual el tiempo en procesar un frame puede variar. Teniendo en cuenta estas circunstancias para los movimientos se debe utilizar metros por segundo.
Teniendo en cuenta ambos conceptos podemos decir:
FPS = 1/Time.deltaTime
O bien:
Time.deltaTime = 1/FPS
Por tanto si el FPS en un dispositivo es 60, es decir, 60 frames en un segundo, el tiempo para cada frame es 0.016666666 segundos, como se explicó anteriormente, por tanto la distancia que se mueve el objeto en 1 sg es 1 unidad (0.0166666 * 60 frames). Si el FPS es 30, es decir, 30 frames en un segundo, el tiempo para cada frame es 0.03333 sg. La distancia recorrida por el objeto en 1 segundo es 1 unidad (0.03333 * 30 frames). Al final, el objeto se mueve la misma distancia independientemente del rendimiento del dispositivo.
De forma que si queremos que un objeto se mueva una distancia en metros por segundo será lo mismo que multiplicar por Time.deltaTime
Nuestro sistema de referencia está constituido por tres ejes perpendiculares entre sí (ejes XYZ) . La posición, la escala y la rotación de un objeto se basa en este sistema, ya que se asigna un valor a cada eje. Teniendo en cuenta estos valores, se puede usar su vector posición para realizar movimientos del objeto. El vector posición de un objeto respecto a un sistema de referencia se define como el vector que une el lugar ocupado por el cuerpo con el origen del sistema de referencia.
La unidad de medida de la posición y tamaño en el Sistema Internacional es el metro (m) y los grados (º) en las rotaciones.
En cinemática para realizar un movimiento se utilizan los vectores, ya que la posición no sólo se define por un número omódulo del vector ), sino que tiene dirección y sentido, por eso se dibujan con una flecha. Son vectores las fuerzas, la aceleración, la velocidad, etc.
En Unity la forma de representar un vector tridimensional es la clase Vector3. Esta clase contiene tres propiedades (X, Y, Z) y se puede inicializar usando alguno de los constructores que puedes consultar en la Documentación oficial de Unity.
Esta clase contiene una serie de constantes estáticas que hacen referencia a los vectores tridimensionales más usuales:
Constantes estáticas de la clase Vector3
Constante
Valor
Vector3.zero
(0,0,0)
Vector3.one
(1,1,1)
Vector3.right
(1,0,0)
Vector3.up
(0,1,0)
Vector3.forward
(0,0,1)
Vector3.left
(-1,0,0)
Vector3.down
(0,-1,0)
Vector3.back
(0,0,-1)
Esta clase tiene ciertos métodos que permiten desplazar un objeto:
Lerp: desplaza un objeto desde una posición a otra con velocidad desacelerada.
MoveTowars: desplaza un objeto desde una posición a otra con una velocidad constante.
El movimiento de un objeto lo establecemos en base a una cantidad (magnitud del vector) y una dirección (vector normalizado). En base al tipo de movimiento podemos usar una clase Vector:
Vector1: tiene una dirección 1D, es un punto en una línea. Por ejemplo pasamos de (0) o (50). La magnitud de un Vector1 es igual al valor absoluto de la componente x del vector o sqrt (x ^ 2)
Vector2: tiene una dirección 2D, como un punto XY en un espacio 2D o bien la posición de un joystick. Por ejemplo el punto (0,0) o (1, 100). La magnitud de un Vector2 es igual a sqrt (x ^ 2 + y ^ 2).
Un Vector3 tiene una dirección 3D, como un punto XYZ en un espacio 3D, o un color en formato RGB, o un conjunto de tres números. p.ej. (0,0,0) o (-0.1, 3.14, 30). La magnitud de un Vector3 es igual a sqrt (x ^ 2 + y ^ 2 + z ^ 2).
Al aplicar una fuerza por ejemplo a un objeto 2D utilizaremos el Vector2 aunque como ya hemos comentado el estudio lo realizaremos para objetos 3D.
En este apartado vamos a realizar una serie de ejemplos donde modificaremos la propiedad position de un objeto utilizando un objeto Vector3. Pero llegado a este punto vamos a explicar la opción Local/Gobal de la barra de herramientas de la escena ya que afecta al movimiento de un objeto según el sistema de referencia que esté seleccionado:
Global: el sistema de referencia es el de la escena con origen en (0, 0) y es común a todos los objetos.
Local: cuando hablamos de un eje local, es que un objeto pasa a ser el sistema de referencia de otro. Lo vemos con un ejemplo, tenemos el objeto A (0, 4) y el objeto B (3,1). Si tomamos el objeto B como referencia del objeto A, esto es que B pasa a ser el eje de coordenadas (0,0) y A tomaría las coordenadas (-3,3). Como ves la posición de A es diferente en base al sistema de referencia que se utilice.
Lo tendremos en cuenta porque a veces nos interesará hacer una traslación de un objeto cambiando el sistema de referencia. De momento entendemos que el sistema de referencia es Global.
En este ejemplo queremos desplazar el objeto en el eje-x una serie de metros. Para ello utilizaremos el producto escalar de un número por un vector. En el siguiente ejemplo se realizará el movimiento cuando pulsamos la tecla "space" y como queremos que se desplace por el eje-x utilizamos Vector3.right:
if (Input.GetKey(KeyCode.Space)) {
transform.position = Vector3.right * _positionX;
}
Como puedes ver la nueva posición del objeto es (5,0,0), resultado de multiplicar el vector (1,0,0) por 5.
Lo ideal será desplazar un objeto desde su posición a otro punto a una segunda posición. A este movimiento de le puede aplicar una velocidad constante utilizando Vector3.MoveTowards, o bien una velocidad desacelerada con Vector3.Lerp.
if (Input.GetKey(KeyCode.Space)) {
transform.position = Vector3.MoveTowards(transform.position, new Vector3(10, 5, 5), _velocity);
}
Estos métodos lo que hacen es calcular una serie de puntos partiendo de un origen para llevar el objeto al punto destino, esto se conoce como interpolación. A medida que mantenemos la tecla space pulsada el objeto va desplazándose.
A veces necesitamos de ciertas acciones que no nos ofrece la clase Vector3 y debemos usar la clase Mathf que contiene una serie de métodos interesantes que puedes consultar en la Referencia de la clase Mathf. Entre los métodos que hacen referencia al movimiento de un objeto están:
Lerp: hace la interpolación lineal entre el punto origen y destino en el tiempo t.
PingPong: genera un valor x que nunca es mayor al valor máximo y nunca menor a 0. Este método es útil para crear un movimiento ida y vuelta al punto origen.
Clamp: devuelve un valor que se encuentra dentro de un rango establecido por un mínimo y máximo. Si el valor está fuera del rango, devuelve el valor del límite máximo próximo. Este método es útil para saber si un objeto controlado por teclado ha llegado a uno de los límites del movimiento.
Vamos a escoger una esfera y vamos a moverla usando las flechas derecha e izquierda en el eje-x entre unos límites, por ejemplo [-10,10]:
public class MoveCubeClamp : MonoBehaviour
{
// Start is called before the first frame update
public int limitMin = -10;
public int limitMax = 10;
public float velocity = 0.1F;
private float _value;
void Start()
{
}
// Update is called once per frame
void Update()
{
_value += Input.GetAxis("Horizontal") * velocity;
_value = Mathf.Clamp(_value, limitMin, limitMax);
transform.position= new Vector3(_value,0.5F,-2);
}
}
Por último veremos cómo escalar o cambiar el tamaño de un objeto en base al componente Transform y su propiedad localScale. Partiendo de su tamaño original cuando pulsemos una tecla le sumaremos un Vector3 para cambiar el tamaño del objeto en uno de sus ejes.
También haremos uso de la clase Random para escoger un valor dentro de un rango posible utilizando el método estático Range que devuelve un número flotante aleatorio entre un valor mínimo y máximo, ambos inclusive.
if (Input.GetKey(KeyCode.T))
{
transform.localScale= new Vector3(Random.Range(0.2F,5.0F),1,Random.Range(0.2F, 5.0F));
}
Vamos a echarle imaginación, y vamos a pensar en un esfera en la que clavamos una varilla que pasa por su centro. Vamos a realizar un giro en sentido horario. En base a esta imagen vamos a explicar los parámetros que participan en una rotación:
Eje de rotación: está claro que es la varilla.
Cantidad de ángulos a girar: se expresa en grados. Si he girado la mitad de la espera la cantidad en ángulos sería 180º.
Sentido de giro: ha sido horario, es decir en el mismo sentido que las agujas de un reloj.
De igual forma que explicamos que el sistema de referencia es importante en las traslaciones, en las rotaciones es importante el eje de rotación que puede ser Pivot/Center situado en la barra de herramientas de la escena:
Center: un objeto rota en base a su centro. es decir (0,0,0) en el espacio del mundo.
Pivot: en base a un componente Pivot de un objeto o imagen.
De nuevo contaremos con una estructura de datos para gestionar la rotación de un objeto que tiene cuatro coordenadas: X, Y, Z y W y en Unity se llamaQuaternion o cuaternos. Esta última coordenada no se encuentra en la vista Inspector pero existe y es su orientación en el espacio. Esta orientación es fundamental en la rotación de un objeto. Evidentemente parece complicado, pero lo bueno es que la clase Quaternion nos ofrece una serie de funciones que nos permite crear, manipular y concatenar varias rotaciones sin aprender el cálculo matemático.
Podemos modificar la propiedad rotation de un objeto mediante el método estático Euler de la clase Quaternion:
transform.rotation= Quaternion.Euler(30, 10, 0);
Si queremos que un objeto gire a una velocidad constante en base a uno de sus ejes se puede utilizar la clase Vector3 ya que la orientación, componente W, no influye. Usamos Time.deltaTime para que se base en el tiempo y no en base al refresco de pantalla.
Para ver que la esfera está girando, cuando ejecutes el juego, visualiza la vista escena y selecciona la esfera verás como gira sobre su eje-y 30º. Prueba a realizar la rotación en su eje-x y en su eje-z.
Otro método interesante es RotateAround donde un objeto rota al rededor del punto central de otro objeto. Podemos hacer que una esfera rote alrededor de un cubo con el siguiente código:
public GameObject objectPivot;
public float velocity;
................
void Update() {
transform.RotateAround(objectPivot.transform.position, Vector3.up, velocity);
}
Para que este ejemplo funcione tienes que inicializar la variable objectPivot en la vista Inspector y escoger un objeto de la escena como muestra la imagen.
Entender los cuaternos es complicado, te proponemos que realices el Taller de Unity Cuaternos que te guiará en un ejemplo. El vídeo está subtitulado en "español latino" para ello pulsa en Configuración > Subtítulos > Español Latinoamérica.
Juan ha terminado de ver los movimientos cinemáticos y se da cuenta que hay mucho por aprender, ya que el juego que deben realizar necesita del motor de físicas para simular las colisiones, caídas, etc. Lejos de estar cansado está cada día más ilusionado viendo el potencial de Unity para construir un juego.
En Unity hay dos motores de física separados para juegos 3D que es PhysX de Nvidia y Box2D que se ha desarrollado en C++ y se distribuye bajo la licencia zlibque es una licencia de software libre. Ya hemos planteado un ejemplo donde se ha aplicado física y lo único que hemos hecho es añadir a un objeto el componente Rigidbody y ya está sometido al movimiento que pueda inducirse por una de las acciones del motor físico y que estudiaremos en este apartado.
Otro componente que estudiaremos será Collider para ver cómo un objeto responde a un rebote y otros efectos producidos por las colisiones entre objetos.
El comportamiento de ambos motores físicos es configurable desde el menú:
Edit > Project Setting > Physics para la física 3D
Edit > Project Setting > Physics 2D para la física 2D
Puedes consultar el apartado Visión General de la Física de la documentación oficial de Unity que te expone los aspectos más importantes a tener en cuenta en la simulación del mundo real gracias a la física.
Un componente Rigidbody se puede modificar a través de la vista Inspector o bien mediante un script. Mediante este componente añadimos el comportamiento físico a un objeto: tiene masa, está afectado por la gravedad, puede colisionar con otros objetos, se le puede ejercer una fuerza, tiene un coeficiente de rozamiento, puede tener velocidad, etc. Algunas propiedades son las siguientes:
Mass: masa en kilogramos.
Drag: resistencia al aire cuando nos movemos de forma lineal. Si se establece a 0 es que no hay resistencia.
Angular Drag: resistencia al aire mientras el objeto gira.
Use Gravity:si está afectado por la gravedad. Ten en cuenta que a veces en los juegos hay una serie de objetos que están flotando.
Is Kinematic: si ésta opción está seleccionada el objeto deja de estar influido por la física y pasa a tener un comportamiento cinemático.
Si un objeto tiene un comportamiento físico no se debe usar el componente Transform, si no que su movimiento dependerá del motor de física.
Este componente también es importante cuando estamos en movimiento cinemático, ya que en el caso de querer detectar una colisión entre dos objetos se necesita por un lado que los dos objetos tengan el componente Collider, pero obligatoriamente uno de ellos tiene que tener un componente Rigidbody para que la colisión se detecte. De ahí la propiedad Is Kinetic. Gestionar esa colisión dependerá de nosotros y no del motor de física. Si bien no es recomendable cambiar el valor Is Kinetic desde código por la carga de rendimiento que supone.
Aunque no se estudie en este curso existe la posibilidad de unir GameObject a través de juntas o uniones llamadas Joints. Este componente es fundamental para el correcto funcionamiento de los objetos por el motor físico.
En código podemos acceder al componente Rigidbody de un objeto de la siguiente forma:
Si el movimiento depende del motor físico ¿cuándo se considera que un objeto está parado?
Cuando un objeto se mueve o rota a un valor menor establecido en Edit > Project Setting > Physics > Sleep Threshold el motor de física entiende que está parado y deja de actuar la física en él. Se dice que el objeto está dormido osleeping. La mayoría de las veces el cambio de estado de un objeto es transparente al desarrollador, pero se puede despertar al objeto mediante el método WakeUp() y volver a dormir mediante el método Sleep().
Finalmente si realizamos cambios en un Rigidbody hay que utilizar el método FixedUpdate() ya que a diferencia de Update():
FixedUpdate() siempre es llamado en el mismo intervalo de tiempo (por defecto 50 veces por segundo). El método Update() depende del rendimiento y puede variar de un frame a otro.
Si se ha realizado un cambio en el componente RigidBody que implique un cálculo en la física se realiza inmediatamente.
Para mover un objeto mediante la física se le debe aplicar una fuerza a su componente Rigidbody. Para ello utilizaremos el método AddForce(). La opción más simple es pasar por parámetro un Vector3 y utilizar el segundo parámetro para indicar el tipo de fuerza en base a una enumeración de ForceMode:
Force: se aplica una fuerza continua teniendo en cuenta la masa del objeto.
Acceleration: se aplica una aceleración ignorando su masa.
Impulse: se aplica una fuerza instantánea, es un golpe puntual considerando su masa.
VelocityChanged: Se aplica una velocidad instantánea pero ignorando la masa.
Vamos a establecer una fuerza a una esfera utilizando las flechas. La fuerza será continua y realizaremos el movimiento en el eje-x y en el eje-z. Para ello creamos un proyecto que tenga un plano para el suelo y una esfera. Creamos el script con nombre ExampleAddForce y se lo añadimos a nuestra esfera:
public class ExampleAddForce : MonoBehaviour
{
public Rigidbody rg;
public float velocity=50F;
void Start(){
rg = GetComponent<Rigidbody>();
}
void Update(){
}
private void FixedUpdate()
{
Vector3 force = new Vector3(Input.GetAxis("Horizontal") * Time.deltaTime * velocity,
0, Input.GetAxis("Vertical") * Time.deltaTime * velocity);
rg.AddForce(force);
}
}
Vemos que la esfera se desplaza por el plano y se mueve en el eje correspondiente según la tecla que hemos pulsado. Pero al ser una esfera ¡lo hace rotando! El desplazamiento lo realiza el motor de física en base a las propiedades del objeto Rigidbody. Vamos a realizar varias modificaciones al juego:
Si queremos que la esfera no rote, tenemos que modificar la propiedad freezeRotation a true. Intenta ejecutar el juego. ¿No se desplaza, verdad? Esto se debe a que la fuerza que tenemos que realizar para desplazar el objeto es mayor. Modifica el valor de la velocidad por ejemplo a 500F.
Disminuye la masa del objeto, por ejemplo a 0.5 verás como el objeto se desplaza a doble de velocidad.
Modifica el rozamiento de la esfera con el plano y modifica la propiedad Drag a 1, de nuevo la esfera cuesta moverla y se detiene antes.
Para realizar una fuerza de tipo impulso vamos a usar igualmente el método AddForde() pero vamos a cambiar el método donde realizar la fuerza. Para las fuerzas constantes hemos usado el método FixedUpdate(), sin embargo en aquellas que son del tipo impulso son fuerzas que no son constantes en el tiempo, sino que se aplica en un momento concreto es por ello que utilizaremos el método Update().
En este caso le aplicaremos una fuerza de impulso a la esfera del proyecto que hemos creado anteriormente cuando se pulse la tecla virtual "Jump" que está asociada a la tecla space. En ejemplos anteriores hemos usado GetButton() pero en este caso concreto usaremos GetButtonDown() ya que este método sólo devuelve true en el momento de ser pulsada la tecla, no queremos mantener el impulso durante el tiempo que la tecla esté presionada.
public float impulse = 2F
.........................
void Update()
{
if (Input.GetButtonDown("Jump"))
rg.AddForce(Vector3.up*impulse,ForceMode.Impulse);
}
Podemos comprobar que mientras la esfera está en el aire y damos de nuevo en la tecla de la barra espaciadora se genera un segundo salto, y esto no es real. Tenemos que comprobar si la esfera está en el suelo para poder lanzar otro salto. Para ello nos fijaremos en la propiedad velocity del componente Rigidbody que es positiva mientras la esfera asciende y es negativa mientras la esfera cae, con lo cual comprobaremos que el valor absoluto de la velocidad sea menor a un umbral que fijamos por ejemplo a 0.01F. Para ello usaremos el método estático Mathf.Abs. Esta condición sólo se cumple dos veces cuando está en lo más alto y cuando está en el suelo, que se cumpla la primera cuando demos a la tecla Jump es altamente improbable.
if (Input.GetButtonDown("Jump") && Mathf.Abs(rg.velocity.y)<limitJump)
Como ya se ha comentado, cuando usamos la física sobre un objeto se debe usar su objeto Rigidbody. Para realizar una traslación usaremos Rigidbody.position que permite obtener y establecer la posición. Para establecer su posición haremos uso de la clase Vector3 y sus funciones.
El cambio de posición es inmediato, no se hace de forma progresiva.
Comprueba el siguiente script donde cambiamos la posición de un objeto al pulsar la tecla "space".
public float x = 0F;
public float y = 0F;
public float z = 5F;
....................
void FixedUpdate()
{
x = GetComponent<Rigidbody>().position.x;
y = GetComponent<Rigidbody>().position.y;
if (Input.GetKey(KeyCode.Space))
GetComponent<Rigidbody>().position= new Vector3(x,y,z);
}
Otro ejemplo es realizar un desplazamiento del objeto desde un punto origen a un destino mediante el método MovePosition(). En este caso sí se mueve de forma lineal el objeto pero si hay algún objeto en el camino se ignora. Vamos a tomar como ejemplo dos cubos que están distanciados en una escena. Uno de ellos se desplazará hasta la posición del segundo cubo que llamamos target.
Recuerda que debes inicializar el objeto target en la vista de Inspector.
public class MovePosition : MonoBehaviour
{
public float movementSpeed = 5f; //for instance
public Rigidbody rg;
public GameObject target;
void Start()
{
rg = GetComponent<Rigidbody>();
}
void Update()
{
Vector3 direction = (target.transform.position - transform.position).normalized;
rg.MovePosition(transform.position + direction * movementSpeed * Time.deltaTime);
}
}
Para entender las diferencias entre un movimiento a través de la cinemática o bien a través de la física te recomendamos el siguiente vídeo. Pulsa sobre el botón Configuración > SubTítulos > Inglés (Generados Automáticamente). Una vez hayas realizado esta modificación vuelve a realizar la misma operación pero selecciona Traducción automática> Español para que además realice la traducción y puedas leer las explicaciones del autor.
Ya vimos cómo para las rotaciones el uso de los cuaternos oQuaternion (x,y,z,w) es la solución a usar. Aunque su funcionamiento nos parezca más complicado al final usaremos sus funciones, que harán el trabajo por nosotros:
Quaternion.Euler: método que pasa la rotación a tres dimensiones o ángulo de Euler.
Quaternion.LookRotation: este método toma una dirección como parámetro. Una dirección puede considerarse la ruta recta desde 0,0 hasta la posición final del vector. También se conoce como la posición relativa. Así que por ejemplo el código Quaternion.LookRotation(target.position) está calculando la dirección desde el origen del mundo (0,0,0) hasta target.position.
Quaternion.Angle: devuelve el ángulo en grados entre dos rotaciones a y b. Las rotaciones se suelen hacer entre dos planos por ejemplo el plano X-Z e X-Y.
Quaternion.Slerp: interpola entre las orientaciones, representadas como cuaternos, usando la interpolación lineal esférica.
Quaternion.FromToRotation: creará un cuaternio de rotación que transformará el vector1 (su primer parámetro) en el vector2 (segundo parámetro).
Y utilizaremos la variable de clase:
Quaternion.identity: que es el equivalente a no rotación con el valor (0,0,0,1)
Para entender la rotación en física vamos a utilizar un proyecto que tenga una esfera y dos objetos hijos, en concreto cilindros, a modo de nariz para comprobar las rotaciones: uno rojo para la X y otro verde para la Y. Los pasos que hemos realizado son los siguientes:>
Se ha creado tres tipos de materiales y se han asignado a sus correspondientes objetos.
Se ha creado un componente Rigidbody para la esfera donde indicamos que no esté afectado por la gravedad.
Se han creado los cilindros con los siguientes parámetros:
Objeto, escala y rotación usados
Objeto
Escala
Rotación
Eje-X
(0.2,0.1,0.2)
(0,0,-90)
Eje-Y
(0.2,0.1,0.2)
(0,0,180)
Se ha asignado los dos objetos Eje-X y Eje-Y como hijos de la esfera. Para ver cómo se visualiza y se crea un objeto hijo consulta la documentación oficial de UnityCreando un objeto hijo.
Vamos a crear una rotación de la esfera, y de los hijos que contiene, utilizando la tecla "space". Creamos el siguiente script:
En este vídeo podrás ver la correlación entre ángulos Euler y un cuaternio. Además pone un ejemplo de cómo realizar una rotación mediante el método Slerp. Pulsa sobre el botón Configuración > SubTítulos > Inglés (Generados Automáticamente). Una vez hayas realizado esta modificación vuelve a realizar la misma operación pero selecciona Traducción automática> Español para que además realice la traducción y puedas leer las explicaciones del autor.
Rotar un objeto mediante el método Slerp de un cuaternio.
Cuando un objeto tiene el componente Collider es un objeto sólido que detecta las colisiones. Cuando este componente no está acompañado de Rigidbody estamos hablando de un objeto totalmente estático, con el cual podrá colisionar, rebotar pero el objeto permanecerá inmóvil en la escena. Se suele crear para definir el suelo, paredes y techos y tenemos que indicarlo al motor de física marcando la casilla Static como muestra la imagen.
Por el contrario cuando tiene un componente Rigidbody el objeto es dinámico y se conocen como dynamic colliders.
En base a lo ya explicado podemos concluir que hay tres tipos de cuerpos con Collider:
Estático -> No tiene Rigidbody.
Dinámico -> Tiene Collider y Rigidbody isKinematic = false.
Cinemático -> Tiene Collider y Rigidbody isKinematic = true.
Por tanto tenemos que tener clara la siguiente regla:
Sólo se detectará la colisión cuando al menos uno de los objetos sea dinámico o bien no se detectará la colisión entre cuerpos cinemáticos o estáticos
Para detectar una colisión sólo tenemos que sobrescribir una de las funciones evento:
OnCollisionEnter: se ejecuta cuando un objeto entra en colisión con otro objeto.
OnCollisionStay: se ejecuta mientras un objeto está en colisión con otro objeto.
OnCollisionExit: se ejecuta cuando el objeto deja de estar en colisión con otro objeto.
void OnCollisionEnter(Collision col) {
Debug.Log(col.gameObject.name + " ha colisionado con " + this.name);
}
Nos queda por averiguar cómo detecta el motor de física la colisión entre dos objetos. Esto se debe a que cada objeto tiene un área que lo envuelve. Si te das cuenta cuando hemos añadido un objeto primitivo se ha creado con uno de los tipos de Collider básicos:
Box Collider: para los cubos (Cube).
Sphere Collider:para las esferas (Sphere).
Capsule Collider: para las cápsulas (Capsule) y cilindros (Cilinder).
Hay que tener en cuenta que cuanto más complejo sea un Collider más recursos consume. Algunos más sofisticados son:
Mesh Collider: construye su Collider usando la malla o Mesh del objeto. La colisión será más precisa a costa del rendimiento del sistema.
Wheel Collider: usados para los vehículos en movimiento.
Terrain Collider: manejan las colisiones entre terrenos.
Puedes consultar el siguiente enlace donde podrás ver los diferentes tipos de Collider sobre una misma imagen:
Una malla poligonal o mesh no es más que una serie de vértices relacionados entre sí formando triángulos, con una serie de propiedades como coordenadas de textura o vectores normales. La mayoría de elementos y personajes que pueblan las escenas de un videojuego son mallas poligonales formadas por conjuntos de triángulos.
Vamos a comprobar la teoría con un ejemplo práctico donde vamos a crear tres esferas y un plano. A cada esfera le vamos a poner un icono tal como muestra la imagen: a la primera esfera la llamaremos Estatica y se deja tal cual. A la segunda le llamamos Cinematica y activamos su propiedad Is Kinematic y a la tercera la llamamos Dinamica y le añadimos el componente RigidBody.
Ya hemos visto que cuando se produce una colisión el motor de física llama a funciones OnCollisionEnter(Collider other), OnCollisionStay(Collider other), OnCollisiionExit(Collider other) que se hayan implementando en cualquier script adjunto a los objetos involucrados. Estos métodos tienen como parámetro un objeto Collider que contiene datos del evento:
other: es el colisionador con el que hemos colisionado. Podemos obtener el nombre de dos formas:
En el ejercicio que te proponemos vamos a utilizar las etiquetas o Tag para referenciar a uno o más GameObject de forma que podemos tener una colección de objetos y realizar una operación de control por ejemplo averiguar si el personaje está interactuando con un enemigo. Consulta el siguiente enlace para ver cómo Crear y utilizar las etiquetas en un proyecto.
Se puede crear una etiqueta desde la ventana en Edit> Project Settings... > Tags an Layers o bien en la vista Inspector de un objeto seleccionamos la propiedad Tag y nos aparece un desplegable con las opciones por defecto y escogemos la opción Add Tag...
Una vez que se ha creado aparece como opción en el desplegable y se selecciona en nuestro caso Enemy.
Aunque se puede acceder a la propiedad tag de un objeto, hay que tener en cuenta que se trata de cadenas y utilizar el operador == para comparar cadenas sobrecarga al recolector de basura o Garbage Collector, es por ello que usaremos el método CompareTag().
Vamos a crear un proyecto que cumpla los siguientes requerimientos:
Vamos a crear una plano, una esfera y un cubo que copiaremos hasta tener en total de cuatro.
Vamos a mover la bola con las flechas.
Dos cubos serán enemigos o Enemy.
Creamos un script CollisionSphere.cs que asignamos a la esfera donde tenemos que comprobar si el cubo con el que hemos colisionado es un enemigo. Ten en cuenta que si lo hacemos por nombre tendríamos tantos if como objetos que controlar por el nombre, en este caso sólo tenemos un if ya que comprobaremos que el Tag sea Enemy.
Si la magnitud de la velocidad relativa es mayor a un valor destruimos el cubo y si es menor lo pintamos de color rojo.
Destroy(other.gameObject);
//O bien
other.gameObject.GetComponent<MeshRenderer>().material.color = Color.red;
A veces nos interesa detectar si un objeto entra en en una zona determinada o bien si un objeto entra en contacto con otro. Para ello debemos indicar que el componente Collider se comportará como un trigger o disparador activando su propiedad IsTrigger. Esto significa que cualquier objeto que colisione con el ente Trigger podrá atravesarlo, ya que éste no es un objeto sólido (más bien es un fantasma) pero queda registrado que el objeto ha entrado en su área definida y se ejecutarán los siguientes métodos:
OnTriggerEnter(): se ejecuta cuando un objeto entra en colisión con otro objeto.
OnTriggerStay(): se ejecuta mientras un objeto está en colisión con otro objeto.
OnTriggerExit(): se ejecuta cuando el objeto deja de estar en colisión con otro objeto.
Teniendo en cuenta los tres tipos de cuerpos estático, cinemático y dinámico podemos tener la siguiente regla en el caso de los sensores. El motor físico detectará la colisión:
Si uno de los cuerpos es dinámico.
Si uno de los cuerpos es cinemático.
Hablamos de sensor cuando el objeto no es visible al jugador. Se puede crear un GameObject vacío o bien un objeto transparente para detectar cuándo un objeto entra en contacto con él. En el siguiente ejemplo creamos un objeto transparente:
Creamos un cubo en la escena y le añadimos un componente Rigidbody y desmarcamos Use Gravity
Añadimos un cubo que cambiaremos de tamaño y lo renombramos como Sensor y marcamos su propiedad Istrigger. Aquí tenemos dos opciones:
Desactivamos o quitamos el componente Mesh Renderer.
Crear un material transparente: en la propiedad Rederer Mode cambiamos Opaque a Transparent. Le asignamos un color con 100% de transparencia.
Creamos el script y se lo asignamos al Trigger y dentro del método <span lang="en">OnTriggerEnter</span> escribimos un mensaje en la consola.
Si vamos a simular el mundo real tenemos que tener en cuenta que hay ciertos materiales con características que los hace especiales, no es lo mismo tirar un objeto de goma al suelo que un objeto de cristal. El primero es flexible y rebotará y el segundo se romperá en trozos. Este comportamiento Unity lo tiene en cuenta mediante los materiales físicos o Physic Material. Mediante este componente podremos establecer ciertas propiedades que definen el comportamiento en una colisión y que puedes consultar en la documentación oficialMaterial de Física:
Fricción: es la cantidad de rozamiento que tienen las superficies. Puede ser de dos tipos:
Dinámica(Dynamic Friction): cuando está en movimiento. Un valor de 0 hará que no se aplique fricción a la superficie y un valor de 1 hará que el objeto se desacelere muy rápidamente cuando esté en contacto con otra superficie.
Estática (Static Friction): cuando el objeto se encuentra quieto. Un valor de 0 permitirá que el objeto comience a moverse muy fácilmente. Un valor de 1 tomará mucha fuerza para que el objeto comience a moverse.
Rebote (Bounciness): según el material puede ser más flexible y por tanto rebotar en la superficie. Con un valor 0 el objeto no rebotará en absoluto (toda la energía cinética será absorbida). Con un valor 1, el objeto rebotará indefinidamente (se mantendrá toda la energía cinética). Con un valor mayor que 1 hará que el objeto rebote más alto (ganará energía cinética).
Cómo se combina lafricción (Friction Combine) entre dos objetos en colisión y se puede aplicar la siguiente combinación:
Media (Average): la fricción aplicada es la media de los los dos colisionadores.
Multiplicar (Multiply): la fricción aplicada es el producto de la fricción de ambos colisionadores.
Mínimo (Minimum): la fricción aplicada es la fricción mínima de cualquiera de los colisionadores.
Máximo (Maximum): la fricción aplicada es la fricción máxima de cualquiera de los colisionadores.
Cómo se combina el rebote (Bounce Combine) entre los objetos. Admite las mismas combinaciones que la fricción.
Cuando se establece un material a un objeto también hay que tener en cuenta el parámetro Drag de su Rigidbody, ya que este parámetro indica la resistencia del objeto al aire de forma que un valor 0.001 simula un bloque sólido de metal y un valor 10 una pluma.
Recuerda que la propiedad Rigidbody tiene el parámetro Drag que es la resistencia al aire cuando se la aplica una fuerza
Si queremos que todos los objetos se comporten de la misma manera y tengan el mismo material físico se puede realizar en la configuración medianteEdit > Project Settings... > Physics. Por defecto no hay ningún material asignado ya tenemos el valor None (Physic Material) en la opción Default Material.
Debes tener en cuenta que simular el material físico de los objetos supone más sobrecarga en el procesamiento de las imágenes
Unity también ofrece la posibilidad de crear materiales físicos para ajustar la fricción y el rebote a un objeto en concreto cuando colisiona con otro mediante la opción vista Project > Asset > Create > Physic Material o bien Physic Material 2D según el proyecto. A continuación ponemos una tabla donde se establecen los valores para tipos de materiales:
Tipos de material y valores que puede tomar cada uno
Crea una plataforma de una mesa de billar, con una bola a la que se le aplicará una fuerza de impulso y un material de física de forma que rebote. Modifica los valores del material para alcanzar el efecto rebote que veas conveniente.
En desarrollo de un juego nos vamos a encontrar en la tesitura que debemos repetir objetos, los cuales deben tener las mismas propiedades en cada aparición del juego. Unity ofrece la opción de crear un Prefab, que es una plantilla que encapsula un GameObject de forma que todos los objetos del Prefab tienen el mismo comportamiento y características. Cualquier cambio en el Prefab se aplica a todas las instancias del Prefab en el juego. El comportamiento del Prefab lo estableceremos como hasta ahora en un script.
Podemos crear un Prefab en Unity de varias formas:
Arrastrando un GameObject sobre la vista Project. Automáticamente se convierte en un Asset pero con extensión .Prefab en la carpeta donde lo hayamos arrastrado y con el nombre con el que se haya creado.
Crear una carpeta específica Prefabs en la vista Project y en ella seleccionar Create > Prefab, se indica el nombre y se arrastra el objeto GameObject que formará el Prefab.
Cuando un objeto está conectado a un Prefab se muestra en color azul en la vista Hierarchy.
Al seleccionar un objeto Prefab la vista Inspector es diferente respecto a un objeto normal:
Las propiedades que son diferentes al Prefab o plantilla original aparecen en negrita. Se puede modificar los valores de una instancia sin modificar los valores originales de la plantilla. Si posteriormente se modifica la misma propiedad en la plantilla el cambio no repercute tampoco en la instancia, ya que se ha modificado y está en negrita.
Open: cuando seleccionamos esta opción, aparece la vista Scene con fondo azul y en la vista Hierarchy un único objeto que es la plantilla Prefab, estamos en modo edición del Prefab. Es en esta vista donde podremos modificar los valores de la plantilla y que después tomarán todas las instancias del Prefab. La flecha hacia atrás en la barra de encabezado de la ventana Hierarchy visible, nos permite salir en modo edición del Prefab:
Select: esta opción modifica la vista Project ya que se ubica en el directorio donde se encuentra el Prefab y se selecciona el Prefab entre todos los elementos. Además, aparecen los valores por defecto en la vista Inspection de forma que aquí también se puede modificar los valores de la plantilla pero no aparecen todas las opciones.
Override: sólo aparecerá esta opción cuando se seleccione un valor que sea diferente entre la instancia y el Prefab.
Vamos a explicar las opciones que tenemos en este último botón Override:
Se puede seleccionar el componente que se quiere sobreescribir de forma que tenemos las siguientes opciones:.
Revert: anulamos todos los cambios dentro del componente realizados en la instancia del objeto y tomamos el valor por defecto de la plantilla.
Apply: modificamos los valores del Prefab con los valores de la instancia actual.
O bien aplicar todos los cambios en un sentido u otro. Si seleccionamos Revert Allse sobrescribe todos los valores de la instancia por los originales. Y se escogemos Apply Alltodos los cambios realizados en la instancia se copian a la plantilla o Prefab .
La ventaja de los Prefab es que podemos crearlos en tiempo de ejecución mientras que su configuración como los materiales y texturas que lo forman lo hemos realizado previamente, ahorrando líneas de código. Los ejemplos más usuales son:
Construir una pared o elementos de una escena en base a varios Prefab.
Para crear un Prefab en tiempo de ejecución hay que tener en cuenta algunas cuestiones:
Como trabajo previo, se usa un 'Empty GameObject' en la vista Hierarchy para contener el script asociado al Prefab y para añadir las instancias del Prefab como hijos de este objeto vacío.
A la hora de crear un Prefab no podemos hacer referencia a otros a GameObjects o componentes de un GameObject de la escena para ello haremos uso de una de las soluciones que proponen en el siguiente enlace: Obtener una referencia a cualquier GameObject.
Vamos a crear un proyecto donde tendremos una esfera que lanzará proyectiles desde su posición cuando se pulse la tecla virtual Fire1 (CTRL izquierdo) y el objeto vacío que contendrá los Prefab instanciados.
Creamos un objeto cápsula y lo rotamos 90º en el eje-z para que parezca un proyectil. Arrastramos la cápsula sobre la vista Project y vemos que se ha creado el Prefab, por tanto eliminamos el objeto de la vista Hierarchy, ya que creamos los objetos de forma dinámica.
Creamos el siguiente script donde cada Prefab creado se destruirá en el tiempo establecido en la variable Time. Fíjate que lo hacemos en el método Start ya que sólo debe ejecutarse en el primer frame.
public class DestroyProyectil : MonoBehaviour
{
public float time;
void Start()
{
Destroy(this.gameObject, time);
}
}
Añadimos el script al Prefab y no nos olvidamos de inicializar la variable Time.
Continuamos con la enumeración de pasos a seguir del apartado anterior:
Creamos el script que creará los proyectiles. Declaramos dos variables velocity y el componente Rigidbody con nombre proyectilque asignaremos en el editor de Unity al componente Rigidbody del Prefab. Mediante el método Instantiate creamos la instancia del Prefab con la posición de la esfera, pero con la rotación que se haya definido en el Prefab mediante proyectil.transform.rotation. En el método TransformDirection establecemos la dirección del proyectil. Tenemos que tener en cuenta la orientación de la esfera y ponemos un valor negativo para que salgan por la izquierda.
public class InstantiateProyectil : MonoBehaviour
{
public Rigidbody proyectil;
public int velocity;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
proyectil = Instantiate(proyectil, transform.position, proyectil.transform.rotation);
proyectil.velocity = transform.TransformDirection(new Vector3(-velocity, 0, 0));
}
}
}
Para instanciar un Prefab también se puede usar el método Resources.Load como muestra el siguiente código: GameObject prefab = Resources.Load("Assets/Resources/MainCamera");
En este ejemplo utilizaremos la esfera como el objeto que lanzará los proyectiles con lo cual el siguiente script lo añadimos a la esfera. Inicializamos la variable proyectil en el editor de Unity como muestra la imagen:
Si tienes dudas o quieres ver otro ejemplo te proponemos que veas tres vídeos. Los dos primeros te muestran cómo instanciar un Prefab y el último cómo eliminar un Prefab. Estos vídeos forman parte del Tutorial de Unity del canal CodigoFacilito por si quieres consultar algún vídeo relacionado con lo que hemos visto.
La música o efectos de sonidos son imprescindibles en un juego. En el caso de estar en una batalla y no escuchar el sonido de los disparos crea una sensación extraña y decepcionante. Así que al proyecto de disparar proyectiles vamos a añadirle un poco de sonido, así que lo primero es descargarnos un sonido de disparo. Además de la tienda oficial de Assets de Unity hay varias webs que nos ofrecen recursos:
Unity utiliza internamente el formato Vorbis que se puede reproducir dentro del entorno de Unity, pero nos hemos bajado un sonido en formato mp3 que añadimos al proyecto en la carpeta Asset > Sounds que hemos creado para guardar los archivos de música y sonido.
Para conseguir que nuestro proyectil suene tenemos que hacer uso de dos componentes:
Audio Listener: recoge el sonido que genera el componente Audio Source. Hace la función de los oídos del jugador en la escena. En cada escena sólo podemos tener un Audio Listener y suele ir asociado a la cámara principal pero se puede seleccionar cualquier otro GameObject.
Audio Source: es la fuente de sonido y puede haber varios. Además el sonido de cada uno de ellos será más fuerte o menos en función de la distancia con el Audio Listener.
Si queremos añadir un Audio Listener en un objeto lo hacemos añadiendo este componente mediante la opciónAdd Component > Audio > Audio Listener. Cuando se crea un proyecto nuevo es la cámara principal quien funciona como los oídos del jugador y contiene el componente con lo cual únicamente tenemos que asegurarnos que esté activo, es decir que esté marcado el checkbox que hay a la izquierda del nombre:
Si queremos que sea otro objeto quién contenga el componente Audio Listener no nos podemos olvidar de eliminar el componente en la cámara: botón derecho en Audio Listener > Remove Component.
A continuación configuramos el Audio Source. Como ya se ha comentado, en una escena se pueden estar reproduciendo varios sonidos: el sonido de un río, de un pájaro, sonidos que realiza el personaje, etc. Para ello se debe añadir el componente a un objeto mediante la opción Add Component > Audio > Audio Source. Siguiendo con el ejemplo realizado en el apartado 3.9.1.- Crear Prefab en tiempo de ejecución I vamos a añadir el sonido de un disparo a la esfera. Podemos ver cómo en la esfera aparece un gizmo en forma de altavoz indicando que ese objeto tiene la capacidad de emitir un sonido.
En la vista Inspector vemos las propiedades de este componente donde el más importante es AudioClip que es donde seleccionamos el sonido que se va a reproducir. Además vamos a deseleccionar la opción Play OnAwake porque no queremos que se reproduzca cuando se ejecute el juego (Run) sino cuando le demos a la tecla de disparar y lo vamos a controlar mediante un script asociado a la esfera.
Realizar este tutorial no te resultará complicado, ya que hemos visto cómo copiar objetos en una escena (en este caso "gérmenes"), crear un Prefab y añadirles un sonido que veremos en el siguiente apartado.
Vamos a programar mediante un script que sólo se reproduzca el sonido cuando se pulse la tecla de disparo. Destacamos las líneas 5, 9 y 17 del código que hemos añadido al proyecto:
using UnityEngine;
public class InstantiateProyectil : MonoBehaviour
{
public Rigidbody proyectil;
public AudioSource audio;
public int velocity;
void Start()
{
audio = GetComponent<AudioSource>();
}
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
proyectil = Instantiate(proyectil, transform.position, proyectil.transform.rotation) as Rigidbody;
proyectil.velocity = transform.TransformDirection(new Vector3(-velocity, 0, 0));
audio.Play();
}
}
}
El diseño de la interfaz de usuario en Unity se suele utilizar para mostrar información sobre el juego. Ejemplo de interfaces son el menú de opciones en la pantalla de bienvenida, el marcador o puntuaciones, configuración del juego, etc. Esta interfaz puede contener textos, botones, imágenes, slider, etc.
Cuando creamos un objeto de la interfaz de usuario en una escena se añaden por defecto dos elementos:
Un objeto Canvas que funciona como objeto raíz y marca el área donde tienen que estar todos los elementos de la UI. Este objeto contenedor no tiene el componente Transform sino RectTransform que marca los límites y nos permite posicionar los elementos UI en el mundo. Este objeto se adapta a la resolución de pantalla del dispositivo re-escalando los elementos que contiene.
EventSytem: este objeto nos permite controlar todas las entradas o Input en nuestros elementos de la UI del juego. Lo interesante es que gestiona de manera automática los diferentes eventos en base a la plataforma del juego, ya sea un móvil o bien un PC. Es opción del programador usar este objeto o bien gestionar por él mismo los eventos, pero no se puede eliminar de la jerarquía de objetos porque de lo contrario no funcionaría los eventos en los elementos de la UI .
Otro elemento a tener en cuenta son los anclajes o anchors ya que los elementos de la interfaz se posicionan siempre respecto a una ubicación concreta dentro del Canvas. Vamos a explicar a continuación los conceptos que necesitas para realizar una interfaz para una aplicación móvil.
Los elementos de la interfaz se dibujan en el objeto Canvas en el mismo orden que aparecen en la vista Hierarchy. Si dos elementos se superponen será el último elemento el que aparecerá encima del resto.
El objeto Canvas tiene la propiedad Render Mode que renderiza el espacio del Canvas en el espacio de la pantalla o en el espacio del mundo. La opción por defecto es Screen Space donde los elementos de la UI se colocan por encima de los objetos de la escena y está vinculada al tamaño de la pantalla. Puedes consultar las otras opciones en el siguiente enlace: Información del objeto Canvas.
Si estamos en tipo Screen Space es posible que en la previsualización de la escena el objeto Canvas lo veamos de un tamaño mucho mayor que el resto de elementos de la escena, ya que internamente el Canvas trabaja con píxeles y los elementos de la escena asumen el metro como unidad del espacio del mundo. No debe preocuparnos ya que al ejecutar el juego el objeto Canvas se ajustará al tamaño de la pantalla o de la cámara.
Para conseguir interfaces adaptables tenemos que tener en cuenta la propiedad Canvas Scaler que permite controlar el escalado y la densidad total del píxel de los elementos de la UI en el objeto Canvas. Este escalado Puede tener los siguientes valores que puedes consultar en detalle en el siguiente enlace: Creación de Interfaz de usuario en Unity:
Constant Pixel Size: los tamaños de los objetos de la interfaz se especifican en píxeles. Si la pantalla tiene más densidad los objetos se verán más pequeños a no ser que utilicemos strech en Rect Transform y sea un objeto estirable. Esta opción es la ideal para juegos de PC o videoconsolas.
Constant Physical Size: en este caso los objetos siempre ocuparán el mismo espacio físico, independientemente de la densidad de pantalla. En este caso se utilizan los píxeles independientes o dpi dentro del objeto Canvas. Aunque la pantalla de un móvil o PC tengan densidades diferentes los objetos tendrán las mismas dimensiones físicas (en cm reales). Esta opción es útil para los menús de forma que el tamaño de los botones sea el mismo independientemente de la plataforma. Y también si el juego se realiza para dispositivos móviles.
Scale With Screen Size: con esta opción el contenido de la UI se escala en base al tamaño de la pantalla. Normalmente se diseña la interfaz pensando en un tamaño de pantalla en píxeles. En el caso que el ancho o alto sean diferentes el tamaño de los objetos se escalará de forma proporcional.
Cuando creemos un script que gestione los objetos de la interfaz y sus eventos hay que añadir los siguientes espacios de nombres:
using UnityEngine.UI; //Para los elementos UIs
using UnityEngine.EventSystems //Para el control de eventos;
A continuación explicaremos los aspectos más importantes en el diseño de una UI .
El Slider es un elemento de una página web que muestra múltiples imágenes y texto que se alternan entre ellas.
Siguiendo con la barra de herramientas y las operaciones de rotación, tamaño y escalado es buena idea tener la configuración Pivot y Local.
Ya hemos comentado que Rect Transform es el nuevo componente para posicionar los objetos dentro de un Canvas. Vamos a añadir un objeto Button mediante la opción GameObject > UI > Button para ver las operaciones que podemos realizar.
En este componente se incluye el concepto Anchors, que son cuatro manillas pequeñas con figura de triángulos en la vista de escena y se configura mediante el botón Anchors Presetque está marcado como 1 en la parte superior izquierda de la imagen anterior.
Mediante esta herramienta marcamos el anclaje horizontal y vertical. Se puede anclar el elemento UI a:
Los lados del padre.
A la mitad del padre.
O estirar con el tamaño del padre.
Por defecto el botón muestra las opciones seleccionadas como puedes ver en la imagen: vertical (middle) horizontal (center). Visita la página oficial para ver cómo el Rect Transform hijo puede ser anclado al Rect Transform padre en varias maneras en el apartado Diseño básico.
En el rectángulo 2 se muestra la propiedad Pos (X,Y,Z) que marca la posición del punto del rectángulo relativa al anclaje, en el 3 podemos modificar las propiedades Width y Height indican el ancho y alto del rectángulo y finalmente en el 4 podemos modificar su ángulo de rotación o Rotation en grados alrededor de su punto de pivotaje a lo largo de los ejes X,Y y Z y el factor de escalada o Scale que se aplica a las dimensiones del objeto en cada eje.
Una vez que hemos visto qué propiedades se pueden modificar en un objeto puedes consultar la documentación Diseño básico para ver las propiedades de los elementos básicos: etiquetas de texto, imágenes o botones en Unity.
EventSystem es el responsable de procesar y manejar los eventos en una escena de Unity. Son muchos los eventos que maneja esta clase con lo cual se ha dividido en interfaces que nosotros tendremos que implementar si queremos que se ejecute el método callback correspondiente en nuestro script como puedes ver en la API de la clase UnityEngine.EventSystems.
Vamos a crear un script con nombre MouseEvent.cs con el siguiente código y lo asignamos a un ButtonUI. Lo que hemos hecho es implementar tres interfaces que detectan los tres estados cuando hacemos clic con el ratón o touch sobre un UI:
public class MouseEvent : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler {
public void OnPointerClick(PointerEventData eventData){
Debug.Log("He realizado click");
}
public void OnPointerDown(PointerEventData eventData){
Debug.Log("He levantado el puntero");
}
public void OnPointerUp(PointerEventData eventData){
Debug.Log("He levantando el puntero");
}
}
Otra opción es definir triggers o disparadores dentro de un objeto de forma que serán los encargados de llamar a la función que nosotros le indiquemos. Utilizaremos para ello la vista Inspector, ya que al objeto le añadiremos el componente Event Trigger. Cada uno de los eventos soportados se pueden incluir opcionalmente en el Event Trigger al oprimir el botón Add New Event Type. Tienes que tener en cuenta que hay controles de UI ya implementan este componente de forma nativa como es el caso de Button.onClick. Veamos este último ejemplo:
En primer lugar vamos a crear un script llamadoSendMessage.cs con un método propio HelloWorld que escribirá un mensaje por consola y lo asignamos a un objeto de la escena. Puede ser un GameObject Empty o en este caso lo asignaremos al objeto Canvas:
public void HelloWorld()
{
Debug.Log("Hello World....");
}
Pinchamos sobre el + de la imagen y dejamos la opción por defecto Runtime Only. En el desplegable de abajo seleccionamos el objeto Canvas.
En el desplegable "No function" seleccionamos y nos aparecerá el nombre del scriptSendMessage.cs. A continuación el nombre del método que queremos que se ejecute, en nuestro caso HelloWorld().
Si ejecutas el juego verás cómo se escribe el mensaje por consola cada vez que pulsamos sobre el botón.
Te proponemos seguir el siguiente tutorial donde crearás un controlador táctil para dispositivos móviles utilizando objetos UI . Al final del tutorial hay un enlace para descargar el código de ejemplo que da error. No te preocupes en el apartado retroalimentación de esta actividad puedes descargar la solución.
Vamos a versionar el tutorial de UnityRoll a Ball que se explica en español en la web de Jairo García de forma que vamos a englobar todo lo que hemos visto en la unidad. Este juego va a consistir en un jugador (sphere) que moveremos a través del acelerómetro del móvil a través de una plataforma (plane) en la cual aparecen una serie de enemigos (cube) que están girando y tenemos que eliminarlos colisionando con ellos en el menor tiempo posible. Vamos a construir el ejercicio en diferentes fases.
Vamos a conseguir la perspectiva deseada en el juego modificando los valores de la cámara. Para ello hay dos opciones:
Copiar los datos de la vista escena a la vista juego: si estamos seguros que la vista de la escena es la que queremos en la vista juego, podemos copiar esta vista en la cámara. Para ello seleccionamos Main Camera y seleccionamosGameObject > AlignWithView de forma que la cámara, se alinea con la vista de la escena. Si queremos que la vista Scene muestre lo mismo que la vista Game, es decir, el paso inverso, se realiza de la misma forma salvo que escogemos la opción Align View to Selected de forma que se alinea con el objeto seleccionado.
Ajustar los valores en la vista Inspector: para ello hacemos uso el componente Transform de Main Camera y ajustamos la propiedad Position para que coincida con X=0, Y=10, Z=-10 y la propiedad Rotation para que coincida con X=45, Y=0, Z=0.
Recuerda que en la ventanaCamera Preview se ve las modificaciones de la cámara. Si todo ha ido bien verás el suelo y el jugador centrados.
Para crear el tablero crearemos cuatro cubos que serán nuestros muros y el suelo que será un plano.
Empezamos por el suelo donde vamos a escalar el objeto de forma que X=2 y Y=1 y Z=2 de forma que tenemos un mayor área de juego. Recuerda que podemos hace uso de los materiales y el sistema de partículas para modifica una superficie. En este ejemplo vamos a crear un material llamado Floor para darle un color al suelo. Una vez que has creado el material cambiamos el color del suelo en la propiedad Albedo con la herramienta Color Picker.
A continuación vamos a crear las paredes por cada una de ellas creamos un cubo o copiamos uno ya creado:
WallOest: con Position: -10, 0, 0 y Scale 0.5, 2, 20.5.
WallEast: con la propiedad Position a 10, 0, 0 y Scale 0.5, 2, 20.5.
WallNorth: con las propiedades Position: 0, 0, 10 y Scale: 20.5, 2, 0.5
WallSouth: con las propiedades Position: 0, 0, -10 y Scale: 20.5, 2, 0.5
Le asignamos el material creado a la pared también. Y el resultado debe ser similar a la siguiente imagen:
Para tener una mejor visión del jugador vamos a girar el componente Directional Light y en su componente Transform vamos a aplicar una rotación de 60º a su eje-y
Ya tenemos los muros laterales del tablero con lo cual ya evitamos que la esfera pueda salir del tablero. Nuestro dispositivo de entrada será el acelerómetro del móvil, de forma que cuando movamos el móvil, el acelerómetro integrado nos da una aceleración lineal. Con lo cual vamos a crear un script de programación para controlar el movimiento del jugador. Ya hemos visto que cuando aplicamos una fuerza física es mejor utilizar el método FixedUpdate para que el movimiento sea fluido ya que se ejecuta el tantas veces como actualizaciones realice el motor de física.
Como puedes consultar en la documentación oficial Input en dispositivos el acelerómetro tiene las mismas coordenadas que Unity. Si mantenemos el móvil en posición vertical, con el botón de inicio delante de nosotros, el eje X es positivo a lo largo de la derecha, el eje Y es positivo directamente arriba, y el eje Z es positivo apuntando hacia ti.
Aunque nuestra aplicación se va a ejecutar en orientación LandscapeUnity hace automáticamente el cambio e igualmente el eje horizontal corresponderá al eje-x y el movimiento vertical al eje-y del acelerómetro. En este ejemplo utilizaremos Input.acceleration para realizar el movimiento. Puedes leer las opciones que nos da la clase Input.
Como es un movimiento físico tenemos que añadir un componentes Rigidbody a la esfera y asignarle el siguiente scriptPlayerController.cs:
public class PlayerController : MonoBehaviour
{
private Rigidbody rb;
public float speed = 20F;
// Use this for initialization
void Start () {
rb = GetComponent<rigidbody>();
}
void FixedUpdate () {
float moveH = Input.acceleration.x;
float moveV = Input.acceleration.y;
Vector3 move = new Vector3(moveH, 0.0f, moveV);
//Asigno ese movimiento o desplazamiento a mi RigidBody
rb.AddForce(move *speed);
}
}
Te recomendamos que realices el juego original, es decir enfocado a un PC y pruebes las siguientes variantes:
Nosotros no contemplamos que la cámara siga al jugador (configuración del juego en tercera persona) ya que lo ejecutaremos en el móvil e indicaremos obligatoriamente que se ejecute en posición horizontal o Landscapepero sería interesante que vieras cómo implementarlo y su resultado en el juego.
Así mismo nosotros moveremos la esfera a través del acelerómetro del móvil, prueba a realizar el movimiento del jugador con el teclado.
Alrededor del jugador vamos a crear una serie de cubos que serían nuestros enemigos. Su característica principal es que tienen que tener un componente Collider para detectar la colisión del jugador con ellos y aquí tenemos dos opciones posibles:
Destruir los objetos.
O bien desactivarlo, de forma que pasado un tiempo pueda activarse de nuevo como dinámica del juego. Utilizaremos esta segunda opción e indicaremos que se comportará como un Trigger.
Para identificar al enemigo, vamos a hacer uso de las etiquetas o Tag dentro del Prefab, para posteriormente poder acceder a los enemigos por código. Estos enemigos aparecen rotando sobre ellos mismos. con lo cual lo vamos a rotar 45º el objeto modificando su propiedad Rotation a los valores X=45,Y=45, Z=45. Y les asignamos el siguiente script para que sigan rotando en el juego:
Estos objetos serían estáticos porque no se modifica su posición (componente Transform) pero sí están rotando con lo cual obliga al motor de física a comprobar su actualización en cada frame. Vamos a convertir su movimiento en cinemático para quitarle trabajo al motor de física. Para ello realizamos los siguientes pasos:
Añadimos componente Rigidbody.
Desactivamos la opción Use Gravity.
Y activamos la opción Is Kinematic.
Como ya hemos definido el comportamiento de todos los enemigos, lo creamos como Prefab y creamos los 12 enemigos alrededor del jugador.
Vamos a añadir dos componente UI > Text, el primero para mostrar el contador y el segundo para mostrar el mensaje final del juego. Ambos los vamos a anclar con respecto a la escena y después modificaremos su posición mediante la herramienta Anchor Presets en la vista Inspector. Modificaremos su posición en PosX y PosY en el componente RectTransform para que se posicione en el lugar deseado. Además, modificamos el color, el tamaño. Finalmente en la propiedad Horizontal Overflow modificamos su valor a Overflow para que no realice un salto de línea entre palabras. Quedando la escena como muestra la imagen:
Una vez que hemos realizado el diseño, vamos a programar que si chocamos con un enemigo, aumentamos el contador y actualizamos los puntos. Cuando hemos llegado al máximo de objetos, entonces desactivamos la bola y mostramos el mensaje que ha ha finalizado el juego.
public Text textCont;
public Text textFinish;
private int cont = 0;
private const int MAXCONT = 12;
............................................
void OnTriggerEnter(Collider other) {
if (other.gameObject.CompareTag ("Enemy"))
{
//Desactivo el objeto
other.gameObject.SetActive (false);
//Incremento el contador en uno (también se puede hacer como contador++)
cont = cont + 1;
UpdatePoints();
if (cont == MAXCONT){
textFinish.gameObject.SetActive(true); // Activo el mensaje para que se muestre
this.gameObject.SetActive(false); // Desctivo la bola para que no se vea
}
}
}
private void UpdatePoints(){
textCont.text = "Points: " + cont;
}
Falta inicializar los valores y aquí vamos a utilizar el método Awake.
Awake y Start son métodos que son llamados automáticamente al iniciar el script pero Awake siempre se llama primero y en él se suelen inicializar las variables, así que finalmente terminamos el script con el siguiente código:
public void Awake(){
cont = 0;
textFinish.gameObject.SetActive(false); // Desactivo el mensaje
}
Antes de ejecutar el juego, recuerda asignar los objetos creados las variables declaradas en el script desde la vista Inspector
Si así lo deseas, puedes descargar el código fuente final del proyecto que hemos ido desarrollando, en el siguiente enlace:
Juan y Ana están de enhorabuena. En tan solo unas horas han realizado un juego fantástico durante el cual han aprendido muchas técnicas y conceptos nuevos: desde mover objetos, crear colisiones, añadir sonidos y crear interfaces dentro del juego. Y todo su esfuerzo ha quedado plasmado en un juego. Ada ha recibido noticias de que ambos se encuentran satisfechos con sus progresos, así que ha solicitado a Juan que le mande el juego terminado para que pueda instalarlo en el móvil y probarlo.
Y ahí es donde Juan encuentra otro problema, cuando ya no esperaba tener ninguno más:
¿Cómo puedo hacerle llegar a Ada el juego sin tener que explicarle cómo instalar Unity?
¿Le funcionará el juego en Android?
La solución pasa por aprender a desplegar el proyecto de forma que pueda ejecutarse en cualquier plataforma sin necesidad de instalar nada más.
Para crear el ejecutable de un juego en cualquier plataforma destino tenemos que escoger la opción del menú File > Build Settingsque abrirá la pantalla de compilación.
En primer lugar añadimos las escenas que queremos compilar mediante el botón Add Open Scenes.También se puede arrastrar las escenas desde la vista Project al áreaScenes in Build. Aunque tengamos una escena puedes ver cómo se añade un valor de índice a la escena, en este caso scene 0 es la primera y única escena que va a cargarse cuando se construya el juego. Pero tienes que tener en cuenta que existe un orden en las escenas y en el caso de querer modificarlas simplemente debes seleccionar la escena y debes arrastrarla a la ubicación deseada.
A continuación seleccionamos la plataforma sobre la cual queremos compilar el proyecto. En base a la plataforma seleccionada tendremos que configurar ciertos parámetros que son utilizados durante la generación del juego según la plataforma mediante el botón Player Settings...
En la parte inferior hay dos botones de forma que ambos generan los ejecutables del juego, pero el segundo Build And Run también lo ejecuta.
En nuestrovcaso queremos exportar el juego para dispositivos Android, con lo cual el primer paso es seleccionar la plataforma Android y a continuación el botón Switch Platform. Tarda un poco hasta que se configura nuestro proyecto para Android. Cuando el proceso ha terminado aparece el logo de Unity en la plataforma de Android.
Recuerda que en la instalacion del Editor de Unity realizamos la instalación del módulo Android Build Support, por eso nos sale el incono de Unity en la plataforma Android de forma que podremos realizar la compilación.
Vamos a ver qué configuración específica necesita nuestro proyecto para crear el ejecutable en Android.
Si seleccionamos la opción Player Settings se accede a una ventana que se divide en dos: la primera parte es común a todas las plataformas y nos permite establecer el nombre de la empresa, el nombre del producto, el icono que se mostrará para lanzar el juego y el tipo de puntero del ratón que se utilizará en las plataformas compatibles.
Independientemente de las opciones que queramos personalizar par el juego, se deben establecer los siguientes parámetros del apartado Other Settings:
Package Name: es el nombre del juego o de la aplicación dentro de Android. Debe tener el siguiente formato com.CompanyName.
Versión: la versión del juego o de la aplicación. En el caso que se haya realizado modificaciones a la anterior versión se debe incrementar en uno su valor.
Minium API Level: la versión mínima de Android donde el juego o la aplicación es compatible.
Target API Level: es la versión que ha utilizado el programador para probar el juego, inicialmente siempre escoge el número de versión más alto.
Puedes consultar la sección Solución de Problemas en Desarrollo para Android en el caso que tengas algún problema en la instalación del juego. Aunque por defecto está habilitada, hay que comprobar que no hemos modificado por error el valor de Install Location que debe ser Prefer External.
Una vez realizada la configuración pulsamos sobre el botón Build, y nos pedirá la ubicación dónde guardar el .apk. Un buen lugar para hacerlo es crear el directorio Build en el directorio raíz de nuestro proyecto, en el mismo nivel que Assets. Selecciona este directorio e introduce el nombre del ejecutable. Puedes consultar el siguiente enlace de la documentación oficial donde se explica cómo ejecutar el juego para un dispositivo Android, así comoiOS: Building for Mobile
Puedes compilar y ejecutar el juego en un dispositivo móvil mediante la opción Build And Run. Para ello debes tener un dispositivo o emulador con el sistema Android conectado y seleccionarlo en la pestaña Run Device. Si ves que no aparece pulsa sobre el botón Refresh. Esta opción ejecutará el juego en tu dispositivo, pero es un proceso lento, con lo cual no es la mejor opción para testear tu juego. En el siguiente apartado te explicamos cómo realizarlo.
Si quieres publicar el juego en Google Play Store de Android es necesario firmar el juego. En el siguiente enlace puedes ver Cómo firmar tu app. Posteriormente a este proceso debes configurar los ajustes de publicación en la ventana Player Settings > Publishing Settings.
En el apartado anterior hemos visto cómo crear el ejecutable. Mientras desarrollamos un juego es muy probable que queramos probar su ejecución en un emulador o dispositivo. Tenemos que realizar los siguientes pasos:
Damos por hecho que tenemos instalado Java, pero aún así lo mencionamos como requisito.
Habilitar el modo de depuración o USB Debugging en el dispositivo móvil que puedes consultar en el siguiente enlace Cómo configurar las opciones de desarrolladores en Android. Si utilizas el sistema operativo Windows, si en al Administrador de dispositivos de Windows aparece el dispositivo con una exclamación amarilla es que debes instalar el controlador.
Descargar elSDK de Android. Nosotros ya lo tenemos instalado, así que simplemente hay que indicar la ruta en Unity en Edit > Preferences > External Tools y se debe seleccionar la carpeta SDK de Android.
Verificar la instalación del dispositivo a través del comando adb: para saber si el dispositivo está conectado:
Abre un terminal o símbolo del sistema. Debes dirigirte a la carpeta platform-tools que se encuentra en el directorio SDK de Android.
Ejecute el siguiente comando adb kill-server y presiona la tecla Intro.
A continuación ejecuta el comando adb devices y presiona la tecla Intro. A continuación aparece un listado de dispositivos conectados y debería estar tu teléfono. Si no fuera así, no has instalado correctamente el controlador.
Instalar la aplicación Unity Remote en el dispositivo móvil que puedes encontrar en Google Play. Esta herramienta evita tener que crear el ejecutable .apk e instalarlo en el dispositivo Android en cada cambio. La aplicación se conecta con Unity mientras ejecuta tu proyecto en el modo de reproducción desde el Editor de Unity. Puedes consultar la documentación oficial de Unity Remote.
Vamos a indicar que Unity Remote se va a ejecutar en un dispositivo Android, con lo cual seleccionamos Edit > Project Settings > Editor > Device> Any Android Device
Una vez que hemos realizado la configuración es necesario realizar los pasos en el siguiente orden para que la comunicación Unity Remote - Unity Editor se realice:
Tenemos que tener el Editor de Unity.
Conecta el dispositivo móvil al ordenador.
Abre la aplicación Unity Remote en el dispositivo móvil.
Vamos a exportar el proyecto del juego que hemos realizado en Unity y vincularlo a un proyecto de Android, de forma que el usuario pueda ejecutar el juego desde una Activity de Android. Explicamos todos los pasos a realizar.
Vamos a exportar el proyecto del juego que hemos realizado para poder abrirlo desde Android Studio. Para ello accedemos a la pantalla de configuración de compilación mediante File > Build Settingsy vamos a modificar los siguientes valores:
A continuación, pulsamos sobre Plater Settings... y vamos a realizar los siguientes cambios que te ponemos en la imagen. A parte de realizar la configuración del proyecto (Package name, Version, Minimum APILevel, Target APILevel) que ya se ha explicado hay que añadir las librerías necesarias para ejecutar el juego en arquitecturas ARM64. Debemos:
Debes tener en cuenta que el proyecto de Unity se tendrá que ejecutar en dispositivo físico ya que el emulador de Android Studio tiene como arquitectura x86. Si lo ejecutas en un emulador obtendrás el error "No se encuentra la librería libmain.so."
Si aparece el error "NDK no encontrado", hay que asegurarse que Unity haya descargado e instalado su propia copia de NDK en Edit > Preferences > External Tools > Android NDK.
Ya tenemos el proyecto de Unity en una carpeta, y lo abrimos en Android Studio. Verás que existen dos módulos tal como se explica en la documentación oficial Gradle for Android son:
Módulo UnityLibrary: contiene el juego con todos los datos. Este módulo ya se exporta como una biblioteca que podemos integrar en cualquier otro proyecto de Gradle. Fíjate como en el fichero build.gradle aparece apply plugin: 'com.android.library' Y lo usaremos para incrustar Unity en aplicaciones Android existentes.
Módulo Launcher: es una aplicación de ejemplo que lanza el juego de Unity. Este módulo lo vamos a quitar del proyecto porque usaremos nuestra propia aplicación.
Para ellos accedemos al fichero settings.gradle del proyecto y eliminamos el módulo Launcher dejando el fichero así:
include ':unityLibrary'
A continuación tenemos que modificar el fichero AndroidManifest.xml. de la librería unityLibrary ya que UnityPlayerActivity ya no será la actividad principal tenemos que eliminar intent-filter con los intent que contiene android.intent.action.MAIN y android.intent.category.LAUNCHER.
Aplicamos los cambios sincronizando Gradle pulsando sobre Sync Gradle. Como verás desaparecerá el módulo del explorador de proyecto, pero aún como un directorio del proyecto, lo eliminamos por ejemplo desde el explorador de archivos.
Finalmente reconstruimos el proyecto mediante la opción Build > Make Project
Se debe reconstruir el módulo una vez finalizado todos los cambios para compilar el módulo con todos los cambios realizados.
Ahora vamos a añadir nuestro módulo UnityLibrary a un proyecto Android. Hay dos formas, en principio utilizaremos la primera ya que podemos ver la estructura de clases, en concreto nos interesa UnityPlayerActivity.java que es la actividad principal del juego de Unity.
Importar módulo al proyecto Android
Nos vamos al proyecto de Android Studio donde queremos añadir el juego y seleccionamos la opción File > New > Import Module. A continuación nos pide el directorio donde se encuentra la librería, seleccionamos la carpeta y cargará en el proyecto de Android el módulo UnityLibrary.
Añadir como librería AAR al proyecto Android
Cuando hemos reconstruido nuestro proyecto (Build > Make Project) se ha generado un archivo AAR en el directorio del proyecto: PROJECT_FOLDER\build\outputs\aar.
Ya desde nuestro proyecto Android realizamos los siguientes pasos: File > New Module > Import JAR/AAA Package y seleccionamos el anterior fichero aar generado en el proyecto de Unity.
Vamos a seguir las recomendaciones de la documentación oficial y vamos a crear una actividad en nuestro proyecto que extienda de la clase UnityPlaterAcctivity.java
Para que responda a la tecla Back, vamos a sobrescribir el método onBackPressed() y modificamos el fichero AndroidManifies.xml con la configuración deseada del juego en nuestra aplicación. Hemos copiado tal cual el código de ejemplo de la página oficial Extending the UnityPlayerActivity Jaca Code.
En nuestro caso sólo hemos modificado el fichero AndroidManifiest.xml para que se ejecute de forma horizontal quedando de la siguiente forma:
El único requisito hasta ahora en Unity es que declaremos en nuestro proyecto de Android una cadena de nombre game_view_content_description. Abrimos el fichero strings.xml de nuestro proyecto Android y añadimos:
En caso de no realizar este paso obtendremos el siguiente error:
...android.content.res.Resources$NotFoundException: String resource ID #0x0...
Finalmente añadimos un botón a nuestra pantalla principal que lanzará la clase que extiende de UnityPlaterAcctivity.java tal como hemos visto en Android.
Cualquier cambio en el proyecto Unity supone realizar todos los pasos hasta el cuatro de nuevo, ya que hay que actualizar todos los ficheros del proyecto.
Puedes descargarte el proyecto que hemos realizado con anterioridad de Unity en Android en el siguiente enlace:
Un Kit de desarrollo nativo o NDK permite desarrollar software directamente en una plataforma concreta sin tener que utilizar la máquina virtual.
Es la arquitectura de la mayoría de los dispositivos móviles. ARM64 es la evolución de la arquitectura ARM compatible con el procesamiento de datos de 64 bits.
Es posible que queramos pasar datos de Android a Unity, por ejemplo preferencias del usuario. En nuestro ejemplo vamos a indicar si el usuario quiere que suene la música al inicio del juego.
Para ello utilizaremos el objeto Intent que utilizamos para iniciar la actividad que extiende de UnityPlayerActivity. Al igual que en Android usaremos el método putExtra para pasar en este caso de una cadena con la keysettingSound. Queremos que aparezca en la ventana del juego la música que está sonando de fondo y que el usuario ha personalizado en la aplicación Android.
btInit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, GameActivity.class);
intent.putExtra("settingSound","RockAndRoll");
startActivity(intent);
}
});
Vamos a crear un script que asignaremos a un objeto vacío dentro de la escena. En esta escena creamos un que mostrará la canción que se escucharía en el fondo del juego. Este script recoge el intent de la Activity que hereda de la clase UnityPlayerActivity y que en nuestro ejemplo se llama GameActivity. UnityPlayerActivity es la instancia que crea automáticamente Android y que hace referencia al juego de Unity, con lo cual siempre podemos acceder a ella desde la clase AndroidJavaClass. A través de ella accederemos al objeto GameActivity mediante el código UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity") mediante la clase AndroidJavaObject. Estas dos clases nos ofrecen métodos genéricos como Call que nos permite llamar a un método de Android que pasamos como parámetro del método.
Una vez que tenemos una referencia de esta Activity podemos acceder al objeto intent que inició la Activity y usando los métodos de obtención de los extras acceder al par key-value que queramos, en nuestro caso settingSound:
public class SettingsManager : MonoBehaviour
{
public Text textSetting;
void Start()
{
AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject intent = currentActivity.Call<AndroidJavaObject>("getIntent");
AndroidJavaObject extras = intent.Call<AndroidJavaObject> ("getExtras");
//Recogemos el string que guarda las preferencias de sonido dentro de la aplicación Android
string settingSound = extras.Call<string>("getString", "settingSound");
textSetting.text = "Música de fondo: "+settingSound;
}
}
Una vez que finalice el juego queremos almacenar el tiempo que ha tardado por ejemplo el jugador en realizar el juego. Es por ello que necesitamos llamar a un método de una Activity. Dicho método debe estar declarado en la Activity que extiende de la clase UnityPlayerActivity, que en nuestro ejemplo es GameActivity.
public void endGame(String time) {
Toast.makeText(this, "Has tardado en terminar el juego:" + time, Toast.LENGTH_LONG).show();
}
Desde el scriptPlayerController.cscuando comprobemos que el jugador ha finalizado el juego llamaremos a este método que mostrará el mensaje flotante con el siguiente código:
if (cont == MAXCONT)
{
......
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
//Obtenemos la Activity que extiende de la clase UnityPlayerActivity
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
finalTime = Time.time-startTime;
var minutes = Mathf.Floor(finalTime / 60).ToString("00");
var seconds = (finalTime % 60).ToString("00");
var sfinaltime=string.Format("{0}:{1}", minutes, seconds);
activity.Call("endGame", sfinaltime);
.....
}
Se recoge la Activity que extiende de la clase UnityPlayerActivity y de nuevo mediante el método Call llamamos al método de Android con el parámetro que le queremos pasar. Comprueba el proyecto final con todas las variantes que hemos añadido en el siguiente enlace:
A continuación se realiza una clasificación por género muy detallada resaltando algunos de los videojuegos más importantes dentro de su categoría que dieron paso al género o bien supusieron su popularización. Te animamos a que busques en Internet imágenes de algunos de ellos y podrás entender mejor en qué consiste la categoría.
Acción: los videojuegos de acción son aquellos donde se realizan movimientos y/o combates rápidos. Aquí podemos incluir algunas de los géneros que veremos más adelante como los juegos de lucha, simulaciones de combate, juegos de disparo en primera persona, etc. Como representantes de los primeros juegos de acción podríamos nombrar Pong, Asteroids y Space Invaders.
Aventura: son aquellos que sumergen al jugador en una historia que se va desarrollando conforme avanza en el juego. Suelen incluir puzzles y otros desafíos que se superan con astucia e intuición. Los más antiguos no tenían gráficos y funcionaban mediante descripciones del entorno en forma de texto. Entre ellos destacan Zork (en modo texto), las series: King's Quest, Broken Sword y Monkey Island,
Lucha: en ellos, el jugador pelea contra otros jugadores o bien contra personajes controlados por el videojuego. Eso incluye los juegos de lucha uno contra uno o los juegos cooperativos donde el jugador o jugadores se enfrentan a hordas de enemigos mientras avanzan por un nivel. Otro subgénero lo forman los Beat 'em up (también conocido como yo contra todo el barrio), en el que se destaca el combate cuerpo a cuerpo entre el protagonista y un gran número de antagonistas. Como ejemplos podríamos nombrar: Double Dragon, Tekken, Devil May Cry, Street Fighter, Mortal Kombat y Virtua Fighter.
Videojuegos de disparo en primera persona (FPS): los FPS son juegos donde la pantalla representa lo que vería el personaje a través de sus ojos. En ellos, el personaje suele ir fuertemente armado y dispara a los enemigos mientras recoge ítems desperdigados por el nivel. Los más conocidos fueron: Wolfenstein 3D, Doom, Duke Nukem 3D y Quake.
Plataformas: este tipo de juegos suele consistir en un personaje, controlado por el jugador, que avanza por un nivel mediante movimientos rápidos y saltos. Los niveles suelen recorrerse en horizontal o vertical. Se podría considerar Super Mario Bros como el iniciador del género al que siguieron otros éxitos como Bubble Bobble o Rainbow Island.
Estrategia: son juegos donde la planificación de las acciones suele tener bastante peso a la hora de obtener un victoria. Existen varios subgéneros dentro de la estrategia, dependiendo de si consta de turnos, de la complejidad en la gestión (4X o Gran estrategia) o incluso por las condiciones de victoria, que no siempre tiene que ser militar. Uno de los juegos que sentó las bases de la estrategia en tiempo real fue The Ancien Art of War, aunque el género fue popularizado por Dune 2, Warcraft, StarCrafty Command & Conquer. En el caso de la estrategia por turnos Civilization fue el gran iniciador, al que siguieron otros títulos célebres como Master of Orion o X-Com. En el apartado de gran estrategia podríamos citar la saga Europa Universalis. En el apartado de juegos no militares, podríamos citar la saga Tropico.
MOBA («campo de batalla multijugador en línea»): género nacido de los juegos de estrategia en tiempo real, donde equipos de jugadores se enfrentan entre sí en un mapa usando personajes individuales con el objetivo de vencerlos o destruir su base. Los títulos más significativos en la actualidad son Defenseof the Ancients (DotA), League of Legends (LOL) y Heroesof the Storm (HotS).
Puzzle: estos juegos permiten al jugador aplicar estrategias y deducciones lógicas con el fin de conseguir ciertos objetivos. Suelen trabajar mucho con formas geométricas y combinaciones de elementos y colores que pueden ser movidos, intercambiados o rotados. También pueden incluir un tiempo limitado o bien introducir una competición con otro jugador para darle más emoción. El caso más claro de este tipo de juegos es Tetris.
Simuladores: como su nombre indica, intentan recrear un sistema del mundo real. Desde el funcionamiento de una ciudad (SimCity), de un avión (Microsoft Flight Simulator), de un negocio de transportes (Transport Tycoon) o de una nave espacial (X-Wing).
Sandbox: son juegos en los que se le da al jugador una gran libertad de movimiento, progresión y de opciones a la hora de resolver problemas, usando mecánicas de varios géneros distintos. Como ejemplos de Sandbox tenemos Minecraft y las sagas deGrand Theft Auto e Infamous.
incrementando conforme aumenta su experiencia. Además, pueden adquirir y usar objetos y armas que van recopilando durante el juego. Al contrario que sus equivalentes en papel, aquí no es necesario echar a volar la imaginación para situarse en el juego; además, las reglas están implícitas, lo que evita tener que memorizarlas. Las series Ultima, Baldur's Gate o Final Fantasy son algunos ejemplos de este tipo de videojuegos.
Carreras: el objetivo de estos juegos es llegar el primero a la meta. En muchos de ellos se intenta recrear lo mejor posible las sensaciones de conducir un vehículo en una competición. El primero en convertirse en éxito de ventas fue Pole Position.
Deportivos: estos videojuegos tratan de transmitir la emoción de practicar un deporte real. Esto incluye desde deportes individuales, a dobles o en equipo. El juego Summer Games o las series PC Fútbol, Pro Evolution Soccer y FIFA.
Musical: su desarrollo gira en torno a la música, ya sean de tipo karaoke, de baile o en los que se tocan instrumentos musicales. La mayoría de estos juegos se caracterizan por necesitar accesorios especiales compatibles con las consolas y por ofrecer modo multijugador, en el que los jugadores intentan conseguir el mayor número de puntos posible por medio de su actuación. Por citar algunos ejemplos, tenemos Singstar, Dance Central, Dance Dance Revolution, Rock Band, Guitar Hero y Bust a groove.
Minijuegos: son muchos juegos en uno, generalmente de muy corta duración y con unas reglas simples. Pueden ser parte de otro tipo de juego, ofreciéndose los minijuegos como una recompensa o como un requisito para seguir avanzando. En otros casos, el juego en sí consiste en la superación de un conjunto de minijuegos (por ejemplo, Mario Party).
Tradicionales: los equivalentes electrónicos de los juegos de toda la vida. El juego Noughts and Crosses (OXO) puede considerarse uno de los primeros juegos de este género, pero aquí también se incluyen los juegos de cartas, de mesa (ajedrez, damas), etc.
Educativos: los juegos educativos son aquellos dirigidos a aportar unos conocimientos o habilidades al jugador durante el transcurso del mismo. Se combina así formación con entretenimiento. Existen los claramente diseñados para una función didáctica, orientados normalmente a niños, entre ellos podemos citar Fine Artist, GCompris y El autobús mágico.
Serios: los juegos serios son un género muy reciente. Están diseñados no solo para entretener sino para que al jugar repetidamente se adquieran ideas que entran dentro del ámbito de la ética, la realidad social o el trabajo en equipo.
Nos han quedado en el tintero muchas posibilidades de Unity por explorar. Como ya hemos comentado hemos escogido como proyecto final un proyecto en 3D porque para la realización de un juego 2D hay muchos más tutoriales en la web que te explican cómo realizarlo. Mostramos en esta tabla una recopilación de juegos y contenidos con los que ampliar tus conocimientos en Unity.
Enlaces para ampliar aprendizajes
Aprendizaje por adquirir
Enlaces
Manual que explica cómo realizar un juego en 2D como Jetpack Joyride. En esta plataforma puedes encontrar otros tutoriales sobre Unity que te serán de ayuda.
Tutorial de Unity que permite crear un juego en 3D. Muchos de los conceptos los hemos dado en el curso pero amplía conocimientos sobre cómo animar el personaje y su interacción con los enemigos.
Materiales desarrollados inicialmente por el Ministerio de Educación, Cultura y Deporte y actualizados por el profesorado de la Junta de Andalucía bajo licencia Creative Commons BY-NC-SA.
Antes de cualquier uso leer detenidamente el siguenteAviso legal
Actualización de materiales y correcciones menores.
Versión: 03.00.00
Fecha de actualización: 28/06/20
Autoría: Lourdes Rodríguez Morón
Ubicación: No especificada. Mejora (tipo 3): Crear la unidad nueva.
Ubicación: En la sección 1.1.1 Mejora (tipo 1): Cambiar el enlace de LWJGL
Ubicación: 1.6.4 Mejora (tipo 1): Roto enlace Sprite Principe de Persia. Se sustituye por enlace a Generadores de Sprites.
Ubicación: Seccion 1.6.7 Mejora (tipo 1): Roto enlace Sprite Principe de Persia. Se sustituye por enlace a Generadores de Sprites.
Ubicación: 2.1 TEMA 4 Mejora (tipo 1): ENLACE ROTO EN Para saber más
Si quieres conocer los materiales con los que se fabrica un móvil, puedes echar un vistazo a la presentación del enlace siguiente:
¿De qué está hecho un móvil?
Ubicación: Mapa conceptual Mejora (Mapa conceptual): Se crea el mapa conceptual en base a los nuevos contenidos.
Ubicación: Guión, tabla de contenidos y objetivos Mejora (Orientaciones del alumnado): Se modifica todos los apartados en base a los nuevos contenidos de la unidad
Versión: 02.00.00
Fecha de actualización: 06/07/16
Autoría: Jaime Miguel Botonero Morillo
Ubicación: toda la unidad Mejora (tipo 3): Unificación de las tres unidades de videojuegos y realización en Android
Ubicación: No especificada. Mejora (tipo 2): Actualizar esta unidad con Videojuegos en Android y renombrarla.
Ubicación: No especificada. Mejora (tipo 2): Actualización a Android Studio.