miércoles, 26 de septiembre de 2007

Editor, Cámara, Acción!!

La última vez que escribí en este blog, estaba en Coquimbo celebrando las fiestas patrias. En ese entonces planifiqué que el siguiente paso en Avioncitos 3D sería la creación de un editor de terreno. De esta forma, cuando volví comencé a trabajar de inmediato en el editor.

El concepto de "Editor de..." corresponde a un programa externo al juego, que permite crear y modificar de manera relativamente fácil algún archivo que utilice el programa principal. En este caso es un editor de los archivos que guardan los ElevationMap, los cuales hasta ahora eran creados a mano en bloc de notas (mspaint, bloc de notas... no es claramente lo último en tecnología... al parecer son herramientas demasiado básicas para crear un juego 3D, aunque hasta ahora han funcionado). Hay que recordar que inicialmente el Sistema de terreno creaba el relieve basado en valores de variables que eran modificables sólo durante el diseño del juego, ya que formaban parte del código mismo del programa. En una segunda etapa, agregué soporte para cargar estos valores desde un archivo de texto externo, el cual guardaba todos los datos de elevación para un terreno en particular (ElevationMap), lo que permitía la edición desde fuera del programa, la creación de múltiples archivos, la posibilidad de compartirlos, editarlos sin tocar código, etc. Este sistema es el de elección para un juego de este tipo, ya que en teoría permitiría la adición de nuevos terrenos sólo mediante la incorporación de nuevos archivos de texto.
Hasta que volví de Coquimbo, todo funcionaba así. El problema más importante era que los archivos de elevación seguían siendo simples archivos de texto, por lo que toda la información que contenían no era más que números en un formato especial, que luego el Avioncitos 3D interpretaba como terreno. Debido a esto, los archivos eran complicados de editar, ya que requerían bastante imaginación para concebir a los números como una imagen, y por otra parte, no permitía manipulaciones más complejas como copiar un cerro completamente y pegarlo en otra parte del terreno, etc. De esta forma, hacer el terreno completo a mano, metro por metro, sería una tarea demasiado engorrosa y con resultados poco agradables estéticamente. Debido a esto surgió la necesidad de un programa con una interfaz más amigable, el cual fuese capaz de interpretar la información de los archivos en algún tipo de imagen, y permitiera manipulación más compleja de los datos.

A la fecha el editor de terreno está aún lejos de su funcionamiento planificado, pero ya posee funciones básicas como cargar un archivo de terreno, guardar una copia, mostrar el archivo completo o una fracción deseada, modificar directamente los datos (mediante una interfaz de texto) y copiar y pegar unidades de terreno, lo que facilitó enormemente la creación de áreas más extensas de terreno sin la necesidad de definir cada elemento individualmente. A la fecha también cuenta con herramientas para reemplazar masivamente áreas de terreno y mezclar distintas zonas a elección. De momento todo sigue operando en modo texto y botones, pero la interfaz gráfica con arrastrar y soltar, y funciones todavía más intuitivas está en desarrollo.

Cámaras

Gracias al aporte de la nueva herramienta, me fue posible crear un terreno algo más elaborado (sin reemplazar el anterior), para probar la nueva funcionalidad del avioncitos 3D propiamente tal: Las cámaras.

