martes, 23 de octubre de 2007

Editando al Editor

Ha pasado bastante tiempo desde que escribí la última vez. En parte porque Reumatología me tuvo bastante ocupado hace unas semanas; y también porque escribir en este Blog es realmente mucho más rápido que avanzar en el juego. A pesar de todo, he trabajado bastante en el proyecto, y hoy publico los resultados.

En estricto rigor, del juego no he tocado ni una sola línea de código. Todos los esfuerzos están centrados, por ahora, en el editor de código. La última vez que hablé de esta herramienta, era aún una utilidad pequeña que mostraba sólo texto y tenía poca funcionalidad (aunque ese poco supuso un enorme aumento en la velocidad con que pude diseñar el nivel). De todas formas, el paso siguiente consistió en agregar nuevas funciones y obviamente, una interfaz visual más amigable.

El plan inicial era mostrar el nivel en plano, es decir, representar cada subunidad por una grilla que tuviera la textura correspondiente y algún número que mostrara la elevación. Mediante esta interfaz debería poderse modificar la textura a nivel de subunidad, y la elevación a nivel de vértice. Con esto, el editor se volvería muy fácil y rápido de usar. El problema que siempre llega después de la iluminación es "Ya está la idea, ¿pero ahora cómo la implememento?"

Recordando viejos tiempos

Algunos años atrás, hice un juego de fútbol en tablero, así como también un Battleship; en C Sharp, y ambos programas utilizaban una clase "Tablero Gráfico" genérica, que me sería sumamente útil para mis propósitos. Esa clase la creó un ayudante del curso, y era capaz de detectar los clicks, traducir las coordenadas en filas y columnas, marcar con colores las casillas, etc. Lo que yo necesitaba era algo parecido, pero con mayor funcionalidad, pues en vez de colores necesitaba texturas, además de discriminación entre vértice y área (para seleccionar la subunidad entera o sólo el vértice), y algunas cosas extras como capacidad de mostrar texto y lo que se me fuera ocurriendo en el camino. (Al momento de imaginar el programa me pongo a dibujar sobre un papel, y luego veo como implementarlo. Al momento de programar van cambiando las ideas y todo termina bastante distinto a como se planeó, es por eso que desde el inicio el diseño debe ser lo más flexible posible). Como ahora no trabajaba en C Sharp (Tanto el Avioncitos3D, como el editor de nivel están hechos en Visual Basic 6.0) no podía simplemente buscar la clase TableroGrafico y utilizarla. A lo más podría haberla leído y "traducido" a Visual Basic, pero al final, terminé decidiendo crear mi propia grilla desde cero, con las funcionalidades exactas que necesitara. Ahora bien, el C Sharp tiene funciones gráficas bastante más poderosas que las del Visual, ... La realidad es que las del Visual son horribles. Esto me dejaba sin la autosuficiencia del C Sharp para manejar los gráficos por sí solo, por tanto en mi caso debí buscar un "partner gráfico" para complementar al escueto Visual Basic.

Lo primero que pensé fue BitBlt... Es cierto que es bastante viejo, lento, etc. Pero se ve bastante bien para transferir los bitmaps de las texturas al formulario. De hecho, cuando imaginé el sistema, siempre tuve en mente a BitBlt para implementarlo.

Lo primero que hice fue leer sobre BitBlt de nuevo. Habían pasado muchos años desde que lo usé por última vez y me dediqué de lleno al DirectX. Cuando ya resfresqué la memoria, me di cuenta que no sería tan bueno como creía. El problema principal era que necesitaba copiar la imagen desde un Device Context, en el caso más simple un control Picture, pero nunca directamente desde un archivo. Al parecer la solución más simple sería usar DirectX7 y trabajar con Surfaces y BltFast, pero de esto no sabía mucho y no me agradaba la idea de mezclar tantas APIs en un solo proyecto. Al final me decidí por DirectX8, usando Transformed and Lit Vertices, tal como hice con el HUD en avioncitos.

Editando el Editor

Decidía crear mi grilla como una ventana de 8 por 8 subunidades, que se pudiera desplazar sobre el nivel y fuera mostrando información de elevación y textura de las 64 subunidades contenidas. Cuando dibujé los cuadros que representaríasn las subunidades, intenté hacerlo mediante TriangleStrips en vez de TriangleLists, lo que me ahorró muchos muchos vértices. Pensé que sería la solución ideal para rediseñar el Sistema de terreno del avioncitos (que usa 6 vértices por subunidad!!! una cantidad enorme, y se está quedando con frame rates muy muy pequeños). Sin embargo, al usar TriagleStrips surge el problema para mapear las texturas, que ya no podrían ser independientes, lo que atentaría contra la flexibilidad y realismo del juego. Por esta razón, decidí quedarme con los TriangleList y solucionar de otra forma (y en otro momento) el problema del Frame Rate.

Después de algunos días de trabajo (¿dos o tres?), el editor quedó con su "grilla de subunidades" operativa y una funcional adicional: Un previsualizador 3D del terreno. Usé la misma lógica del sistema de terreno del avioncitos y creé una ventana navegable que permite moverse por el terreno y visualizar en 3 dimensiones y de manera inmediata, los cambios hechos al archivo de terreno, incluso sin haber escrito aún en éste (Trabaja sobre una copia en la RAM, que sólo se graba al archivo en el disco cuando se está conforme con el resultado).

Hoy decidí subir algunos snapshots del Editor de terreno, que si bien no está totalmente funcional (Le faltan las herramientas para manejar texturas y más funcinalidad respecto a las elevaciones), de todas formas funciona y ya está siendo de utilidad para el diseño del juego.



