« Julio 2006 | Inicio | Septiembre 2006 »

Agosto 30, 2006

Aplicaciones multiusuario con Unity ( y actionscript y xml )

Hace poco, y tras una demostración, a la empresa le entró el proyecto de una aplicación multiusuario. Una comunidad virtual que recientemente vio la luz ( y de qué manera, con anuncio en el telediario de la cadena incluido ).

Como ya se había utilizado tanto para la demo, como para un proyecto interno de la empresa, se decidió utilizar Unity Socket Server, y UClient, el set de librerías AS2 desarrolladas por Colin Moock,( el autor de los famosos libros de actionscript ) para trabajar con Unity. El resultado: fabuloso. A pesar de ciertos fallos, que según reflejaba Colin en la lista de correo, se corregirán en la versión 3 de Unity, me parece un servidor fabuloso. Eso sí, hay ciertas pegas o al menos una gran pega. A pesar de que la API está relativamente bien documentada ( desde luego mucho mejor que mis desarrollos ( documentando v1 / documentando v2 ) ), los tutoriales son muy escasos y relacionados con aplicaciones muy básicas y sencillas. El desarrollo de una aplicación tan grande ( en cuanto a complejidad y comprensión del servidor ) ha sido muy costoso.

Algunas características de UClient son:

  • Uso del paradigma MVC

  • Envío y recepción de eventos, mediante el Modelo de Delegación de Eventos

  • Desarrollado por tanto pensando en interfaces y no en la implementación concreta de las clases, lo que es fabuloso y permite una flexibilidad enorme.


Algunas características del desarrollo para la aplicación son:

  • Separación de la lógica de la aplicación en tres grandes áreas:
    • Motor principal que se encarga de gestionar las comunicaciones entre cada una de las zonas de la aplicación, sin que ninguna de ellas tenga que saber de la existencia de las otras.
    • Zona de comunicaciones con el servidor de sockets. Expresamente desacoplada del resto de la aplicación y comunicada con la misma mediante la emisión de eventos permitiendo una "relativamente fácil" migración a otro servidor de sockets si fuese necesario, de forma que afectase mínimamente al resto de la aplicación ( En caso de realizarse dicha migración, posiblemente se hiciese mediante un adapter a la clase que extiende de Uclient, que a diferencia de lo que ocurre en los ejemplos de Unity, no es la clase principal de la aplicación )
      Además este desacoplamiento y comunicación por eventos, permite perfectamente el uso de estas clases en otros proyectos sin necesidad de modificar nada ( acaso creando alguna clase que extienda de alguna de estas para sobreescribir algún método concreto )
    • Zona isométrica. Que se encarga de gestionar toda la isometría. Emite eventos que son recibidos por el motor principal que se los envía a la zona de comunicaciones. Cuando se reciben eventos desde el servidor en la zona de comunicaciones, esta se la envía mediante eventos al motor principal que se la envía a su vez a la zona isométrica. De nuevo, esta zona al estar desacoplada de las demás, es altamente reutilizable en otros proyectos multi o mono usuario que requieran de la perspectiva isométrica.


  • Uso extensivo de interfaces.

  • Uso de factorías abstractas ( y por tanto de interfaces ) de creación de elementos

  • Uso de callbacks

  • El uso de los interfaces y las factorías , permite, tener diferentes salas ( en cuanto a comportamientos ) , con más o menos cuadrículas, con más o menos tipos de celdas, etc.. sin necesidad de tocar código del motor principal isométrico, sino estableciendo el valor de unos parámetros en la clase principal de cada sala ( que extiende de la clase isométrica general, que a su vez implementa el interface de isometría )

  • El uso de máquinas de estados para los elementos de la aplicación ( típicamente los avatares de los usuarios ). Todas las máquinas de estados, se conectan a un único engine. Esto quiere decir, que aunque tenga 30 usuarios en pantalla, tengo un único enterframe que controla las 30 máquinas de estado. Lo que evidentemente, es muy óptimo para el procesador.

  • Completa separación del chat de texto de los grafismos de las salas, siendo una capa y una película independiente. Esto permite construir salas de chat que no tengan la representación isométrica, sin tocar código.

  • Gracias al departamento de animación, y a diferencia de lo que suele ser habitual en estas comunidades, personajes realistas.