En un juego 3D, es de suma importancia el sistema de cámaras. A diferencia de las versiones bidimensionales, donde la visión suele ser fija, en un entorno tridimensional ocurren eventos en todas partes, que no pueden ser visualizados si no existe la posibilidad de cambiar el punto de vista. Básicamente la cámara corresponde al lugar ficticio desde donde el usuario mira al mundo 3D, la dirección hacia la que mira y algunos otros datos como el campo visual, la distancia máxima de visión, etc. Aparte de estos datos básicos, la cámara en los juegos 3D debe cumplir otra función: moverse "inteligentemente".
Hasta antes de crear el sistema de cámaras, el juego contaba sólo con una cámara básica que yo podía mover a voluntad (sin cámara no se vería nunca nada). Gracias a esto logre tomar todos los Snapshots desde ángulos distintos, y funcionaba bien hasta que el avión comenzó a moverse. Obviamente, el jugador debe preocuparse de mover su avión, pero la tarea de mover la cámara no le corresponde. Es por esto que la cámara debe seguir automáticamente la acción, manteniendo una visión óptima para que la jugabilidad no se vea limitada. Todo esto debe ser lo suficientemente autónomo para que casi pase desapercibido por el jugador, pero debe a la vez permitir la modificación de algunos parámetros para que el jugador tenga control sobre la cámara en cada momento. Claramente hay situaciones donde una posición de cámara es superior a otra, por lo que debe permitirse este nivel de personalización.

He llamado "programas de cámara" a 5 modos distintos en que la cámara se comporta según lo que ocurra en el juego. Esto da lugar a 5 tipos de cámara elegibles, todos con algún parámetro configurable por el usuario según necesidad.
De las 5 cámaras posibles, 4 corresponden a vistas externas del avión, mientras que uno es una vista interna desde la cabina del avión (vista de HUD).
Los 4 tipos de vistas externas corresponden a cámaras que siguen automáticamente al avión, ya sea trasladándose o rotando sobre su propio eje, de modo de no perderlo de vista. Según el tipo de cámara, el programa respectivo determinará la acción de la cámara para mantener la vista dentro de los parámetros configurables, como son la distancia al avión en cada uno de sus ejes, la posicion relativa, el radio máximo de rotación, etc. De esta forma, la cámara permite, por ejemplo en modo fijo, mantenerse siempre atrás del avión a una distancia fija, que puede ser modificada por el usuario, de modo de siempre tener la vista al frente. Por otra parte, el modo libre permite elegir mover la cámara para elegir una vista del avión arbitrariamente, para que luego la cámara mantenga esa misma visión del avión, independientemente de sus movimientos. Las vistas externas 1 y 2 mantienen al avión en el centro del campo visual, pivoteando la cámara sobre sus propios ejes, para evitar así traslaciones que pudieran desorientar al jugador. La cámara es también capaz de desplazarse para no perder el encuadre a pesar de los movimientos extremos del avión. La vista de HUD muestra la visión real que tendría el piloto del avión sentado en su cabina y observando a través del HUD. Este es el acrónimo de Head Up Display, y consiste en la proyección holográfica de los datos relevantes sobre el vidrio de la cabina (en realidad es una pantalla transparente justo al frente del piloto). Supongo que todo el mundo ha visto un HUD, y la mayoría lo recordará como los clásicos monitos, miras y relojes que aparecen en los aviones de TopGun, Stealth, y cada película de aviones fighters.) De momento el HUD es sólo una imagen fija (adivinen... Correcto, es paint!) proyectada en frente de la cámara de HUD. Más adelante el HUD se hará funcional, de hecho ya estoy diseñando los modos de display, el sistema de armas y toda la simbología que mostrará, pero no es prioridad actual. Cuando aparezcan nuevas necesidades, crearé modos de cámara nuevos, por ejemplo para seguir a un blanco designado, seguir a un misil, a un avión enemigo, etc.... (Se hace camino al andar...)

A continuación algunas imágenes del juego en su estado actual, con el archivo de terreno procesado por el esbozo de editor; y los modos de cámara en acción.


En la imagen anterior se observa al Shark volando sobre las clásicas casas de siempre. De fondo se observa un complejo montañoso que encierra un valle angosto ideal para ocultarse. Nótese que agregué en el juego mismo información sobre el frame rate (los cuadros por segundo a los que corre el juego; mientras más, mejor) y la cámara activa, en este caso Libre.


En la imagen anterior se observa al Sw71 desde una "vista de pájaro" lograda mediante el modo de cámara libre. Nótese como el frame rate cayó dramáticamente a 30 fps, debido a la mayor cantidad de polígonos en escena.