La imagen anterior muestra la interfaz actual del editor, con la ventana de previsualización 3D a la derecha y el archivo de elevación en modo texto a la izquierda. La barra de menús permitió agregar comandos de edición ahorrando botones en la pantalla. En la vista 3D la cámara se puede mover libremente con los controles de posición.


Esta imagen muestra al editor en modo "diseño de texturas". En la ventana de la izquierda se encuentra representado en plano un trozo de la geometría, para así editar las texturas de cada subunidad. Nótese como las bandas blancas, en la visión plana, se corresponden con las que aparecen en el cerro visible en la previsualización 3D. La edición de los patrones de textura se refleja inmediatamente en la geometría 3D.


Este es un ejemplo de una operación que sin el editor sería muy complicada. Vamos a copiar el cerro indicado con la flecha y lo pegaremos en la ubicación de la marca blanca, de modo que ésta sirva como textura para tapizarlo. Para esta operación se recurre a la función Copiar/Insertar del menú Edición.


Aquí vemos el resultado de la operación: Una copia del cerro original (al fondo), que utiliza la textura de la marca blanca donde fue creado. Este patrón de texturas podrá editarse fácilmente en el modo de edición de texturas.

Esta es una muestra inicial de la evolución del editor, que pasó se ser una ventana simple con algunos botones; a una interfaz rica, con menús y vistas 3D. En el futuro pretendo mejorar la interfaz gráfica de edición de elevacion y texturas, para que crear terrenos llamativos se vuelva una tarea simple. ¡El proyecto sigue avanzando!

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.

lunes, 27 de agosto de 2007

Comienza el proyecto

Comenzó Agosto, y con él mi último proyecto de programación: Avioncitos 3D. El origen de este juego se remonta a los días, no tan lejanos, cuando con RT jugábamos Strikers 1945 en su casa después de los ECOEs. Avioncitos 3D está inspirado en los juegos de este tipo, por lo que he decidido hablar un poco de lo que tienen en común y en lo qu se diferencian..

De partida Strikers 1945 es un juego de Arcade, emulado en MAME, similar a la mayoría de los juegos de aviones en scroll vertical. Cuenta con las típicas bombas que arrasan con todo en la pantalla, los powerups, y el jefe grande al final de la etapa. Lo que le otorga cualidades especiales respecto a los demás del género, tal vez sea el Super Shot y la gráfica un tanto superior. Realmente es un juego adictivo, donde más que volar un modelo real de avión, lo que se consigue es movilizar endemoniadamente el aeroplano entre nubes de balas enormes y coloridas. Si bien el avión realiza maniobras fisicamente imposibles (retrocede fácilmente), esto le otorga la gracia al juego: Evadir millones de disparos a gran velocidad. Como todos los juegos del género, cuenta con enemigos en tierra y en aire, donde en realidad. las balas les afectan simultáneamente a ambos, de modo que el efecto de profundidad es sólo simulado. Realmente los movimientos ocurren en un solo plano.

Con Avioncitos 3D he pensado en recrear la lógica del juego, volando un avión de manejo estereotipado a través de escenarios plagados de enemigos y proyectiles. Avioncitos 3D NO ES un simulador de vuelo. Es una versión de un juego de scroll, salvo que todo ocurre en tres dimensiones. Dada la intensidad de las escenas 2D, me pareció sumamente interesante lo que podría llegar a ser volar en un campo de batalla tridimensional.

¿Por qué avioncitos?

Cuando pensé en hacer mi propio juego, decidí que fuera de aviones porque: 1) Me encantan los aviones y todo lo que tengan relacionado. 2) Por que tenía ganas de tener mi propia versión de Strikers 1945 y 3) Porque los aviones son cuerpos sólidos que requieren mucha menos animación que personajes más biológicos.

Una vez decidido a comenzar a programar, la pregunta fue ¿Cómo hago un juego en 3D?.
A los que se dieron la lata de leer mi historia, les quedará claro que he tenido bastantes acercamientos a la tarea de programar, pero que nunca me he dedicado en serio a aprender ningún lenguaje. Al momento de comenzar el juego ya tenía decidido que sería en 3D, por lo que al menos la API estaba decidida; DirectX8, por ser aquella única en que logré renderizar algo alguna vez (Super Bong, por el año 2005.. Vean mi historia en la primera entrada.)
Después de mi aproximación inicial a DirectX8 con VB, lo dejé de lado y comencé con C#, lenguaje del que algo aprendí, pero bastante poco. Al momento de decidir hacer el juego de avioncitos, pensé en aprender DirectX9 y usarlo con C#, pero claramente esto significaría invertir más tiempo del presupuestado en aprender. Finalmente, después de un fin de semana completo bajando y leyendo manuales de DirectX8, opté por comenzar con esta API en entorno Visual Basic, que era a lo que más estaba acostumbrado. A medida que el programa creciera, pensaría en migrar a una API más reciente y a un lenguaje .Net.

Recordando viejos tiempos

Desde hace siglos no escribía una línea de código, hasta que un buen fin de semana busqué en CD del Visual entre las cajas de CDs viejos y lo instalé. Lo más elaborado que había creado en geometría hasta entonces, era un paralelepipedo que servía de paleta en Super Bong (un Pong en 3D). Sabía que de ahí a dibujar aviones había una diferencia enorme, por lo que pensé en cómo solucionaría el problema de los modelos. Por lo que había leído, la solución inteligente era usar un software de modelado 3D e importar los mesh com archivos .X . De todas formas, yo soy un poco más impaciente y no quise ponerme a estudiar modelado 3D primero(Según sé, cuesta bastante dominar el 3D Studio Max)así que decidí por dos opciones: Crear modelos a mano bastante sencillos, pero entendibles; o bien, crear en Visual Basic mi propia herramienta para diseñar modelos 3D de manera sencilla. Me gustó la idea, pero antes de lanzarme a crear mi propio software, debía recordar como se hacía a la antigua, por lo que me dispuse a crear un modelo simple, especificando la geometría a mano, vértice por vértice en un array de este tipo.