Conclusión. Otro desarrollo costoso ( ha sido como un parto ). Pero por primera vez en mi vida como desarrollador ( en lo que a proyectos muy grandes se refiere ) estoy muy contento con los códigos realizados. La aplicación no solo es robusta, sino que es muy fácilmente extensible, gracias al ya comentado uso de interfaces. La abstracción y desconocimiento de unas zonas de la aplicación por otras, ayuda muy mucho en esto.

Hay desarrollos en los que el resultado final es muy vistoso, pero el código no es extensible o es directamente código espagueti. En este caso no solo estoy contento con el resultado, sino que también estoy muy satisfecho con los códigos. Baste decir una cosa. Aunque la comunidad ha visto la luz ahora, se desarrolló en enero y febrero. El caso es que dada la favorable acogida que ha tenido por los usuarios a los que iba dirigida ( el cliente está como se dice coloquialmente "que no mea" ), está en proceso el desarrollo de más salas, y a pesar de haber pasado seis meses, y haber tirado miles de línea de código entre medias, no estoy teniendo dificultades en añadir los nuevos contenidos ( vamos, que me sorprendo hasta yo mismo a medida que repaso los códigos de lo bien que estaba ).

Así que ya saben, a tunear el coche del neng, que es lo que me da de comer. ;D


( Como verán hago mucho hincapié en el uso de interfaces. En los cursos avanzados de programación que he impartido he notado como la mayoría de los flasheros, o no sabían lo que era un interfaz, o se habían quedado en la definición "es un contrato que obliga a desarrollar los métodos en la clase que implementa el interfaz que los declara" sin ir más allá. Si me permiten un consejo, investiguen más, esfuércense y entiendan el polimorfismo a través de interfaces. Cuando pasar un interface como parámetro, o tipar un objeto no como el tipo de la clase de la que es instancia, sino como tipo interface implementado por esa clase, sea parte habitual de su trabajo, vivirán mucho más felices, al menos si tienen que realizar desarrollos grandes o pretenden reutilizar códigos entre proyectos )

Motor de aventuras gráficas con AS2 y XML ( version 2 )

En una entrada anterior, hablamos del desarrollo de un motor para aventuras gráficas, con ActionScript 2 y gestionado completamente por XML, que permitía una muy rápida generación de aventuras gráficas.

Con aquel motor, y si no me engaña la memoria, fueron 26 los cdroms que se realizaron ( entre castellano, catalán, valenciano y gallego ) en 4 meses.

En el momento de escribir esta entrada, ya son varios los cdroms ( en diferentes lenguas ) que han salido con la "versión 2" del motor.