La anterior es una de mis favoritas: El Shark volando sigilosamente por el valle creadoentre las cadenas montañosas. De fondo se observan las casas donde esperan el retorno del intrépido piloto (XD)...



La imagen anterior muestra al veloz Pyrage cruzando a baja altura por el valle angosto. La cámara se ubica a ras de piso, siguiendo angularmente la trayectoria del avión.



La última imagen muestra la vista de HUD. Hasta el momento la proyección del hud es sólo una imagen fija superpuesta. Posteriormente agregué la capacidad de cambiar el color de la imagen del HUD, para evitar problemas de contraste entre fondo y HUD (como en la foto). Todo esto mediante el uso del blending multiple de texturas en una pasada. Más adelante el HUD se volverá totalmente operativo.

Posteen comentarios, sugerencias, ideas, etc. Se agradece a los que ya han escrito.

Nos vemos en un próximo informe de avance... (Antes que empiece la posta!!!)

miércoles, 19 de septiembre de 2007

Terreno

Desde Coquimbo escribo esta actualización del Blog. Hasta ahora no he introducido nuevas mejoras al juego, por lo que este artículo representa el estado actual, que es como quedó antes de venirme a celebrar las fiestas patrias.

Cuando las entidades quedaron funcionando bien con su iluminación y cascada de texturas, decidí avocarme a construir el otro gran componente del escenario: El terreno. Sabía que no podía ser un terreno pequeño, ya que el avión recorrería grandes distancias en cada etapa. Además, a pesar de que el juego no es un simulador, por el sólo hecho de tener un avión como protagonista, merece un terreno con cerros y elevaciones.

La primera idea fue sencilla: Hacer todo con triángulos. En realidad no hay otra forma (por lo menos para mí). El problema era crear los miles de vértices que representen cada punto del terreno. Me decidí por hacer un rectángulo enorme (sólo 6 vértices), sobre el cual se superpusieran los cerros como entidades. Esta idea fue rápidamente desechada, ya que el terreno no tendría la flexibilidad para mostrar suelos ondulados, acantilados etc. Por esta razón, decidí crear todo el terreno como una sola unidad, donde las elevaciones correspondan a puntos más altos de esta única superficie. Pensé en que también debería ser autogenerado, es decir, que a partir de una matriz con datos de elevación, el programa automáticamente construyera los vértices, pusiera las normales y texturara cada subunidad de terreno. Me quedé pensando en como realizar todo esto. La solución vendría a aparecer recién e día siguiente.
Encontré en mi casa un trozo de pasto artificial, donde meses atrás vivió Pinxa, mi erizo de tierra. Por encima parecía una superficie contínua y sólida, pero al mirar por debajo se evidenciaba que no era más que una red de trabéculas plásticas, en cuya intersección se insertaba una mota de pasto plástico. La malla estaba formada de estructuras triangulares agrupadas en cuadrados, y tenía la particularidad de poder moldearse en cualquier forma. Entonces decidí usar esa misma arquitectura en mi terreno. Si pudiera asignar un valor de elevación a cada intersección trabecular (lo que corresponde a un vértice), podría crear elevación en el terreno. Ya que cada vértice era común para varias triángulos, al elevar un vértice en particular, todo el terreno que lo rodee se debería amoldar para seguir la forma del punto más alto, al igual que con el pasto plástico.
Entonces ya tenía la idea, ahora había que implementarla. Cuando comencé a pensar en código, no estaba en mi casa, por lo que no podía probar de inmediato. Escribí mi primera versión del sistema de terreno en una hoja de papel, para que al día siguiente pudiera recordarla. Cuando volví a mi casa tipeé lo que había en la hoja, llené la matriz de elevación (desde ahora el "mapa de elevación")con ceros, y lo puse a correr. El sistema generó miles de vértices en segundos, los puso en un VertexBuffer y luego mi render los dibujó. Era un rectángulo largo que representaba un terreno plano. Estaba funcionando.
El problema comenzó cuando intenté ampliar el número de subunidades de terreno. Llegué a construir tantos vértices que no hubo buffer capaz de almacenarlos. Con mi mejor tipo de vértice, cada uno ocupaba 40 bytes en el Buffer. Descubrí de manera desagradable que no podía poner más de 32767 bytes en cada buffer, y eso me limitaba a 819 vértices para todo el terreno. Tuve problemas tratando de dividir el terreno en muchos buffers, por lo que decidí descartar los buffers y almacenar toda la geometría en un array gigante, que no ha dado problema hasta ahora.
Para probar la elevación, cambié un par de datos en el mapa de elevación, simulando un desnivel en el terreno a modo de cerro. Renderizé todo en modo WireFrame para observar con detalle la malla de triángulos que formaba mi estructura. El resultado el el siguiente:



Luego probé con paneles sólidos, para ver cómo funcionaba la iluminación y mis normales autogeneradas. Decidí agregar más cerros, por lo que escribir directo en el mapa de elevación se volvió engorroso. Entonces creé una función que cargara el mapa de elevación basado en un archivo de texto. En bloc de notas escribí unos cuantos números y lo guardé como elevation.txt. Al correr el juego, automáticamente se tomaron esos datos de elevación y el mapa de elevación se autorellenó. Aparecieron todos los cerros que había definido en bloc de notas y la iluminación funcionó bien sombreando el relieve. Tomé un snapshot que se vio así:



Texturas de terreno

Cuando todo anduvo bien, fue hora de comenzar con las texturas. Agregué soporte para textura Stage 0, dibujé en paint algo que debiera parecer pasto y se lo agregué. Además agregué las casas que había hecho antes. Este es ese primer terreno texturado.



Se veia bastante bien, aunque demasiado brillante, así que decidí usar una textura de pasto real:



Posteriormente agregué el soporte de doble textura. La idea era que se pudieran mezclar dos texturas distintas para realizar transiciones de una textura a otra, agregar rugosidad a un terreno de un color ya determinado, cambiar el color de un terreno, etc. También agregué un sistema de mapeo de texturas, capaz de tomar una fracción de la textura original y usarla como textura en sí. Esto permitiría incluir muchas texturas en un mismo archivo y seleccionarlas en el mismo programa. La siguiente imagen sicodélica muestra una prueba del nuevo sistema, donde un triángulo de cada subunidad utiliza como textura a una imagen con varios colores, mientras que el otro triángulo usa como textura sólo a la porción roja de la misma imagen.



Finalmente hice que cada subunidad fuese capaz de mostrar una textura independiente. De este modo, los kilómetros de terreno ya no deberían lucir iguales. La información acerca de la versión de textura que usaría cada subunidad(en realidad referencia a una fracción distinta de un mismo archivo de imagen)está contenida en otro archivo de texto que llamé "Mapa de Texturas". De este modo, el terreno está definido en dos archivos de texto pequeños, que cuando tenga completamente definidos voy a fusionar en uno solo. También debo agregar la información sobre las entidades y su posición, lo que actualmente sólo se puede hacer desde el código.
En el siguiente snapshot se puede ver al terreno con una parte en pasto, otra con manchas blancas que corresponden a sitios de fusión con la textura stage 1; y muchas caras sonrientes. Estas últimas corresponden a la forma en que decidí que el programa manejara las subunidades para las que no hay información de textura disponible. Está lleno de estas subunidades "data not found" porque sólo designé texturas para las subunidades de la primera fila (era sólo una prueba). En realidad las caras sonrientes están formadas del blending de dos texturas: Una cara feliz (Smiley, Kirbys, o como le llamen)amarilla con lengua roja; y un fondo rojo. De esta manera se muestra como se mezclan dos texturas con facilidad. También se evidencia el sombreado en los cerros, la texturización independiente de cada subunidad, la integración con las entidades, y la generación a partir de archivos de texto. Es por esto que esta imagen, aunque no muy espectacular, muestra las capacidades máximas actuales del sistema de terreno recién creado.