...Para los que no entiendan mucho del tema, al menos en DirectX, toda la geometría está basada en triángulos, por lo que para construir una figura, se deben especificar las coordenadas de cada vértice, los que el programa luego completa y da forma en un ambiente 3D. Hay una manera fácil de hacerlo (con un programa con que uno sólo dibuja, y luego automáticamente se generan las coordenadas); y una difícil y poco clever, que es imaginar el avión, luego imaginarlo dividido en triángulos, para luego imaginar cada vértice en un sistema cartesiano de tres ejes, y finalmente meter al PC todos esos números....

Primer día de trabajo

Cuando tuve inicializado el motor de D3D, comencé a diseñar mi modelo de prueba. Un avión sencillo basado en un paralelepípedo central como fuselaje (hasta ahora no había hecho más que esas figuras). Tendría un par de triángulos por lado, por tanto 8 primitivas para el fuselaje. Luego cuatro triángulos cerrando el "cilindro" por delante, le darían apariencia de avión. Cuando terminé de dibujar esto, el resultado me sorprendió bastante. Se veía mucho mejor de lo que creía, para ser una primera vez. Me emocioné y agregué un par de triángulos para crear cada Ala (dos planos triangulares montados uno sobre el otro con ligera angulación). Al final me decidí y agregué los planos de cola y el estabilizador horizontal. Algunos triángulos más sirvieron para simular el escape. Cuando pulsé F5, ya tenía mi propio avión hecho a mano. Le tomé fotos por todos los ángulos y terminé de convencerme que sería la manera a la que generaría toda la geometría del juego. A pesar de ser claramente un avión extraño y muy triangular, le tomé cariño y decidí adoptarlo como el primer avión del juego. Se ganó el nombre de Sw71. (Sw viene de Sewoldt, la compañía que lo fabrica XD).






Las imágenes de arriba corresponden a las primeras tomas del primer modelo del juego. Como vi que funcionaba, decidí crear un segundo avión. Esta vez sería un jet de ala en delta. Fue así como el mismo día (o tal vez uno después) apareció la segunda nave de la bandada el SwXX Pyrage. (nunca le di mucha importancia a los nombres. Es muy probable que cambien de aquí al final del juego. Es la gracia de ser mi propio jefe en el proyecto.)
Finalmente, el 9 de Agosto de 2007, creé el último modelo. El Sw28 Shark. Decidí cambiar el color del Sw71 a rojo, para dejar el amarillo al último avión. Este modelo mostró la evolución que ocurrió durante ese par de días. Tiene un grado de teselación mayor, lo que otorga bordes rectos más alejados de la apariencia triangular del Sw71. Las alas tienen considerablemente más trabajo (6 triangulos por ala), por lo que son estéticamente mejores. El Shark toma su nombre de la forma de su cola, la que es alta y triangular, remedando la aleta de un tiburón en el agua.. .(con un poco de imaginación tal vez...).
Cuando estuvieron los 3 aviones creados, apliqué un par de transformaciones, moví unas cuantas matrices y dejé los tres aviones juntos en la pantalla. El Sw71 se encontraba al medio, mientras era escoltado por el Pyrage y el Shark a los costados, cada uno describiendo un roll contínuo hacia afuera. Había logrado crear geometría y animación simple a partir de matrices. Era un indicio de que el sueño imposible, tal vez podría hacerse realidad.

El siguiente snapshot muestra la escena recién descrita, donde aparecen los tres aviones en formación. Un logro muy bienvenido después de tanta incertidumbre. Gracias a esta escena, me di cuenta que había valido la pena lo estudiado, y que sería factible continuar. Por tanto, esta historia continuará.

jueves, 23 de agosto de 2007

Quien Soy (Parte II)

Continuando con lo anterior....

Una de las cosas que me venía llamando la atención desde hace un tiempo era DirectX. Cada vez que instalaba un juego nuevo, debía ceremonialmente instalar el componente, aunque no sabía ni qué era, ni para qué servía. Otra cosa que me sorprendió en ese tiempo fue el comienzo de los juegos en 3 dimensiones. Hasta entonces yo comprendía bien que en 2D bastaba con poner algunos sprites contra el fondo y hacerlos moverse. Las animaciones eran claramente una sucesión de frames, similares a las que yo hacía en las orillas de los cuadernos; pero en 3D era todo distinto e incomprensible. Varias veces hice animaciones pseudo3D, en realidad era solo cosa de perspectiva, pero en el 3D real, podía rotar por todo el espacio, ver cada imagen desde infinitos ángulos y nunca parecía una figura plana en perspectiva. Mi primer acercamiento a este tipo de aplicaciones fue un programa para diseñar ambientes de hogares. En mi rudimentario 286 de 10 Mhz (creo que con turbo subía a 20, era un notebook acer, cuya pantalla estaba mala y proyectaba sobre un monitor externo) tenía un software similar, permitía hacer planos de habitaciones, ingresando comandos en un consola, los que se graficaban en monocromático en una especie de plano. Del programa que hablo ahora (Win95), tenía funcionalidad parecida, salvo que todos los comandos eran del tipo Drag & Drop y finalmente uno podía convertir ese mundo en 3D y recorrerlo a su antojo. Recuerdo que el programa andaba lento y el PC se solía pegar siempre, pero estaba mostrando algo en 3D, lo que realmente me motivaba.

