inmensia |
Stratos
Juan Mellado, 2 Febrero, 2013 - 14:49
Ayer liberé los fuentes de dart-solitaire, una versión escrita en Dart del clásico juego de cartas del solitario. No es un juego demasiado complejo, así que lo usé como excusa para empezar un nuevo proyecto y seguir probando este nuevo lenguaje de programación aún en desarrollo. En mi caso además tenía el aliciente añadido de que hace siete años escribí una versión del mismo juego directamente en JavaScript, en un época donde nadie apenas hacía desarrollos en JavaScript, y me venía estupendamente para comparar las formas de desarrollar en uno y otro lenguaje.
Demo online: http://www.inmensia.com/files/dart-solitaire/solitaire.html Cuando me planteé volver a escribir este juego, además de implementar la mecánica básica, me propuse añadir algunas opciones que siempre había querido desarrollar, como la opción de "undo" para deshacer las jugadas por ejemplo. La manera tradicional de codificar esta opción es utilizando un patrón de diseño llamado "Command", y así es como lo he acabado implementando para no andar reinventando la rueda. Es curioso, casi podría decir que empecé el proyecto para implementar este tipo de cosas en vez del juego en si mismo. El código puedo decir que prácticamente lo he escrito dos veces. La primera vez usé una solución basada en elementos HTML y CSS, donde las cartas por ejemplo eran elementos HTML de tipo DIV. Pero después de tener una versión funcionando empecé a pensar que me gustaría probar una solución basada en el uso de un CANVAS. Y dicho y hecho, empecé a cambiar todo el código que ya tenía escrito hasta conseguir una nueva versión basada en el manejo de sprites esta vez. Es ese tipo de cosas que uno sólo se plantea hacer en proyectos personales, donde no hay restricciones de tiempo, en los del trabajo no suele haber tanta libertad. Una ventaja añadida de usar un canvas es que me permitía implementar de una forma sencilla el famoso efecto de la versión para Windows, donde al finalizar una partida las cartas salían disparadas una a una rebotando y dejando un rastro de si mismas. Recordaba haberlo visto hace poco en una demo tecnológica llamada Winning Solitaire de Ricardo Cabello, así que estudié el código, muy sencillo, y lo adapté para incorporarlo al juego. Da igual en que lenguaje esté implementado, sigue siendo un buen efecto de fin de partida. El tener el efecto de las cartas rebotando implementado a menos me compensa de algunas carencias obvias, como no tener una música de fondo, algún efecto sonoro, o incluso alguna que otra animación al manejar las cartas. Suelo trabajar solo en estos proyectos, así que tengo mis limitaciones a la hora de añadir determinadas características "creativas". En algunas de ellas simplemente no me apetece trabajar, y para otras carezco del talento necesario. Al menos puedo sentirme orgulloso de haber podido hacer los gráficos, que aunque sean sencillos me han llevado bastante tiempo. Aunque el juego utiliza imágenes en formato PNG, las originales son gráficos vectoriales en formato SVG hechos con Inkscape. Inicialmente utilizaba directamente las imágenes en formato SVG, pero me encontré con algunos problemas de incompatibilidad entre los dos o tres navegadores más populares con los que estuve probando, ya que cada cual dibujaba las imágenes según su propio criterio, y lo que es peor, en algunos casos el rendimiento era absolutamente pésimo. He liberado los gráficos vectoriales originales por si alguien puede reutilizarlos para algún desarrollo propio. He añadido además un par de opciones al juego para poder cambiar el diseño del tablero y del frontal de las cartas. Así como el número de cartas que se sacan del mazo cada vez. Aunque esto último lo dejo hacer incluso en medio de una partida sin reiniciarla, lo que no es del todo correcto. Otras opciones que podrían añadirse serían por ejemplo cambiar el diseño del reverso de las cartas, jugar contra el tiempo, añadir un sistema de puntuación, o un histórico de partidas jugadas. Los mensajes y cuadros de diálogo están hechos con un poco de CSS, con el que parece que jamás llegaré a sentirme totalmente cómodo. Inicialmente pensé en utilizar bootstrap, con el que incluso llegué a hacer unas pruebas que me gustaron mucho, ya que el resultado es muy profesional, y resulta muy fácil añadir animaciones y otros efectos con JavaScript. No obstante, al final quité la dependencia y todo el código, ya que me dió la impresión de que el proyecto acabaría teniendo más CSS y código en JavaScript que en Dart. Un detalle que me gustaría incorporar en el futuro, ya que ahora mismo no estoy en condiciones de probar como a mi me gustaría, es la gestión de eventos de tipo "touch" para que el juego funcione en los móviles con pantalla táctil en vez de sólo con el ratón. El problema es del "drag and drop", que los móviles interpretan como un "gesto", en vez de como un "click y arrastrar sin soltar el botón" de un ratón tradicional. Respecto a las pruebas, decir que apenas he probado en el PC de casa con las últimas versiones de Chrome (dev channel), Firefox (ga) e Internet Explorer (10 rc). Y como de costumbre, Internet Explorer es el que más lata ha dado, incluso la nueva versión. Por último, comentar que actualmente prefiero desarrollar en Dart que JavaScript. Me siento más cómodo con el lenguaje, lo encuentro más productivo. Poder trabajar con una sintaxis y estructura de clases e interfaces como la que ofrecen los lenguajes orientados a objetos tradiciones es mucho mejor para mi que trabajar con los prototipos de JavaScript. Para ser un lenguaje que está aún en desarrollo, con muchas cosas que limar, y muchas librerías que desarrollar aún, tiene el plus de ofrecer una "experiencia de codificación" muy gratificante, algo que me resulta difícil de explicar con palabras o cuantificar de una manera más concreta.
Juan Mellado, 8 Junio, 2012 - 13:56
He desarrollado un emulador de ZX Spectrum en Dart. ZX Spectrum fue uno de los ordenadores más populares durante la década de los ochenta, y este año se cumplieron treinta desde su creación. Dart es un nuevo lenguaje de programación que está desarrollando Google. He llamado zx-dart al proyecto y lo he liberado como código abierto. ![]() La versión de código nativo en Dart se puede ejecutar en Dartium, que es una versión de Chrome que incluye la máquina virtual de Dart. Aunque el rendimiento es pésimo, no alcanza ni un frame por segundo. Hay que tener en cuenta que Dart todavía está en desarrollo, las mejoras tienen que ir llegando poco a poco, además de que la especificación oficial del lenguaje cambia cada pocas semanas, por lo que el código escrito hoy puede que no funcione mañana. Dart viene acompañado de una herramienta llamada (actualmente) dart2js que convierte el código Dart a JavaScript, de forma que se pueda ejecutar directamente en Chrome sin necesidad de la máquina virtual de Dart. Afortunadamente esta versión alcanza los 20 FPS en mi máquina y el emulador se deja probar, aunque para una simulación realista de un Spectrum debería alcanzar al menos 50 FPS. El emulador que he implementado está basado en JSpeccy. Realiza una emulación básica de un Spectrum 48K, con carga de ROM y ejecución de BASIC. Le faltan muchas características básicas, como la generación de sonido o la posibilidad de cargar snapshots por ejemplo. Pero hoy en día hay muchos emuladores bastante completos para casi cualquier plataforma, por lo que no merece la pena complicar el desarrollo para reinventar la rueda. Quizás un port a Dart de algún emulador ya existente escrito en JavaScript podría ser una mejor opción. Ha sido emocionante el primer arranque, después de múltiples fallos, y ver el famoso mensaje de copyright.
Juan Mellado, 12 Mayo, 2012 - 20:15
He liberado los fuentes de js-handtracking, una librería escrita en JavaScript que captura la imagen de una webcam y la procesa con el objetivo de detectar la presencia de piel humana, preferentemente una mano, y extraer sus características estructurales más importantes. La librería realiza las siguientes operaciones: - Detección de las áreas de la imagen que contienen piel Demo online: Para probar la demo es necesario utilizar un navegador moderno con soporte para WebRTC, que es la tecnología que permite a JavaScript acceder a la webcam directamente desde el navegador. Por ejemplo, Chrome 18 o superior, con el flag Para la detección de piel al final he optado por convertir los colores desde RGB hasta HSV y comprobar los valores de los canales H y V para determinar si están dentro del rango de la piel humana: v >= 15 and v <= 250
Las condiciones de iluminación son muy importantes y hacen que los colores sean detectados de forma muy distinta por la webcam. He tenido bastantes problemas ajustando los parámetros. Al final eliminando el equilibrado automático de blancos he conseguido una detección bastante estable. Lo realmente importante es darse cuenta que hace sólo unos pocos meses era impensable pensar en realizar este tipo de aplicaciones sencillas de visión artificial en JavaScript.
Juan Mellado, 9 Mayo, 2012 - 18:54
Estoy trabajando en una nueva librería escrita en JavaScript. Esta vez estoy tratando de implementar un sistema de tracking, en especial de manos. Mi objetivo es ser capaz de detectar una mano que se encuentre dentro de una imagen y destacar sobre ella sus características principales. Ya tengo un prototipo bastante avanzado, como puede verse en la siguiente imagen: La librería segmenta una imagen dada dividiéndola en regiones que contengan colores dentro del rango que caracteriza la piel humana (blanco). Asumiendo que la región más grande encontrada corresponde a una mano, ya que ese es el objetivo de uso de la librería. A continuación encuentra el contorno de la región (rojo), y sobre ese contorno calcula la envolvente convexa (azul) y sus defectos de convexidad (verde). Los defectos de convexidad suelen ser de bastante utilidad, ya que se pueden usar para contar el número de dedos que tiene levantados la mano por ejemplo. Viendo la imagen está claro que la librería ya cumple su objetivo, pero aún me quedan varias pruebas que quiero realizar antes de liberar los fuentes. La parte más complicada del proceso está siendo la primera, la detección de la piel humana. Ya había trabajado antes en el tema, pero me estoy encontrando con problemas debido a que mi webcam es MUY mala y no hay forma de que me proporcione fotogramas con los colores correctos. De momento me estoy limitando a utilizar imágenes estáticas, aunque tengo una demo que acepta como entrada vídeo directamente. En el apartado de la documentación de referencia, para la detección de piel he probado tres sistemas distintos. Al final el que se encuentra ahora mismo implementado es el que se describe en esta página (en chino): - http://blog.csdn.net/scyscyao/article/details/5468577 De hecho, la imagen de la mano que he puesto es de esa página. La he estado utilizando para comparar resultados. Espero que no haya problemas de copyright. Antes de liberar la librería me gustaría revisar la implementación que tiene OpenCV de una técnica llamada "adaptive skin detection", que ajusta los parámetros de detección de piel humana en función de como varía la imagen fotograma a fotograma. Pero no estoy muy convencido, ya he hecho una primera prueba en JavaScript de la parte básica sobre una imagen estática y detecta menos piel que el método que tengo ahora mismo funcionando.
Juan Mellado, 13 Febrero, 2012 - 18:05
Hoy he liberado los fuentes del último proyecto en JavaScript en el que he estado trabajando. Es un visor de modelos 3D almacenados en formato AC3D (.ac) que utiliza WebGL para renderizar. He estado utilizando modelos de aviones de FlightGear para probarlo, así que he decidido llamarlo Hangar. He creado una pequeña página web con cuatro modelos escogidos de prueba. Tiene implementado un controlador a modo de trackball que permite rotar y ampliar los modelos utilizando el botón izquierda y la rueda del ratón. Necesita un navegador moderno como las últimas versiones de Chrome o Firefox para funcionar (Y no, IE 9 no es un navegador moderno) ![]() El formato AC3D lo utilizan algunos programas como FlightGear, un simulador aéreo de código abierto, o Torcs, un simulador de conducción deportiva también de código abierto. Es un formato de texto plano que originalmente creó un programa de modelado 3D llamado, lógicamente, AC3D. Mi idea era hacer algo sencillo, pero al final he acabado incorporando un montón de esas pequeñas características que pasan desapercibidas cuando funcionan bien. AC3D Los objetos están definidos de una manera jerárquica, de forma que un objeto puede tener hijos. Además, cada objeto tiene una matriz de rotación y un vector de rotación que aplica a sí mismo y a todos su hijos, por lo que hay que ir calculando la transformación resultante a medida que se baja por el árbol de descendencias. Teselación Me he encontrado con modelos de todo tipo y definidos de casi cualquier forma. Al final he decidido ignorar los polígonos degenerados. Es decir, polígonos con menos de tres vértices, polígonos con coordenadas colineales, polígonos con vértices no contenidos dentro de un único plano, polígonos con aristas que se cruzan, ... Normales La normal a un vértice concreto se calcula como la suma de todas las normales de todas las caras que comparten dicho vértice. Aunque a este respecto el fichero incorpora un parámetro por objeto llamado "crease". Este parámetro es un ángulo, y sirve para generar lo que habitualmente se conocen como bordes duros (hard edges). Si el ángulo que forman la normal de una cara y su vecina supera dicho parámetro entonces esa normal vecina no se tiene en cuenta para calcular la normal en el vértice compartido. SGI Mi implementación soporta .sgi, .rgba, .rgb, .ra y .bw. Es decir, todas las combinaciones posibles, aunque he ignorado deliberadamente algunas características de la especificación, como la posibilidad de usar paletas de colores o escoger entre 8 ó 16 bits por canal. En la práctica todas las imágenes acaban siendo de cuatro canales y con 8 bits por canal en el clásico formato RGBA. Loader Muy útil. Renderer El formato AC3D permite incluir luces en los modelos, pero las he ignorado a la hora de renderizar, utilizando en cambio una luz fija estática direccional sin factores de atenuación. Mi idea era representar modelos de objetos independientes, no escenas completas, por lo que no he encontrado sentido en incluirlas. Aparte de que acabado no fiándome de los modelos, con materiales un tanto extraños a mi parecer. Para minimizar los cambios de estado de la tarjeta gráfica he agrupado todos los polígonos por programa, material, tipo, y todo lo que se me ha ocurrido. Por ello, a diferencia de otros proyectos anteriores, he decidido utilizar Transparencias Lo que me duele es que se supone, repito "se supone", que los materiales incluyen un atributo para indicar si tienen algún tipo de transparencia. Desgraciadamente esto no ocurre así en la práctica. Al final cuando algún modelo no se visualizaba correctamente, abría el fichero, localizaba el material y lo cambiaba a mano. Esto es algo que en general creo que tendría que revisar con el objetivo de entender la manera en que interpretan los materiales programas como FligthGear o Torcs aprovechándome del hecho de que son de código abierto. Autofit De esto también me gustaría escribir un post individual en el futuro, ya que he encontrado distintas soluciones en Internet y no me he quedado del todo satisfecho con la que yo mismo he implementado. TrackBall Resumiendo Una aproximación más práctica al problema hubiera sido utilizar un motor 3D ya existente, como el popular Three.js, y limitarme a hacer un conversor del formato .ac a algún formato que acepte el motor. Pero claro, ¡me hubiera perdido la parte más divertida! |