La idea ahora es seguir mejorando el sistema de terreno, crear herramientas para editar con facilidad los archivos de texto (un editor de terreno o algo así)y aprender a usar un programa de edición más decente que paint para las texturas (se me está haciendo muy dificil trabajar con paint lo de las páginas de texturas). Todo eso cuando vuelva a Santiago, porque por ahora, a disfrutar mi último día de fiestas patrias. ¡Viva Chile!...

domingo, 9 de septiembre de 2007

Luces

Me he dado cuenta alegremente que ya tengo algunos comentarios en el Blog. Se agradece el aporte...

La última vez que escribí, había logrado poner dobles texturas en las casas, con musgo incluido. En ese momento me surgió la inquietud de la iluminación. Hasta el momento, todo el color provenía de los vértices y estaba predefinido. Eso funcionaba bien, porque era confiable, pero planteaba un problema con el realismo, dado que todos los objetos lucían una iluminación pareja, que les restaba calidad y a la vez hacía que se perdieran detalles de profundidad por falta de contraste entre colores idénticos.

Cuando decidí que necesitaba luces, hice lo mismo de siempre: Me puse a leer. Aprendí algo de teoría de iluminación y me di cuenta que no era tan dificil, pero sí que me llevaría un tiempo mayor del presupuestado. De todas formas valía la pena y comencé.

Dado que este blog tiene algún fin didáctico, voy a explicar un poco lo que aprendí en cuanto a luces y el problema que me planteaba:

Poner luces en realidad no cuesta nada. Sólo hay que definir algunas cosas, poner ampolletas por aquí y allá y el motor de iluminación de DirectX hace el resto. La única limitante es que no proyecta sombras, pero no es gran problema todavía. Lo que sí me incomodó un poco, es que necesitaba un tipo de vértice especial: uno que fuese capaz de contener una normal. Además de eso, dado que yo usaba dobles texturas, este tipo de vértices debía tener soporte para doble coordenada. Entonces tuve que volver a definir un tipo de vértice con esas características y cambiar la geometría genérica para que utilizara este nuevo tipo de dato. Después de algun tiempo el resultado quedó así:



La casa que aparece en negro utiliza el nuevo tipo de vértices y funciona basada en la iluminación. Como todavía no había definido nada de luces, la casa se ve negra, a diferencia de las demás que siempre se ven igual, independientemente de las luces.

Configurando la iluminación

Algunos párrafos atrás apareció la palabra "normal". Voy a explicar un poco lo que significa o lo que comprendí respecto a esto.
Cuando trabajamos con polígonos en Direct3D, definimos el triángulo por sus tres vértices. El triángulo sólido en sí vendría siendo el plano que contiene a estos tres vértices, pero sólo la región comprendida entre ellos. Por geometría es evidente que entre 3 puntos pasa un sólo plano, pero esto llevado a la realidad nos deja un problema, el plano tiene 2 "caras", es decir, puede estar mirando hacia nosotros o hacia el otro lado. Cuando trabajamos sin iluminación, esta ambiguedad no supone problema, dado que el triangulo se renderizará igual, sin importar hacia donde apunte la cara "real". En cambio al iluminar, sí tiene importancia este hecho, dado que la luz es incapaz de atravezar el triángulo, y por tanto sólo una de las caras se verá iluminada. (un cajita de fosforos cerrada puede estar muy iluminada por fuera, pero las mismas paredes por dentro sigue oscuras). Es por esto que debemos acabar con la ambigüedad, indicándole a DirectX cúal es la cara que mira hacia afuera. Para esto, le asignamos un vector perpendicular al plano, que apunte simepre en el mismo sentido. De esa forma DirectX será capaz de diferenciar las dos caras del mismo polígono (la que mira hacia la normal, y la que está en el lado opuesto). Ese vector, cuando mide sólo una unidad (así no interferirá cuando multipliquemos) se llama normal.
Ya sabemos para qué sirve, ahora debemos crearlo. Obviamente a mano no es la mejor idea, porque son muchos vectores y no quiero hacer la trigonometría yo solo. Decidí usar una función que creara las normales automáticamente a partir de los vértices de un triángulo. Para crear una función, necesitaba saber la teoría de cómo hacerlo matemáticamente, para luego escribir una expresión general que el VB fuera capaz de entender.