Los primeros juegos en 3D que usé, solían tener elaboradas iluminaciones y "materiales" interesantes en sus polígonos, pero pocos incorporaban texturas. Debido a esto, la sensación de realismo era bastante inferior a la lograda con los 2D y sus sprites elaborados e incluso fotorrealistas (fue increíble cuando en Mortal Kombat lograron meter personas reales al juego!!!), por lo que a pesar de la tridimensionalidad, parecían figuras plásticas y requería imaginación pensarlos como personajes.
Hubo un juego de carreras de autos que me emocionó. Era un demo de Rally, en 3D y con buena geometría. Cada auto estaba bien construído y se veían bastante naturales las curvas, respecto a lo poligonal que acostumbraba a ver. Pero lejos lo que más me sorprendió fue el uso masivo de texturas en los modelos. Comparados con juegos de ahora era realmente primitivo, pero el hecho de tener un mundo 3D, totalmente texturizado era sumamente atractivo, y lo más cercano a la realidad.

Mi pasión simpere han sido los aviones, por lo que un título infaltable en mi colección fue el MS Flight Simulator 98. Aprendí mucho de aviones con él (Creo que es el FSim con la mejor ayuda de la serie). Más de alguna vez estuve a punto de decidime por estudiar para ser piloto (aunque ahora estudio medicina) y creo que mucho influyó el simulador de Microsoft. En algún momento conseguí un editor de texturas para el Fsim, y pinté los aviones a mi gusto. Podría haber sido el primer paso en mi idea de diseñar mi propio simulador de vuelo.

El gran salto cualitativo ocurrió en esos tiempos, digamos año 1997. Un buen día llegó a mis manos un CD y un libro cuyo título prometía mucho: Aprenda Visual Basic, ¡Ya!. Con Juan estuvimos harto tiempo investigando el programa, siguiendo los ejemplos del libro y aprendiendo porfina a programar en Windows. Él sabía bastatne más que yo, pero a pesar de las farimañas y adornos, controles, eventos y cosas nuevas, el resto seguía intacto. En el corazón del lenguaje estaba el mismo Basic que yo había aprendido años atrás.
Ese libro se convirtió en mi biblia dirante mucho tiempo. Dejé de lado los módulos de clase y los enlaces con bases de datos de Access, centrándome sólo en la programación básica y en la parte gráfica, aunque a pesar de ser un lenguaje basado en Windows, las funciones gráficas del VB eran bastante limitadas.

El editor de VB que tenía en ese tiempo era una demo de la versión 4.0. Se llamaba modelo de evaluación, y sólo permitía crear un único formulario, y no posibilitaba crear archivos EXE. De todas formas, todo ese año y el que le siguió, permanecí programando en ese VB.

Con el tiempo aprendí varias cosas e hice algunos buenos programas para cosas del colegio. Cuando pasaba por genética, decidí hacer un simulador de evolución, que según el ambiente seleccionaba los fenotipos apropiados y eliminaba al resto. Funcionaba bastante bien, aunque la parte gráfica seguía muy deficiente. VB como tal solo ofrecía controles Picture e Image para cargar Bitmaps. Podía poner algunos controles de este tipo y moverlos por la pantalla, a la vez que reemplazaba cada imagen con una copia similar muy rapidamente, para lograr el efecto de animación.
Con esta técnica logré esbozar algunos "juegos", pero realmente estaba lejos de conocer una estructura correcta para elaborar un motor de juegos. En ese entonces, mis programas eran poco modulares y bien procedurales, con un nivel de abstracción muy bajo y difíciles de entender. Por otra parte, la gráfica siempre me complicaba, pues no conocía técnicas para lograr Color Key, razón por la cual, todos mis sprites estaban rodeados por un cuadrado de color. Para solucionarlo, pintaba este "fondo" del mismo color que el del fondo real sobre el que pondría el sprite. Así, el helicoptero siempre tenía un fondo color cielo, el cual no podría variar. El problema ocurria cuando se me cruzaban dos sprites, entonces se notaba claramente su naturaleza cuadrada.

Recuerdo una vez, por ahí en el año 2000 o 2001, cuando volví a programar después de bastante tiempo. Estuve enfermo y alejado del colegio casi una semana, por lo que debía hacer algo con mi tiempo libre. Recordé haber leído en una revista sobre un programa que generaba un mundo a partir de datos al azar. Tenía algoritmos para hacer árboles, casas.. Una cosa como un mundo procedural. Cuando estuve enfermo, decidí aplicar la idea para hacer un juego sobre avión que navegara por un mundo que se autogenerara azarozamente. Dado el eterno problema de los sprites cuadrados, decidí enfrentar el problema con lo que tenía: Shapes. Resulta que VB tiene un control Shape que permite crear cuadrados y óvalos y modificarles algunos parámetros. A pesar de su poca flexibilidad, no estaban inmersos en un cuadrado, por lo que me resultaban ideales para crear imágenes que se superpusieran sin interferirse fuera de sus límites reales.
El problema de la superposición se solucionó en parte. El asunto se volvió que un avión hecho de óvalos y cuadrados no sería visualmente muy elegante. Como solución decidí usar un Dirigible como personaje.
Recuerdo que todo funcionó parcialmente bien. Las nubes, árboles y demases se ubicaban en posiciones al azar, con colores aleatorios en paisajes autogenerados. No recuerdo si tuve suerte en volverlo un juego, ya que siempre me complicaron las colisiones y el scroll. Después de eso dejé VB por largo tiempo.

Creo que fue al final de mi último año de colegio (2003) cuando comencé a buscar ayuda en internet. Descubrí cientos de páginas con cursos de todo, todo gratis, todo bien explicado. Encontré por ahí una página que hablaba de juegos con VB. Comentaban que no era un lenguaje ideal para esos propósitos, pero que si de todas maneras se quería hacer algo, entonces BitBlt era indispensable.

