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 )
Comentarios
"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."
Creo que esta frase me ha abierto mucho los ojos, no se me había ocurrido nunca hacer esto y ahora lo estoy pensando y me parece obvio!
De esta forma puedo reutilizar interfaces que puedo usar en varios proyectos.
Gracias!!
Publicado por: Raul Jimenez | Agosto 31, 2006 08:57 AM
Y no sólo eso, puedes modificar el comportamiento de tu aplicación, sin tocar los códigos de la misma, simplemente creando otra clase diferente que implemente el mismo interface. Yo, personalmente, opino que los interfaces son las herramientas más poderosas que hay en actionScript.
Publicado por: Javier Tardáguila | Agosto 31, 2006 10:20 AM
Sí, sí, te entiendo perfectamente, así podría crear una clase VistaCenital, otra VistaLateral y otra Vista3D que implementasen todas a la interface IVista, no?
La verdad que en el caso de las clases lo que menos he usado son las interfaces y creo que ya me toca... ¬¬
Un saludo!! ^^
Publicado por: Raul Jimenez | Agosto 31, 2006 01:44 PM
Efectivamente, y tu las órdenes no se las das a un objeto de tipo VistaCenital o VistaLateral, sino a un objeto de tipo IVista, lo que te permite ir añadiendo todas las vistas que se te ocurran.
Además, ten en cuenta que una clase sólo puede heredar de otra, pero puede implementar todas las interfaces que quieras. Se convierte en algo muy flexible.
Publicado por: Javier Tardáguila | Agosto 31, 2006 01:51 PM
Ajam... así se podrían implementar la VistaCenital y la VistaRayosX por decir algo.
Me gusta, me gusta, tengo que cambiar un poco el chip pero a ver si me pongo, que tengo una cosilla por ahí para hacer y creo que las interfaces irían bien para para un par de clases.
Deu!! Y Gracias!!
Publicado por: Raul Jimenez | Septiembre 1, 2006 12:04 AM
Como curiosidad... ¿cuántos usuarios concurrentes puede manejar un servidor de sockets como Unity? ( según tu experiencia ).
Por otro lado, ¿hay mucha diferencia con otros servers open source como Oregano Multiuser Server?
Con respecto a las interfaces corraboro lo que se ha dicho. Yo lo leí en el libro Patrones de diseño de GOF y me ayudó a comprender mejor otras maneras de afrontar los proyectos.
Gran blog el tuyo ;)
Saludos!
Publicado por: Joan Garnet | Septiembre 1, 2006 01:21 PM
Saludos,
las pruebas de estrés las hizo otra persona pero creo recordar que 2000 conexiones concurrentes las manejaba perfectamente ( pero no estoy seguro del todo )
Por otra parte, yo sólo he trabajado con Unity y con el ya extinto Flash Communication Server ( con Flash Media server no he trabajado ) así que no te puedo contestar a preguntas sobre otros servidores como Oregano server.
Publicado por: Javier Tardáguila | Septiembre 1, 2006 02:10 PM
Hola Javier, (hola raul, hola joan.. jeje estamos los mismos por todos lados!)
Actualmente me voy a enfrentar a un reto de estas características... no es una aplicacion multiusuario muy compleja, pero son 8 juegos multiusuarios de complejidad media.
Estoy planteandome el uso de flash media server o el uso de sockets, aunque como no se usa ni audio ni video veo mas cercana esta ultima posibilidad.
Pintas muy bien unity, y siendo de moock, pues me lo creo perfectamente. Llevo 1 dia y medio mirandome la documentacion para poder tomar la decision correcta, la cosa es que acabo de ver en un post tuyo de algun foro un enlace en el que hablan de electroserver.. y ahora me has hecho dudar :)
has usado electroserver?, la curva de aprendizaje en unity es rapida? Hay que trabajar mucho sobre la parte de servidor en el caso de unity?
Me preocupa mucho la curva de aprendizaje, porque el proyecto es extenso para el tiempo que vamos a tener de desarrollo, aun esta en la primera fase, pero el primer prototipo hay que hacerlo en relativamente poco tiempo y la curva de aprendizaje es lo que mas me preocupa.
Me gustaría contactarte por mail para hacerte unas consultas, si no te parece un atrevimiento por mi parte, escribeme a marcos [en] q-interactiva [punto] com
Gracias de antemano :-)
Publicado por: Marcos | Septiembre 18, 2006 11:57 PM
Saludos,
siempre es dificil tomar una decisión de este tipo. Cuando nosotros decidimos hacer este proyecto, primó el apartado técnico. Creíamos que Unity era el mejor producto para este proyecto, y lo conocíamos ( aunque no en el nivel de profundidad que requería este proyecto ), pero en ocasiones entran en juego otros factores. Los más determinantes son, sin duda el tiempo de desarrollo ( nunca tenemos el suficiente ) y el coste de licencias.
Me centro en aspectos técnicos.
Con Flash Media Server como tal no he trabajado, sí trabajé con Flash Communication Server 1.0 y 1.5. Tengo entendido que FMS trae numerosas mejoras o añadidos de funcionalidades en el lado servidor, como la carga de xml etc... En FCS, para confiar el login o registro al lado servidor necesitabas de Flash Remoting, o AMFPHP o FlashObject. Y sí, podías incluir ( si no recuerdo mal ) la carga de ficheros dentro del main.asc con includes, pero no recuerdo exáctamente. La verdad es que
a) parezco el abuelo cebolletas y estoy desvariando.
b) no me atrevo a recomendar el uso de FMS por eso, porque no lo he usado.
Entre Unity y Electroserver, nosotros nos quedamos con Unity. Hace casi dos años, cuando se hizo el proyecto interno de la empresa, estuve jugando con ambos para ver cual nos parecía mejor. A pesar de tener los libros de Jobe Makar ( creo que lo he escrito bien ) de desarrollo de juegos, en los que enseñaba a utilizar Electroserver, tras las pruebas nos decantamos por Unity inequívocamente. La verdad es que no recuerdo qué motivos eran, pero en la decisión no sólo influyo que Unity hiciese más, o que estuviese mejor, sino que Electroserver no nos convenció. Supongo que desde entonces, haya habido versión nueva, que lo mismo...
Con respecto a unity.
- curva de aprendizaje. Depende, si quieres hacer una aplicación simplemente, es fácil. Si quieres hacer un framework ( como supongo que será tu caso por el hecho de hacer 8 juegos ), pues eso te exige entender bien el UClient, y hay cosas complicadas. Bien es cierto, que nosotros para este proyecto necesitábamos algo muy muy flexible, pues el proyecto crece en varias fases con funcionalidades diferentes en cada una, por lo que la flexibilidad es fundamental. Si en tu caso, el proyecto se limita a estos 8 juegos que me indicas y con las especificaciones muy claras e inamovibles, evidentemente la dificultad es menor.
con respecto a usar o no la parte servidor. Pues ( ya se que esto no aclara mucho ) también depende de tu aplicación. En general, lo puedes hacer todo sin tener que tocar o programar clases java de servidor, pues las clases del UClient son la representación en lado cliente del servidor ( incluso puedes manejar desde cliente las factorías abstractas de creación de rooms ). Ahora bien, si quieres un proceso automático que cada x tiempo emita un evento a todos los usuarios conectados a cierta room ( por ejemplo ) te lo tienes que hacer ( en Unity2 no está implementado, Colin indicó en la lista de correo que en Unity 3 eso estará ), y una de dos, o te lo haces en el lado servidor ( que sería lo propio ) o te creas un sistema por el cual ese proceso lo ejecute el primer usuario que entra en la room que se lo envía a los demás, y en caso de salirse, le cede la responsabilidad de ese proceso a otro usuario ( bastante lioso ).
Si es cierto que la lista de correo de Unity está bien, y eso ayuda. Entiendo que tu mayor preocupación es la curva de aprendizaje. Claro, yo ahora lo veo y como está montado el chiringuito me parece lógico, en su momento me costó. Por cierto, si te decides por Unity, te vendrá muy bien leer en el libro de Colin ( Essential ActionScript 2.0 ) en la tercera parte, el capítulo 19 ( Modelo de Delegación de Eventos ), pues es como está montado UClient.
Publicado por: Javier Tardáguila | Septiembre 19, 2006 09:16 AM
Hola Javier,
antes que nada muchisimas gracias por el tiempo que te has tomado para contestarme, me ha venido muy bien esta vision que has representado.
Estas en lo cierto en el sentido de que aunque si bien queremos reutilizar codigo y que el desarrollo sea progresivo por la reutilizacion y no lineal, no nos enfrentamos a una aplicacion que tenga que ser escalable y super flexible. Los juegos tienen unas especificaciones bien delimitadas y no irán más alla.
Te he mandado un mail, basicamente, confirmas las ideas que tenia tras estos dias de mirarme la documentacion a saco. Lo que me gusto de ElectroServer es que parece contar con una comunidad de desarrollo mas activa, pero tambien me llama de Unity que lo haya realizado moock, toda una garantia de buen trabajo.
El libro lo tengo, y los patrones que detalla tambien me los tengo bastante mirados. Pero aun asi me cuesta decidirme... :( Pero bueno, seguro que con cualquiera de los dos se puede.
El tema es que me he bajado algun ejemplo de Electroserver y me ha parecido mas simple aun que unity, aunque tienen grandes similitudes en las clases que traen preparadas...
Bueno, lo dicho, hablamos y gracias.
Saludos!
Publicado por: Marcos | Septiembre 19, 2006 12:17 PM