Los números detrás de la luz

Lo ideal en este punto es comenzar a trabajar vectorialmente. DirectX tiene una estructura de tipo VECTOR, que es perfecta para guardar una normal. La idea es crear primero un par de vectores que definan el plano del triángulo. Esto se logra trazando un vector entre los vértices 1 y 2, y luego 2 y 3. De esta manera, el triángulo dejó de ser un conjunto de tres puntos, y se convirtió en un par de vectores. Sólo necesitamos dos de estos, ya que los tres puntos en el triángulo son coplanares, por tanto, el plano que contenga a los dos vectores recién creados, será el mismo que contendría al tercero, por lo que no es necesario incluirlo en los cálculos. Aquí viene la parte interesante (creo..). Para obtener un vector perpendicular al plano que contiene dos vectores, lo único que debemos hacer es calcular el producto cruz entre ambos vectores. El vector resultante sería un vector de misma dirección y sentido que la normal que buscamos. El sentido está determinado por el orden de los vectores en la multiplicación, por lo que es muy importante pasar los vértices en el orden correcto, siempre en sentido horario mirando el triángulo desde "afuera". Con esta convención nos aseguramos que todas las normales apunten en el sentido de la cara que se debe iluminar. Hasta este punto tenemos un vector que es casi una normal, sólo que tiene una magnitud desconocida. La solución al problema es simplemente normalizar al vector, es decir, llevarlo a magnitud uno sin modificar dirección y sentido. El DirectX tiene una función que hace este trabajo automáticamente, aunque supongo que podríamos lograr el mismo resultado dividiendo el vector por el valor absoluto de sí mismo.
Finalizado todo esto, tenemos la normal del triángulo. El punto siguiente es asignarla a cada vértice, de ahí que se requiera un tipo de vértice con soporte para las coordenadas de la normal (puede ser un vector directamente, pero preferí definirlo como las tres coordenadas que lo definen). Una vez asignadas las normales, el triángulo está listo para ser iluminado.

Después de la teoría de las normales, sólo basta hacer una función en VB que realice este proceso con cada vértice. Hay que aclarar que no soy ni ingeniero, ni nada parecido, así que puede que esté hablando puras tonteras.. Al menos lo que dije es lo que aprendí para hacer este tipo de cosas.... Que se manifiesten los matemáticos si algo no está bien... Habrá que ver qué piensa la Camy de todo esto.... De todas formas, creanme que a mi me ha funcionado. Pueden verlo en la siguiente imagen:



Se puede apreciar claramente que la ex casa negra, ahora tiene color. Está bajo una iluminación ambiental tenue, y es claramente distinta a las demás casas que no se afectan por la luz.

En este punto del proyecto, ya tenemos todo lo complicado funcionando. Logramos generar normales para cada vértice de la casa, por que la iluminación ya está disponible. El paso siguiente es crear luces y ver cómo se comportan los modelos.
En la imagen de recién sólo tenía una luz de ambiente, que proviene de todas dirección y por tanto, sólo produce un efecto de brillo o atenuación general. La idea es agrega ahora luces direccionales, que simulen que la iluminación viene de una direccion en especial, como sería la luz del sol.

Agregué un par de luces direccionales y el resultado es el siguiente. Nótese la diferencia de tonos entre el frente de la casa y la pared. Esto no es un cambio de textura, son los efectos de la iluminación, donde la luz incide de manera más directa sobre el frontis que en la pared. En las casas sin iluminación este efecto no ocurre.