Yo no tenía idea a qué se referían con BitBlt. Entre todas las funciones del Visual que conocía, niguna se le llegaba a parecer. Dado que convertí a internet en el maestro que busqué por años, lo utilicé para investigar más sobre esta función que parecía ser alabada por los verdaderos desarrolladores en VB. Recuerdo la primera descripción que leí: "BitBlt es probablemente la función más feliz de la API de Windows". Eso me mostró dos cosas: Estaba ante algo potente, y ese algo requería estudiarse para poderse entender.
Cuando aprendí a usar BitBlt, gané el poder para transferir bloques de bits (de ahí el nombre simpático: BitBlt = Bit Block Transfer) a cualquier device context (DC) de Windows. Cuando creaba controles en VB, automáticamente se creaba un nuevo DC, por lo que tenía el poder de poner imágenes donde nunca antes pude. Gracias a las varias ROPS (raster operations) que conocí, logre al final crear sprites a partir de dibujos de Paint, con un fondo transparente que dejaba ver lo que había más atrás. Desde ese momento dejé de usar controles Picture para mostrar imágenes. Bliteaba todo al DC del Form, con lo que logré componer escenas bastante atractivas. Entre tanta página que visitaba, terminé incluyéndome en un proyecto para crear un juego en comunidad, aportando ideas y código a través de un foro. Ahí aprendí a usar otros trucos de la API de Windows, pero además conocí y por fin entendí una API mucho más poderosa que venía intrigándome desde años atrás: DirectX.

DirectX7 simepre me costó bastante. Recuerdo que la referenciaba sólo para obtener la única función que manejaba bien: TickCount. En mis primeros juegos en BASIC, los intervalos de tiempo los calculaba mediante "For...Next", sumamente impredecible. Con VB hasta ese momento manejaba los tiempos con el Timer, el que lamentablemente perdía precisión manejando intervalos cortos. Una vez, estudiando el código de una animación del proyecto en que estaba trabajando (Se llamaba proyecto Alpha, programaba gente de todo el mundo) encontré que el manejo de los tiempos se realizaba mediante el TickCount, y que nadie usaba el Timer. Me di cuenta que el TickCount era sumamente preciso y confiable, y menos engorroso de implementar que un control Timer (Recuerdo mis formularios con 20 o 30 de estos controles, cada uno con su propio código autónomo interrumpiéndose mutuamente. Era un desastre, pero era lo único que tenía.) Cuando aprendí a usar el TickCount, mi primer programa fue un simulador de helicóptero. Ahora que tenía un control del tiempo con precisión de un milisegundo, no costaría demasiado crear una simulación semirrealista del vuelo idealizado de un helicoptero. todavía recordaba bastante bien varias fórmulas de cinemática y dinámica que servirían, por lo que un día desperté feliz y me dediqué a programar el motor de física.
Otra novedad importante en este juego fue la manera de estructurarlo. El haber colaborado en un proyecto mundial (aunque se canceló y ninguna línea de código fue mia) me permitió aprender a trabajar de modo modular. Con proyecto Alpha un tipo en USA creaba la física, otro en Europa el sonido, mientras yo estudiaba en Chile la manera de crear un Render decente para el proyecto. Con la estructura de mis programas era imposible que alguien colaborara conmigo. Cada función se mezclaba con otra en procedimientos enredadísimos, que a veces me impedían continuar cuando ni yo mismo me entendía. En cambio en proyecto Alpha todo iba en su módulo bien organizado. Cada programador debía sólo conocer la documentación de las funciones que realizaban los demás, sin entender su funcionamiento. A veces el tipo de Inteligencia Artificial le pedía al de física que creara una función de tal forma, a los pocos días el de física devolvía un ZIP en el foro con la función, el de AI la agregaba y trabajaba sobre ella sin involucrarse en su construcción. Este tipo de trabajo yo nunca lo había visto, y si bien, mi proyecto de Helicópteros era a nivel personal, también se beneficiaría del trabajo modular. Por primera vez cree subprocedimientos para cada acción, evitando esos listados interminables de código en una sola función. Si algo no gustaba, se cambiaba sin modificar al resto. Realmente fue un aporte el haber aprendido a trabajar así.

