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 )