¿ En qué consiste ?. Repasemos primero lo que ofrecía la versión 1.


  • Todos los textos genéricos del cdrom, estaban en un xml de configuración ( textos como por ejemplo: "Nombre", "Contraseña", "¿Es la primera vez que juegas?", "El nombre o contraseña introducidas no son correctas. Si es la primera vez que juegas regístrate". Es decir, los textos de las pantallas de introducción ( de los botones, etc..) Permitiendo una traducción muy simple de las mismas, con traducir simplemente el xml de configuración.

  • La aventura, está dividida en unidades. En cada unidad hay tantas escenas como se indique en el xml de configuración de la unidad ( sin haber límite numérico ).

  • Cada escena, está controlada por un xml de la escena. En este xml se especifica lo siguiente:

    • Los objetos que aparecen en la escena.

    • El comportamiento de cada uno de los objetos. Cada objeto especifica en el xml su propia máquina de estados, con las acciones a realizar en cada uno de los estados.

    • La forma de interactuar con cada objeto, si es por hacer click sobre el o si es porque el personaje de la aventura "toca" o colisiona en pantalla con el objeto.

    • La posición ( o posibles posiciones ) en la que ha de estar el personaje controlado por el usuario en pantalla para que la actuación sobre el objeto tenga efecto ( en caso de no estar en una de estas posiciones, aparece un mensaje en pantalla pidiendo al usuario que se acerque más al objeto )

    • El resultado de interactuar con cada objeto en cada uno de los estados de la máquina de estados de dicho objeto. Es decir, por defecto, cada objeto tiene 7 posibles estados ( mas un número indeterminado de estados ficticios ). Estos estados son "visible", "activo", "invisible" etc..Cuando interactuamos con un objeto que está en uno de estos estados, podemos indicarle que o bien permanezca en el mismo estado, o bien que transite hacia otro estado ( lo que viene acompañado de un cambio gráfico pues la película del objeto se mueve hasta el fotograma asociado a cada estado, donde habitualmente hay un movieclip con una animación ).
      Además, la actuación sobre un objeto, puede modificar el estado de otros objetos, haciendo que cambien su estado ( y su representación gráfica por tanto )

    • En el xml se especifica también que la interacción con un objeto puede dar lugar al paso del mismo a un inventario.

    • En el xml se especifica también que en los objetos en los que se indique, para poder interactuar con ellos, es necesario utilizar alguno de los objetos que tenemos en el inventario.

    • Se especifica la posición inicial del personaje en pantalla.

    • Se especifican los textos que aparecen en los avisos que surgen en la escena

    • Los cdroms son didácticos ( acompañan a libros de texto ) y por tanto su finalidad es hacer preguntas al alumno sobre las materias. En el xml de la escena se indica dónde ( al interactuar con que objeto(s)) aparecen las preguntas.

    • La perspectiva utilizada. Hay varias perspectivas posibles. En función de lo indicado en el xml, el personaje aparecerá en pantalla más o menos grande, y su tamaño se reducirá o ampliará más o menos cuando se acerca al fondo o al comienzo de la pantalla.


  • En el xml de configuración de cada unidad, además de indicar las escenas, también se indica el xml con el repositorio de preguntas para cada unidad ( tantos xml de preguntas como unidades ).

  • Cada xml de preguntas de unidad, consta de un número determinado de preguntas ( 15 ). En dicho xml se especifica por cada pregunta:


    • El tipo de pregunta ( hay varios tipos de preguntas, de selección simple, de selección múltiple ) etc.. el motor interpreta este atributo y presenta en pantalla la pregunta con uno u otro grafismo según sea el valor del mismo.

    • Las posibles opciones de respuesta y cual ( o cuales pues puede haber selección múltiple ) son las correctas.


  • Por supuesto, y aunque no está realizado en perspectiva isométrica, el personaje puede pasar por delante y por detrás de los objetos. Esto fue especialmente complejo, pues a priori, y dado que el número de objetos que aparecen en pantalla viene dado por el xml, nunca se sabe cuantos objetos habrá ( ni donde estarán situados )

  • Cada cdrom podía tener unos 600 objetos, es decir unos 600 swf. Ninguno tenía dentro ni una sola línea de código ( excepto los stops de las animaciones ) pues su comportamiento está definido en los xmls.


La conclusión es que, con este motor se podía trabajar-y se trabajaba- ( sin tener que escribir ni una sola linea de código ) en varios cdroms a la vez con un equipo de guionistas, animadores y personas escribiendo archivos xml de configuración de escenas por cada cd.

Todo esto está muy bien, pero.. ¿ se podía mejorar ?. Sí, y eso es lo que se hizo en la versión 2 del motor, en la que se añadieron:

  • Más perspectivas del personaje. Permitiendo ( dada la habilidad de los animadores ), diferentes tipos de escenas, con mayor o menor sensación de amplitud, pues en algunas la línea del horizonte está más baja, lo que unido a un factor de escala del personaje determinado, proporciona perspectivas muy variadas.
  • Comunicación con el usuario mediante el uso de una "PDA". Al usuario se le muestran avisos de texto o se le mandan preguntas ( recordamos, cdroms didácticos ) mediante un interface gráfico en forma de PDA.
  • Añadimos que desde el xml de configuración de la sala, no solo indicamos donde salen preguntas, sino cuántas salen cada vez ( permitiendo así, las baterías de preguntas )
  • A los 5 tipos de preguntas existentes, se añaden otros 6, llegando a 11 tipos diferentes de preguntas. Añadiendo preguntas de unir mediante flechas, o de arrastrar y soltar. Como decimos todo indicado mediante atributos xml.
  • Diálogos. Elaboración de un motor de diálogos que permite conversaciones de alto nivel de anidamiento y varios posibles finales. Por cada diálogo tendremos un xml de configuración del diálogo, donde indicaremos cada línea de diálogo tanto del usuario como del objeto con el que interactúa. Es decir, en función de la selección realizada por el usuario, en cada "turno" de palabra, el diálogo será diferente. En caso de llegar al final del árbol del diálogo por alguna de las ramas que no llevan a una de las frases indicadas como finales en el xml, el diálogo comenzará de nuevo. Cada vez que elegimos una frase, el personaje cambiará su estado para presentar una animación del mismo hablando. Cuando el turno es del objeto con el que interactuamos ( que obviamente, de normal representa a una persona ), será dicho objeto el que se pondrá gráficamente a hablar y nuestro personaje se pondrá en posición de escucha. Estos dos estados, de hablar y de escuchar, son dos de los estados que tienen todos los objetos en su máquina de estados ( que luego, habrá objetos que los usen y objetos que no ).
  • Inventario múltiple. Se "extiende" la funcionalidad de inventario, para tener varios objetos en el mismo. Esto implica que cada vez que interactuemos con un objeto, que necesita ( porque así lo hemos indicado en el xml ) que se haga uso de un objeto del inventario, tendremos que comprobar que se está usando el objeto correcto.
  • Mientras en el primer motor, cada unidad lleva asociada un temario, y siempre el mismo ( por ejemplo, unidad 1 del cd de matemáticas, los números primos. Unidad dos la división, etc.. ) la versión actual del motor, permite una asociación dinámica entre las escenas del juego y las preguntas de las unidades de cada asignatura. De este modo, la historia de la aventura gráfica será siempre la misma y mantendrá el mismo orden consecutivo en el argumento ( se jugará secuencialmente y siempre en el mismo orden las etapas ), pero las preguntas de cada unidad didáctica podrán plantearse indistintamente en cada etapa. Cada vez que se comience una aventura con un usuario nuevo, existirá la posibilidad de realizar una asociación distinta entre las etapas y las preguntas.

Con este motor, y gracias a los divertidos guiones realizados por el departamento de guión, a las fabulosas animaciones realizadas por el departamento de animación, los grafismos del departamento de diseño, y la elaboración de los xml de configuración de escenas por tecnología, se han podido realizar ( y se siguen realizando ) numerosos cdroms, en diferentes idiomas, y trabajando en tres o cuatro a la vez ( dado que no es necesario tirar una sola línea de código ). Y a los niños, les gusta el juego ( aunque haya preguntas de matemáticas, o de lengua ).


Y sí, realizar el motor, .... ha sido difícil. Pero ha quedado chulo. Podéis ver el resultado a partir de septiembre, cuando empiece el curso escolar y distribuyan los discos ( creo que se los entregan a los profesores y estos los instalan en los ordenadores de los colegios, pero no estoy seguro ). Y podréis seguir las aventuras de los agentes secretos "Zeta" y "Hache".

( Por cierto, ya hay una versión tres del motor, que permite lo que todas las buenas aventuras gráficas, una navegación no lineal, pudiendo volver a escenas ya pasadas en donde, mediante el uso de mementos, se recuerda el estado de las mismas, y un montón de novedades más que ya contaré )