Lo del Helicóptero me tomó un par de días antes que me aburriera. La física funcionaba bien. leía perfecto las entradas del teclado y el Render, aunque sencillo, funcionaba perfectamente hasta entonces. Por primera vez incorporé la lógica de mi juego en un Loop, volviéndose muy similar a los motores de juegos "reales". Hasta entonces el programa corría bien como simulador, pero le bastaba bastante para ser jugable. Decidí mejorar los escenarios. Agregué edificios que hacían scrolling por la pantalla. Todos colisionables y wur permitían posarse en ellos (con el cuidado necesario para no destruir el helicoptero en el intento). Lo agradable era que todo estaba hecho en Paint, por lo que bastaba con modificar el bmp de origen para darle un look nuevo al juego, sin cambiar nada de código. Todo además era bastante paramétrico. Si quería agrandar un edificio, cambiaba sólo un número y el motor de juego se encargaba automáticamente de detectar las colisiones en otro nivel, etc. Cambié el Render varias veces sin tener que tocar una sola línea de código en el resto del programa. El problema apareció cuando la complejidad se hizo tal, que era incapaz de blitear un frame tras otro sin que se notara el corte.
BitBlt se estaba quedando corto para mis propósitos. Debía buscar una solución o mi juego se estancaría. Cuando estuve leyendo sobre DirectX, había aprendido bastante teoría, y sabía que los BackBuffers eran precisamente lo que necesitaba. El problema es que ni Visual, ni la API de Windows, ni nada que conociera soportaba backbuffers, excepto DirectX. Durante un buen tiempo traté de hacerle el quite a esta API. Me parecía poco práctico aprender de cero en la mitad de un proyecto. Además, no se veía fácil por lo que había investigado, por lo que decidí hacer un híbrido entre lo que sabía de VB, BitBlt y lo que pudiera aprender de DX7 en esos días. Recuerdo haber inicializado DirectDraw (La parte de dibujo de DirectX7) como había visto hacerlo a los tipos de proyecto Alpha. Luego creé unas cuantas Surfaces, y un set de BackBuffer y FrontBuffer. Hasta ahí con DirectX. Conservé la lógica de juego y la física original del juego en VB, y sólo pretendí modificar el Render. Como de cargar imágenes en surfaces no sabía mucho, decidí usar el BitBlt de Windows en vez del equivalente de DirectDraw. Al final nada resultó. BitBlt no era capaz de copiar en las surfaces de DirectDraw, a pesar de todos mis esfuerzos. Traté de crearles un DC compatible con funciones de la API, estuve mucho tiempo en eso y no funcionó. Me frustré y abandoné la idea de aprender DirectDraw. Terminaría mi juego como pudiera.
Hubo un momento en que comprendí que BitBlt había tenido su momento, pero que ahora necesitaba cosas mejores. No tenía sentido aferrarse a una función que me siguiera limitando. Después de todo, estaba haciendo todo eso por aprender. Hay un post por ahí en un foro (que todavía aparece si se busca en google) donde pido ayuda con mi problema con BitBlt y su poca velocidad. La respuesta fue categórica: "Aprende DirectX".

A partir de entonces, me dediqué a leer lo que encontrara de DirectX7 para aprenderlo cuanto antes, después de todo, por no saber Dx no había podido colaborar más con Proyect Alpha. en una de esas tantas búsquedas, encontré algo que me interesó aún más. Era un tutorial muy bien hecho donde enseñaban DirectX8. Ya no existía DirectDraw, desde Dx8 todo era 3D. Obviamente lo bajé y ese mismo día terminé de leerlo y hacer todos los ejemplos.

No ha pasado tanto tiempo desde que hice mi primer cubo coloreado que giraba y giraba infinitamente. La lógica de programar en 3D me fascinó, y abandoné el helicóptero. En vez de eso, hice un juego de Pong en 2D usando los Shapes de VB, con la salvedad que todo corría en un Loop que finalizaba en dos Render alternativos. El primero simplemente organizaba los shapes para que simularan la situación actual de la escena. El segundo hacía exactametne lo mismo, pero en un entorno 3D. La pelota era un cubo rojo que corría en una cancha azul, sólo delimitada por 4 líneas en el espacio. La cámara se podía mover libremente y hacía un efecto de "Super Switch", alternando repetitivametne entre la perspectiva del jugador y su oponente. Agregué un efecto Stealth, donde la pelota desaparecía en la mitad de la cancha, para luego aparecer sorpresivametne en los últimos segundos. Todo esto lo volvió un juego bastante interesante, del que compilé una demo que envié a un amigo para probar. Le intenté agregar soporte para juego en línea, pero nunca resultó, en parte porque no tenía dos PCs para ir probando. El juego se llamó Super Bong y aún lo conservo. Ha sido mi único juego en 3D, hasta ahora......

Terminó ese verano, y con él las posibilidades de seguir programando. Cuando volví a Santiago, tomé un curso de programación en la escuela de Ingeniería de mi universidad. Era el ramo terror de los ingenieros novatos, quienes debían aprobarlo en su primer año. Esto me hizo creer que ofrecía mucho y decidí tomarlo como electivo. Son 10 créditos de los que no me arrepiento, a pesar de las advertencias de mis amigos acerca de no tomarlo.
En ese curso aprendí bastante, de hecho, aprendí un lenguaje distinto y una filosofía totalmente nueva. Me enseñaron C# (C sharp), un lenguaje de Microsoft para su Framework.Net. Hace tiempo que venía leyendo sobre esta "cosa nueva" .Net; ya sabía de un Visual Basic.Net al que nunca me atreví a conocer más a fondo. Ahora, aprendiendo C#, conocí la filosofía .Net y la verdadera orientación a objetos. De principio me chocó un poco el cambiar toda mi forma de pensar un programa. Al comienzo intentaba aprender creando analogías con lo que ya sabía, pero al poco timepo comprendí que era necesario desprenderse del legado del BASIC y comenzar de cero con mentalidad nueva. El C# era un lenguaje basado en el C, esa cosa que tanto anduve buscando en mi niñez, potenciado para Windows y el FrameWork.Net. El hecho de vincular todo con internet me motivó bastante, puesto que había comenzado a esbozarse un proyecto de empresa de diseño Web con un amigo. Al final aprendí bastante en ese semestre y la orientación a objetos me gustó tanto que me costó imaginar cómo hubiese hecho las mismas cosas con Visual Basic años atrás. En mi proyecto final, junto a tres compañeros creamos un juego de futbol en tablero, cuya Clase de gráficos estuvo a mi cargo, y donde debí aprender bastante de aquello. Para lograr trabajar con algo más familiar, encapsulé las funciones graficas del C# en algo a lo que estaba más acostumbrado: Le agregué un BitBlt. En resumen, aprobé el curso y me quedé con el conocimiento de algo nuevo. No soy muy persistente, así que no seguí practicando. Al final dejé la programación un poco de lado para dedicarme a la música y la literatura, y obviamente a la medicina que se volvió muy demandante.