Como todo resultó bien para esa casa, decidí repetir el método para todas las demás casas. Cambié el tipo de vértice y repetí el proceso. El resultado fue claramente distinto a lo que esperaba....



Ese ejército de mantarrayas de otro planeta, se supone que eran mis casas... El error fue el mismo que la vez anterior. Al cambiar el tipo de vértice, debía modificar la manera en que se calculaba el tamaño de los buffers... Son cosas que pasan... Decidí guardar el snapshot de todas formas... (No serían malos enemigos.. Las mantarrayas asesinas.. Tema para el próximo juego)..XD

Corregí el error, apliqué texturas dobles a todas las entidades, encendí las luces y tomé un snapshot. Así quedó mi población con doble textura e iluminación. Por fin las casas estaban finalizadas como entidad. Ya podría comenzar a programar otra parte del juego.



Bonus Track

Antes de terminar, decidí crear una textura alternativa. Durante el verano había hecho un viaje a Pedernales, una localidad de la V región. Ahí encontré una casa que me gustó bastante, está hecha de pedernal, una roca que abunda en ese sector. Tengo una foto mía en la casa. Entonces tomé esa foto, corté un pedazo y la usé como textura. Tomé una puerta y una ventana de otra casa y compuse todo en paint.


Esta es la foto original de la casa en Pedernales.



Y así quedaron las casas, iluminadas, doble textura, con una capa de foto real y una de musgo hecho en paint. Con esto me bastó para dar por terminadas las casas y comenzar a pensar en el paso siguiente: El terreno...

viernes, 7 de septiembre de 2007

Entidades

A pesar del nombre sugerente de mi juego, claramente debía tener algo más que sólo aviones. Consideré que ya era tiempo de agregar otros elementos al escenario: Casas, edificios, vehículos, etc. Decidí llamar genéricamente a todo esto "entidades", para diferenciarlo del otro elemento del escenario, que vendría a ser el "terreno".

Para comenzar declaré un tipo de dato "Entidad estática", para que definiera en general a todas las entidades que no se movieran, y por tanto, que prescindieran de inteligencia artificial. Cada objeto de este tipo, contiene cuatro VertexBuffers, que almacenan la geometría para los 4 distintos niveles de daño que puede sufrir. Una vez creado el tipo, llegó la hora de crear la geometría en particular e instanciar el objeto.

Decidí empezar haciendo una casa: Es un objeto bastante simple de dibujar y me permitiría probar rápidamente si estaban funcionando mis ideas. Creé unos cuantos vértices, llené los buffers, instancié una casa genérica, y luego le pedí al programa que me creara tres casas personalizadas basadas en esa geometría genérica más unos cuantos parámetros de posición individuales para darles una ubicación particular.

El resultado fue este, las primeras entidades estáticas del juego:




Cuando todo comenzó a andar bien, completé los paneles triangulares del techo de las casas y creé una función para generar con facilidad todas las casas que quisiera. Gracias a esto apareció la primera "ciudad, población, condominio, o lo que sea"...



Las Texturas llegaron Ya.....

Cuando comencé a diseñar el juego, decidí que no lo texturaría, dado que: 1) Nunca había puesto una textura, jamás en toda mi vida... y 2) Aunque aprendiera rápido, sería un trabajo eterno mapear a mano vértice a vértice cada elemento. Hay que recordar que toda la geometría está diseñada a mano, dibujada en el primer papel que encuentro cerca y luego tipeada vértice por vértice en el programa. Si esto ya es un gran trabajo, agregarle coordenadas de textura sería mucho más complicado y podría quitarme las ganas de continuar...

De todas formas, cuando tuve las casas quise que se vieran mejor. Entonces aproveché un fin de semana y recopilé bastante información sobre texturizado en DirectX8. Cuando sentí que podía hacerlo, dibujé una textura sencilla en paint (Tal vez sería bueno conseguirme el photoshop.. aunque todo en paint lo hace bastante más artesanal :P) un poco inspirada en la casa en que vivía el año 97, cuando conocí VB :P. Apliqué la textura y el resultado fue el siguiente:



Quedé bien conforme con el resultado, lo que me motivó a leer más. Aprendí sobre blend de multiples texturas en una sola pasada. Entonces decidí implementar mi primera cascada de texturas. Para eso tuve que crear un nuevo tipo de vértice, con soporte para doble coordenada. Eso implicó rediseñar las casas, lo que me entregó una nueva entidad genérica. Cuando parecía todo listo, ejecuté el programa y el resultado fue bastante freak, como se ve a continuación:



Eso que parece un perro de otro planeta, se suponía que era una casa. El problema fue que calculé mal el tamaño de un VertexBuffer. Con un poco de paciencia logré encontrar y corregir el problema. Entonces tuve lista mi casa con soporte de doble textura. Ahora debía utilizarlo. Abrí el paint y con el spray dibujé unos musgos sobre un lienzo blanco. Configuré mi cascada de texturas para que los dibujara sobre la casa recién hecha, y el resultado quedó así:



Gracias a ese fin de semana las casas ganaron bastante realismo, y yo mucha motivación para darme el trabajo de texturizar todo lo que hiciera de ahí en adelante. Además, me surgió una nueva inquietud: Si las casas ya tenían texturas, ahora merecían iluminación, pero eso ya es tema de otra entrada en este Blog.

miércoles, 5 de septiembre de 2007

Buscando el movimiento

Cuando ya tuve los aviones diseñados y dibujados. El desafío siguiente fue lograr controlarlos. Lo que más tiempo me tomó fue diseñar e implementar el sistema de movimientos. Decidí crear un avión que se moviera de manera predecible al estilo arcade. Básicamente el avión se traslada sobre sus 3 ejes, pudiendo combinar estos movimientos. Para agregar algún efecto interesante, decidí incluir una animación breve de alabeo o cabeceo del avión, previo a comenzar la traslación en sí. Realmente esto me tomó mucho tiempo, y significó volver a familiarizarme con el añejo GetTickCount de la API de Windows.

Al terminar el proceso, cada avión cuenta con las mismas animaciones en sí, aunque variables en cuanto a velocidad, basadas en datos particulares de cada avión. Así, cada aeronave tiene sus propios parámetros de agilidad en cada una de las dos fases del movimiento (animación y traslación), permitiendo la variabilidad deseada entre los distintos tipos de avión.

Cuando el sistema de movimientos estuvo completo, decidí agregar soporte para Joystick. Esto sí resltó totalmente novedoso para mí, ya que nunca había intentado semejante empresa. Luego de algunas noches leyendo tutoriales y husmeando en MSDN, logré implementar un soporte sencillo para mi joypad de 12 botones, basado en DirectInput8, el que funcionó perfectamente. Mi joystick (lease "palanca") también funcionó correctamente, aunque la limitación a movimientos estereotipados no saca ventaja de las múltiples posiciones posibles en los ejes de un joystick, en oposición a los 3 valores discretos del joypad (Ejemplo: Izquierda, Centro, Derecha). Claramente este juego está hecho para un joypad... Es arcade, no un simulador.
Otro hecho interesante fue el soporte de ForceFeedBack, el cual utilicé solo a modo de efectos de vibración, ya que los joypad no tienen un ForceFeedBack real. (y no me quise tomar el tiempo de crear una característica no soportada).

Durante las pruebas del sistema de movimientos y el joypad, tomé un video que difundí entre mis amigos para captar sus impresiones sobre el juego. Desde entonces estoy recibiendo bastante feedback y logré captar la atención en el proyecto. Gracias a esto, decidí empezar este blog.


Este es el video del que hablo: Después de su grabación, el sistema de movimientos no ha sido modificado en su esencia, sólo le he realizado algunas optimizaciones de código, y decidí mover el soporte de joystick a un módulo propio, para tratar de poner orden en mi proyecto.