Después de todo esto, pasó un buen tiempo y ahora estoy en 4to año, con las esperanzas de ser un gran Doctor (Soy medio Médico, en la mitad de la carrera). Este semestre he tenido un poco más de timepo libre, lo que provocó que comenzara a retomar mis pasatiempos pasados. Me decidí a comenzar un nuevo proyecto en programación, para seguir con el aprendizaje y lograr plasmar en algo concreto todos los años de trabajo. Después de tanta presentación (y un poco de nostalgia mientras escribía) aquí comienza el texto sobre lo medular de este Blog: El proyecto Avioncitos 3D.

Quien soy (parte I)

Este es el Blog oficial del proyecto Avioncitos 3D.
Me presento, Soy Sebastian Ewoldt (Sewoldt) y este es mi primer proyecto de un juego en 3 dimensiones...



Hace muchos muchos años, debo haber tenido unos 9 o 10, llegó a mis manos mi primer PC (era eso??) un ATARI 800XL. Recuerdo haber estado horas frente al televisor, con el fondo azul y un cursor blanco, tratando de entender qué podía hacer con el juguete nuevo. Hace tiempo que venía sabiendo que los computadores se programaban, que era cosa de aprender, para tenerlos haciendo lo que uno quisiera. Siempre me intrigó el poder entenderme con una máquina, tenía nociones básicas de cómo funcionaba, solía "programar" toda cosa que pestañara en "12:00", videograbadores, radiorelojes y cosas de ese estilo. Recuerdo que años atrás, me había llenado de alegría el poder programar el VHS para grabar a determinada hora; en fin, era agradable la sensación de poder sobre una máquina, pero ahora, a mis 10 años, tenía una pantalla azul esperando mis instrucciones, y no tenía la menor idea de cómo hablarle.
Con la ayuda de mi padre, aprendí las primeras nociones de la lógica de programar. Me presentó algunas funciones básicas, los primeros controles de flujo.. Creo que al final del día terminé logrando una sencilla calculadora.

Gracias que en esos tiempos no había mucho en qué distraerse, ni TV buena, ni juegos de PC; mi pasatiempo se volvió el leer un libro que venía adjunto con el ATARI: Un manual de referencia de lenguaje BASIC. Conforme pasaron los días, los programas se hicieron cada vez más sofisticados, y comencé a conocer las bondades de programar con sólo texto. Pero a mí me movía algo superior: Siempre quise hacer un juego, y para eso necesitaba potencia gráfica.
Recuerdo un día glorioso que marcó esta etapa. Buscando entre los ejemplos del libro, encontré un programa que utilizaba las funciones gráficas del BASIC para mostrar el logo de ATARI. Después de haber copiado el ejemplo, encontré en éste la información que quería. Conocí el PLOT y el DRAWTO, Graphics 3, SetColor (0,2,8), (no sé porqué esos parámetros se quedaron hasta hoy en mi memoria). Sin saber completamente lo que estaba haciendo, empecé a echar mano del programa y a manipularlo a mi antojo. Comprendí el sistema de dibujo con coordenadas. El hecho de que cada imagen estuviera formada por una colección de puntos coloreados era bastante evidente en el logo Atari que mostraba el programa.

El paso siguiente fue dibujar a voluntad. Tomé un papel cuadriculado y comencé a dibujar pensando en pixeles. Cuando terminé todo, tenía una lista enorme de coordenadas, entonces se las pasé a una función PLOT, puse RUN y fue increíble: Había hecho un dibujo en mi televisor, sólo escribiendo números.... De ahí no paré más....

El manual del ATARI me enseñó a usar DrawTo en vez de PLOT para crear líneas. Gracias esto, los dibujos se volvieron más complejos y ya me estaba quedando corto en resolución.

Recuerdo que mi último gran logro fue un pseudoJuego de "Dos Perros Tontos" (era mi programa favorito en esos años). El televisor se ponía negro, a la vez que se dibujaban las siluetas de los dos personajes... Sonaba una música monofónica (el BASIC permitía tocar las notas que uno quisiera, a intervalos que nunca pude definir bien, más que poniendo ciclos for next vacíos entre ellos. Yo tocaba flauta dulce y sabía muchas canciones y sus partituras, siempre consideré agradable que mi televisor las tocara por mí). Al tiempo, despues de un retardo con un buclé vacío, el fondo se llenaba de estrellas (dibujé puntos toda la tarde) y el programa acababa.. Se lo mostré a toda mi familia... No sé si comprendieron lo importante que era para mí, pero yo estaba feliz... En ese televisor estaban pasando las cosas que yo quería.... Ya no era más la caja tonta... Ahora yo tenía el control..

Con los años fui creciendo y nunca más pesqué mi ATARI. Me había leido el libro muchas veces y no tenía nada nuevo de donde aprender. No existía internet como ahora, y la biblioteca de mi casa nada tenía de computación. Mi papá no sabía mucho más que yo. Durante la universidad había aprendido BASIC para usar su calculadora programable, pero de gráficos no tenía idea. Creo que jamás conoció el poder de PLOT. Pasaban los días y yo seguía con la misma grilla de ¿serán 50 x 50? pixeles, que ya no me satisfacía. Sentía que para lograr un dibujo creíble, necesitaba achicar los pixeles hasta hacerlos indistinguibles, estaba dispuesto a plotear 1000 coordenadas si era necesario, pero me faltó un buen maestro y me estanqué.

Conocía a una amiga de la familia, que ahora trabajaba de secretaria, y hablaba simepre de computación. Como gran novedad escribía sus cartas en computadores, y hacía todos sus cálculos de esta forma. Pensé que encontraría en ella la ayuda que andaba buscando, pero no fue así. Con el tiempo comprendí que no era más que una usuaria de programas, pero que jamás supo algo de programación. La gente que creaba todo aquello con que ella trabajaba estaba muy lejos, jamás en Chile, infinitamente fuera del alcance de un niño Chileno de 10 años, en ese entonces.

A medida que pasaban los años, me volví usuario. Aprendí MS-DOS con mi papá y le saqué provecho a varias noches hablando de PCs. Hasta entonces estaba acostumbrado al entorno de texto, lo que se revolucionó completamente de un día a otro cuando me mostró un nuevo "programa".. Tipeó WIN en el prompt del C: y mágicamente el monitor se limpió, mostrando el inquietante mensaje: "Iniciando Windows 3.1"

Me costó acostumbrarme a ver todo en entorno gráfico. Todo lo que alguna vez había imaginado al usar aplicaciones de consola, ahora estaba disponible y listo en la pantalla, sólo había que verlo. Nunca más imaginé una carpeta con su árbol de subdirectorios.. Ahora era cosa de mirarla. Fue como pasar de leer un libro a ver la película, tal vez un poco restrictivo a la imaginación, pero sencillo, y muy muy rápido.
Me sorprendió la facilidad con que se podían hacer dibujos en PaintBrush. Algunos años atrás, debía pasar horas calculando coordenadas para esbozar siluetas de un décimo de complejidad. Con el tiempo llegó el mouse, y desde entonces, el TAB, Alt-TAB, y todos sus derivados, desaparecieron de mi mente y se escondieron en algún recoveco de mi hipocampo.

Recuerdo que en mi colegio se comenzó a enseñar computación. Me aburrí... Sólo jugábamos y dibujábamos. Pero yo esperaba encontrar ahí a mi maestro. Ahora tenía todo el poder gráfico de un sistema operativo revolucionario. Si con apenas 10 años y un ATARI había logrado los "Dos perros tontos", era esperable que con un PC de verdad, con Windows, mouse y una bunea profesora, surgieran cosas mil veces superiores, pero no fue así.... Cada vez tenía menos control de la máquina.

A medida que la computación fue avanzando, la interacción usuario-máquina había subido de nivel, lo que hizo alcanzable la computación para muchos usuarios; Aunque en cuanto a mí, sólo me traía problemas. Me estaba alejando de la madre de todas las madres. Desde allí arriba ya ni se podía ver el código de máquina. Me desilusioné un poco y me volví "leecher", comencé a jugar, a usar el PC para escribir cuentos, hacer dibujos aburridos en Paintbrush y mirar el cursor moverse de un lado a otro siguiendo al mouse, sin saber qué clase de cosas interesantes lo estaban posibilitando.

Por mi padre sabía de la existencia del lenguaje C, que el BASIC ya no se usaba, y que mi única posibilidad de hacer algo realmente novedoso era usando un lenguaje de alto nivel. El problema es que nadie sabía nada. Ni mi profesora de computación, ni nadie conocido tenía un compilador de C instalado. Nadie quería mirar más allá. Me sentí solo en mi búsqueda, hasta que conocí Windows 95.

Cuando conocí el primer PC con Win95, era el año 1997, mi mamá se había casado por segunda vez y fue una revolución en mi vida. Fue en el verano del 97 cuando Juan, mi padrastro, me presentó algo como un 586 de 120 Mhz, con 8 Mb de RAM, que corría Win95. Yo había sólo leído de este sistema en alguna revista que lisonjeaba sus bondades, pero tenerlo en mi PC era para mí como alojar en mi casa a un RockStar. De Windows me sorprendió la capacidad de tocar midis con su reproductor. Habían días en que me quedaba escuchando decenas de tracks, sólo por oir música en el computador. Me acuerdo de algunos programas notables como SkyMap, o el mismo PowerPoint, en el que ví la posibilidad de hacer mis propias animaciones. Recuerdo un día que desperté emocionado tratando de programar algo en PPT. La posibilidad de hacer animaciones y determinar eventos me hizo creer erronamente que lo lograría. Con el timepo me di cuenta que seguía sin programar. En algún momento de la evolución el "If..Then" se había perdido, de alguna forma me estaba quedando restringido a usar los numerosos programas nuevos que iban apareciendo, creados por aquellos afortunados que tenían el don y derecho a programar. Decidí tomarme la vida fácil. Comencé a Jugar.

Junto con el PC nuevo, el otro artículo importantísimo del que se pobló la casa fueron las revistas de computación. Leí todo lo que caía en mis manos, desde Windows, pasando por JavaScript y las nuevas tecnologías de las que se poblaba la incipiente internet. Aprendí bastante de arquitectura de computadores, y de las cosas ignotas que ocurrían mientras uno simplmente pulsaba sobre un botón. Me informé de las nuevas tecnologías que aparecían, de como el DMA venía a revolucionar la forma de gestionar memoria, de los fundamentos de la multitarea y de la manera en que se se formaban imágenes en los PCs. En esencia todo seguía igual a cuando comenzó. Windows y sus farimañas no eran más que una manera amigable de encapsular a lo que realmente estaba pasando. El viejo DOS seguía corriendo de fondo, llamando a funciones de la BIOS, que a su vez pasaban las mismas instrucciones al procesador. Mi 286 de 10 Mhz estuvo haciendo lo mismo durante años, Windows sólo venía a ser una capa ocultando la exquisita complejidad de lo que más abajo ocurría. Necesitaba encontrar la manera de volver a vincularme lo más cercanamente al hardware. Estaba dispuesto a abndonar la comodidad de presionar botones... ¿pero dónde estaba C?.. ¿Por qué entre los miles de accesorios inútiles de Windows no venía algo como un editor de C o assembler?.. Algo grande estaba pasando allá abajo y lo quería conocer. Por suerte, cuando volví a programar no abandoné la comodidad del entorno Windows y comencé con un lenguaje visual de alto nivel, pero eso es historia para otra ocasión......