UNIVERSIDAD NACIONAL DEL CENTRO DE LA
PROVINCIA DE BUENOS AIRES
FACULTAD DE CIENCIAS EXACTAS
TRABAJO FINAL DE GRADO DE INGENIERÍA DE
SISTEMAS
SISTEMA DE MANEJO DE PARTIDAS PARA JUEGOS
DE TIPO MULTIJUGADOR POR TURNOS
por
Joaquín Bengochea
Director
Mg. Claudio Aciti
Codirector
Resumen
El objetivo principal de este trabajo fue el desarrollo de un sistema que facilite el desarrollo de juegos de tipo multijugador por turnos.
Mediante un estudio de los sistemas más importantes que existen en el mercado y la funcionalidad provista por cada uno, se determinó la funcionalidad requerida para que el sistema cumpla con las necesidades de los desarrolladores.
El sistema provee a los desarrolladores herramientas que permiten la creación, actualización y eliminación de jugadores dentro del juego, así también como la vinculación de los mismos con sus redes sociales, y la posibilidad de interacción con otros jugadores dentro del juego. Además, permite crear, administrar y eliminar partidas dentro del juego, asignar jugadores a las mismas y encontrar partidas a medida para jugadores específicos.
Se realizó una selección de las tecnologías a utilizar para el desarrollo teniendo en cuenta los requerimientos del sistema y la decisión de la empresa cliente de utilizar Haxe como lenguaje de desarrollo, siendo elegidas Node.js para el desarrollo del servidor y MongoDB como sistema de gestión de bases de datos.
Desde el punto de vista de los resultados obtenidos, el sistema probó decrementar considerablemente el tiempo requerido para el desarrollo de un videojuego de las características mencionadas, y proveyó toda la funcionalidad requerida para su desarrollo. Al mismo tiempo, los tiempos de respuesta y consumo de recursos del sistema fueron muy positivos.
Índice
Resumen ... 2
Índice de Figuras ... 6
Capítulo 1: Introducción ... 9
1.1 Historia de los videojuegos ... 9
1.2 Motivación ... 12
1.3 Objetivo ... 13
1.4 Alcance ... 13
1.5 Limitaciones ... 14
1.6 Organización del trabajo ... 14
Capítulo 2: Estado del Arte ... 16
2.1 Juegos móviles, sociales y casuales ... 16
2.2 Servicios de soporte de Juegos multijugador ... 18
2.2.1 Google Play Games Services... 18
2.2.2 Facebook for Game Developers ... 18
2.2.3 Apple Game Center ... 19
2.2.4 Comparación ... 20
2.3 Sistemas de gestión de bases de datos ... 21
2.3.1 MongoDB ... 21
2.3.2 Cassandra... 23
2.3.3 CouchDB ... 24
2.3.4 Oracle Database ... 25
2.4 Lenguajes de programación para el servidor ... 26
2.4.1 PHP ... 26
2.4.2 Node.js ... 27
2.4.3 Python ... 28
Capítulo 3: Análisis de requerimientos ... 30
3.1 Requerimientos Funcionales ... 30
3.1.1 Partidas ... 30
3.1.2 Jugadores ... 30
3.1.2 Interacción entre usuarios ... 30
3.1.3 Partidas aleatorias ... 30
3.1.4 Customización ... 30
3.2.1 Integridad de datos ... 31
3.2.2 Volumen de datos ... 31
3.2.3 Portabilidad ... 31
3.2.4 Tecnologías libres ... 31
3.2.5 Consumo ... 31
Capítulo 4: Arquitectura y diseño de la solución ... 33
4.1 Selección de tecnologías utilizadas ... 33
4.2 Descripción de la arquitectura de la solución ... 34
4.2.1 Modelo Cliente-Servidor ... 34
4.2.2 Instanciación en el sistema ... 35
4.3 Diseño de la solución... 35
4.3.1 Modelo de datos... 35
4.3.1.1 Game ... 36
4.3.1.2 Player ... 37
4.3.2 Persistencia de datos ... 38
4.3.3 Servidor ... 38
4.3.3.1 Chequeos de integridad de datos ... 38
4.3.3.2 Extensibilidad del servidor ... 40
4.3.3.3 Identificación de los usuarios ... 41
4.3.4 Cliente ... 42
4.3.4.1 Interfaz de comunicación con el servidor... 42
4.3.4.2 Persistencia de datos en el dispositivo ... 44
4.3.4.3 Sincronización de partidas ... 45
4.3.4.4 Tipos de datos... 46
4.3.5 MatchMaking ... 47
4.3.6 Sistema eliminación de partidas antiguas ... 49
4.3.7 Información temporal de partidas ... 49
Capítulo 5: Experiencia de uso del sistema ... 52
5.1 Descripción del juego desarrollado ... 52
5.2 Estructuras de datos específicas ... 56
5.2.1 Datos específicos del jugador ... 57
5.2.2 Datos específicos de la partida ... 57
5.3 Generación de tableros ... 58
5.4 Extensión de funcionalidad del servidor ... 59
Capítulo 7: Trabajos futuros ... 66
7.1 Soporte para juegos en tiempo real ... 66
7.2 Sistema de notificaciones ... 66
7.3 Sistema de monitoreo para el servidor ... 66
Bibliografía ... 68
Índice de Figuras
Figura 1.1: Tennis For Two ... 9Figura 1.2: Super Mario Bros. ... 10
Figura 1.3: Ultima Online ... 11
Figura 1.4: Mobile Apps ... 12
Figura 2.1: Candy Crush ... 16
Figura 2.2: Flappy Bird ... 17
Figura 2.3: MongoDB ... 21
Figura 2.4: Cassandra ... 23
Figura 2.5: CouchDB... 24
Figura 2.6: Oracle Database ... 25
Figura 2.7: PHP ... 26
Figura 2.8: Node.js ... 27
Figura 2.9: Python ... 28
Figura 4.1: Esquema básico del servidor ... 34
Figura 4.2: Cliente-Servidor ... 34
Figura 4.3: Entidad Game ... 36
Figura 4. 4: Entidad Player ... 37
Figura 4.5: Flujo de chequeo de requests ... 39
Figura 4.6: Métodos de la API cliente ... 43
Figura 4.7: Información guardada localmente ... 45
Figura 4.8: Flujo básico de matchmaking ... 48
Figura 5.1: Tablero ... 52
Figura 5.2: Selección de casilla ... 53
Figura 5.3: Ubicación de letra ... 53
Figura 5.4: Letra colocada ... 53
Figura 5.6: Turno del oponente ... 55
Figura 5.7: Desafío ... 56
Figura 5.8: Entidad Board ... 59
Figura 5.9: Amazon SNS Service ... 60
Figura 5.10: Detalles de uso de “Juego de Palabras” ... 61
Figura 5.11: Detalles de uso de Preguntados ... 61
Capítulo 1: Introducción
1.1 Historia de los videojuegos
La industria de los videojuegos es el sector económico involucrado en el desarrollo, la distribución, la mercadotecnia y la venta de videojuegos y del hardware asociado. Se puede considerar como primer videojuego el Nought and Crosses, también llamado OXO, desarrollado por Alexander S. Douglas en 1952[1]. El juego era una versión computarizada del “Tres en Línea”, que se ejecutaba sobre la EDSAC, ordenador de la época, y permitía enfrentar a un jugador contra la máquina. En 1958 William Higginbotham creó, sirviéndose de un programa para el cálculo de trayectorias y un osciloscopio, Tennis for Two (tenis para dos): un simulador de tenis de mesa para entretenimiento de los visitantes de la exposición Brookhaven National Laboratory. Este videojuego fue el primero en permitir el juego entre dos jugadores humanos.
Figura 1.1: Tennis For Two
En 1966 Ralph Baer empezó a desarrollar un proyecto de videojuego llamado Fox and Hounds dando inicio al videojuego doméstico. Este proyecto evolucionaría hasta convertirse en la Magnavox Odyssey, el primer sistema doméstico de videojuegos lanzado en 1972 que se conectaba a la televisión y que permitía jugar a varios juegos pregrabados.
videojuegos (destacando los microprocesadores y los chips de memoria). Aparecieron en los salones recreativos juegos como Space Invaders (Taito) o Asteroids (Atari).
El negocio asociado a esta nueva industria alcanzó grandes cosas en estos primeros años de los 80, pero sin embargo, en 1983 comenzó la llamada crisis del videojuego, afectando principalmente a Estados Unidos y Canadá, y que no llegaría a su fin hasta 1985.
Japón apostó por el mundo de las consolas con el éxito de la Famicom (llamada en occidente como Nintendo Entertainment System), lanzada por Nintendo en 1983 mientras en Europa se decantaba por los microordenadores como el Commodore 64 o el Spectrum.
A la salida de su particular crisis los norteamericanos continuaron la senda abierta por los japoneses y adoptaron la NES como principal sistema de videojuegos. A lo largo de la década fueron apareciendo nuevos sistemas domésticos como la Master System (Sega), el Amiga (Commodore) y el 7800 (Atari) con juegos hoy en día considerados clásicos como el Tetris.
A finales de los 80 comenzaron a aparecer las consolas de 16 bits como la Mega Drive de Sega y los microordenadores fueron lentamente sustituidos por las computadoras personales basadas en arquitecturas de IBM
Figura 1.2: Super Mario Bros.
Nintendo supuso un estallido de creatividad. Por primera vez teníamos un objetivo y un final en un videojuego. En los años posteriores otras compañías emularon su estilo de juego.
Otra rama de los videojuegos que creció con fuerza fue la de los videojuegos portátiles. Estos comenzaron a principios de los 70 con los primeros juegos completamente electrónicos lanzados por Mattel, los cuales difícilmente podían considerarse como videojuegos, y fueron creciendo en popularidad gracias a conversiones de recreativas como las realizadas por Coleco o adictivos microjuegos como las Game & Watch de Nintendo. La evolución definitiva de las portátiles como plataformas de videojuego llegó en 1989 con el lanzamiento de la Game Boy (Nintendo).
Durante la década del „90 en PC eran muy populares los FPS (juegos de acción en primera persona) como Quake (id Software), Unreal (Epic Megagames) o Half-Life (Valve), y los RTS (juegos de estrategia en tiempo real) como Command & Conquer (Westwood) o Starcraft (Blizzard). Además, conexiones entre ordenadores mediante internet facilitaron el juego multijugador, convirtiéndolo en la opción predilecta de muchos jugadores, y fueron las responsables del nacimiento de los MMORPG (juegos de rol multijugador online) como Ultima Online (Origin).
Figura 1.3: Ultima Online
juego y dándole mucha importancia a la interacción entre usuarios, generalmente a través de redes sociales [2].
Figura 1.4: Mobile Apps
1.2 Motivación
Una de las mayores categorías dentro de los videojuegos multijugador casuales es la de los juegos por turnos. Estos juegos aprovechan al máximo la interactividad entre distintos jugadores, la posibilidad de socializar entre ellos y los tiempos cortos de juego, haciéndolos la mejor opción para los jugadores casuales que no tienen tiempo para estar varias horas jugando.
Los servicios existentes que proveen una serie de herramientas para facilitar el desarrollo de juegos de este tipo son escasos y, en algunos casos, poco completos o dependientes de una plataforma o servicio específico [3, 4, 5]. Esto se debe a que en su mayoría son desarrollados por empresas que poseen ya una plataforma social específica, y crean el servicio para facilitar el desarrollo de mejores aplicaciones para poder brindarle un mejor servicio a sus clientes.
Center provee sus propias herramientas para el manejo de este tipo de juegos, pero están restringidas a iOS, con usuarios registrados con su Apple ID [5].
De esta manera, si un desarrollador desea cubrir una mayor cantidad de jugadores, deberá implementar varios servicios diferentes dependiendo de las plataformas que desee abarcar, lo que conlleva a una mayor complejidad de código y un mayor tiempo de desarrollo.
1.3 Objetivo
Desarrollar un sistema que facilite el desarrollo de juegos de tipo multijugador por turnos, brindando herramientas que permitan tanto la identificación de un usuario dentro del juego con un método en particular, como con un conjunto de ellos, el manejo completo de partidas (creación, modificación, vinculación con los jugadores, eliminación de partidas terminadas), y la interacción entre jugadores.
Objetivos parciales a cumplir:
● Lograr que la diferencia entre distintas redes sociales utilizadas para la identificación sea transparente para el desarrollador y para el mismo usuario. ● Lograr que el sistema soporte grandes volúmenes de transacciones, como
los que se generarían al ser utilizado por un videojuego con muchos usuarios jugando en simultáneo.
● Permitir que el sistema funcione de forma independiente a las plataformas sociales que pueda utilizar, de forma que se pueda utilizar indistintamente de si se utilizan otros medios de identificación o no.
1.4 Alcance
Los mismos deberán ejecutarse en dispositivos móviles que corran los sistemas operativos Android o iOS.
Para el desarrollo de la solución se solicitó por pedido expreso de la empresa cliente la utilización del lenguaje Haxe.
1.5 Limitaciones
Las limitaciones que se considerarán para la ejecución del sistema son las siguientes:
● Se debe contar con un servidor web que pueda ejecutar el mismo y responder los pedidos de los usuarios.
● Los juegos desarrollados con este sistema deben correr en dispositivos móviles con conexión a Internet.
1.6 Organización del trabajo
Capítulo 2: Estado del Arte
2.1 Juegos móviles, sociales y casuales
“Mientras que el término “gamer” probablemente evoca una imagen particular para muchas personas -tal vez el estereotipo de chico nerd adolescente jugando en múltiples pantallas en el sótano de su casa- el término nunca ha sido representativo para la mayoría de personas que juegan videojuegos”[2]. De hecho, según datos de la Entertainment Software Rating Board, el promedio de edad de los jugadores está entre 18 y 45 años, habiendo igual cantidad de hombres y mujeres que juegan [6].
El mayor cambio en el ambiente del gaming es el incremento en el rango de dispositivos y plataformas en las en los cuales se puede jugar. Desde que las redes sociales online como Facebook facilitan a los juegos sociales a ser jugados con el entorno social del jugador, y los dispositivos móviles como smartphones y tablets permiten que casi todos puedan llevar sus aplicaciones donde quiera que vayan, los juegos se han tornado cada vez más omnipresentes. Vagones de trenes están a menudo repletos de jugadores tirando con resorteras digitales y asediando cerdos en Angry Birds, o intentando formar líneas de brillantes caramelos en Candy Crush Saga.
Figura 2.1: Candy Crush
Casual (2010) [7], Juul identifica un género de juegos y, consecuentemente, un tipo de jugadores que está emergiendo, el cual en contraposición con el gamer estereotípico, proviene de un espectro demográfico mucho más amplio, y suele jugar en ráfagas cortas de tiempo. Sin embargo, esta característica de los jugadores casuales se vuelve rápidamente problemática, ya que la experiencia muestra que los juegos diseñados para permitir períodos cortos de juego también pueden ser suficientemente irresistibles para ser jugados de manera larga y focalizada, tanto como los juegos más hardcore.
Figura 2.2: Flappy Bird
2.2 Servicios de soporte de Juegos multijugador
2.2.1 Google Play Games Services
Play Games es el conjunto de servicios de Google orientado al desarrollo de videojuegos [3]. Se incluye dentro del paquete de servicios Google Play Services, y provee una serie de herramientas destinadas a desarrollar de forma rápida las partes del juego en las que se puede encontrar la interacción entre los jugadores.
Entre los servicios mencionados, pueden encontrarse:
● Logros: Hitos importantes dentro del juego, tendientes a aumentar el compromiso del jugador para con éste, o a mostrar formas alternativas de juego; y generar un refuerzo positivo para el usuario durante el juego.
● Marcadores: Rankings entre jugadores basados en distintos criterios específicos del juego, buscando aumentar la competitividad y mejorar la sensación de interactividad entre los usuarios.
● Partidas guardadas: Disponibilidad de espacio en la nube para guardar los datos del juego, estando accesibles así para el jugador, no importa desde qué dispositivo desee jugar.
● Multijugador: posibilidad de crear partidas entre varios jugadores, en tiempo
real o por turnos, utilizando los círculos de Google+ para conectarse con amigos, o creando partidas automáticas contra oponentes aleatorios.
Estos servicios están disponibles para dispositivos con Android o iOS, pero requieren que el usuario ingrese con una cuenta de Google+ para poder utilizarlos. Además, soportan hasta un máximo de 4 jugadores para partidas multijugador.
2.2.2 Facebook for Game Developers
el juego; dando a conocer éste a sus amigos y de esta manera ampliando la cantidad de usuarios que llegan al juego de forma orgánica.
A diferencia de la contraparte de Google, Facebook no posee un servicio integral para el desarrollo de juegos multijugador, pero en cambio posee dos herramientas que pueden ayudar a la hora de desarrollar uno:
● Game Requests: Servicio que permite enviar notificaciones mediante Facebook a personas que no tienen el juego instalado, invitándolos a descargarlo y jugarlo.
● App-To-User notifications: Este servicio permite a la aplicación mostrar notificaciones al usuario incluso cuando la aplicación no está corriendo, alertando al mismo sobre eventos que puedan haber pasado en el juego en tiempo real (notificación sobre el turno de una partida por ejemplo).
Los servicios de Facebook están disponibles en casi cualquier plataforma, pero es necesaria una cuenta de Facebook para poder utilizarlos.
2.2.3 Apple Game Center
Game Center es la red social orientada a juegos de Apple [5]. Es una colección de componentes que brindan distintos tipos de herramientas y funcionalidades tanto para los desarrolladores como para los mismos jugadores.
Está compuesta por 3 componentes principales:
● Game Center Service es la parte online de Game Center. Estos servidores almacenan la información de los juegos y jugadores, y brindan datos y otros servicios a los distintos dispositivos.
● Game Kit Framework es un conjunto de clases destinadas a que los desarrolladores puedan incluir de forma simple los servicios brindados a sus juegos.
● Game Center App es una aplicación centralizada para que los usuarios puedan acceder a todas las funcionalidades de Game Center.
crear partidas multijugador y creación de partidas con oponentes aleatorios utilizando un sistema de auto-matching.
Este servicio sólo está disponible para iOS y Mac OS X, y requiere de una cuenta de Apple para funcionar.
2.2.4 Comparación
A continuación se muestra un cuadro comparativo con las principales características de los sistemas nombrados anteriormente:
Google Play Games Services
Facebook for Game developers
Apple Game Center
Logros y marcadores
Si No Si
Partidas guardadas
Si No Si
Game Requests No Si No
Notificaciones App-To-User
No Si No
Soporte Multijugador
Si No Si
Player auto-matching
Si No Si
Multiplataforma Si Si No
2.3 Sistemas de gestión de bases de datos
2.3.1 MongoDB
MongoDB es una base de datos poderosa, flexible y escalable de propósito general, que combina una alta escalabilidad con características como índices secundarios, consultas de rango, agregaciones e índices geoespaciales [8].
Figura 2.3: MongoDB
Es una base de datos orientada a documentos. La razón principal por la que alejarse del modelo relacional, es la de facilitar el escalado del sistema. Las bases de datos orientadas a documentos reemplazan el concepto de “tupla” con un modelo más flexible, el “documento”. Permitiendo tener documentos embebidos y arreglos de distintos tipos, es posible representar relaciones jerárquicas complejas en un mismo registro. Ésto se ajusta más naturalmente a la forma en que los desarrolladores en lenguajes orientados a objetos modernos piensan acerca de sus datos.
Los volúmenes de datos con los que cuentan las aplicaciones están creciendo a un ritmo increíble. Los incrementos en el ancho de banda disponible y los bajos costos de almacenamiento han creado un entorno en el que incluso aplicaciones de pequeña escala necesitan de más datos de los que muchas bases de datos fueron pensadas para manejar. Un terabyte de información, antes una cantidad inaudita, ahora es muy común.
Conforme la cantidad de información que se debe almacenar aumenta, los desarrolladores deben afrontar la decisión de cómo escalar sus bases de datos. Se debe decidir entre escalar verticalmente, es decir, conseguir hardware más grande, o escalar horizontalmente, lo que significa repartir la información entre múltiples máquinas. Escalar verticalmente es más simple, pero muy costoso y limitado.
de un clúster, redistribuir los documentos automáticamente y rutear los requests de los usuarios a las máquinas correctas. Ésto permite a los desarrolladores focalizarse en programar la aplicación, no escalarla. Cuando un clúster necesita más capacidad, nuevas máquinas pueden ser añadidas y MongoDB determinará cómo debe redistribuirse la información en ellas.
MongoDB fue pensado para ser una base de datos de propósito general, por lo que además de la creación, lectura, actualización y borrado de datos, provee una creciente lista de funciones únicas:
● Indexación: Soporta índices secundarios genéricos, permitiendo una variedad de queries rápidos. También provee capacidades de indexación únicas, compuestas, geo-espaciales y de texto completo. ● Agregación: MongoDB soporta un pipeline de agregaciones que
permite crear agregaciones complejas desde piezas simples, y permite a la base de datos optimizarlas.
● Tipos especiales de colecciones: MongoDB soporta colecciones con tiempo de vida, para datos que deben expirar luego de cierto tiempo, como sesiones. También soporta colecciones de tamaño fijo, útiles para almacenar información reciente, como logs.
● Almacenamiento de archivos: MongoDB soporta un protocolo fácil de usar para almacenar grandes archivos y metadata de ellos.
Algunas características comunes a las bases de datos relacionales no están presentes en MongoDB, como Joins y transacciones complejas multi-tupla. Estas omisiones son decisiones arquitecturales para permitir una mayor escalabilidad, ya que ambas características dificultan la eficiencia en un sistema distribuido.
2.3.2 Cassandra
Apache Cassandra es una base de datos orientada a columnas, distribuida, descentralizada y escalable desarrollada por Facebook [9]. Basa su diseño de distribución en la base Dynamo de Amazon, y su modelo de datos en BigTable de Google.
Figura 2.4: Cassandra
Cassandra es distribuido, lo que significa que es capaz de correr en múltiples máquinas mostrándose a los usuarios como si fuera una sola. De hecho, no está pensado para ejecutarse en un solo nodo, sino que sus beneficios son apreciados al correr múltiples instancias de la misma.
Cuando se escalan otros almacenamientos de datos, como MySQL o Bigtable, algunos nodos necesitan ser establecidos como maestros para poder organizar al resto de ellos, denominados como esclavos. Cassandra, en cambio, es descentralizado, por lo que cada nodo es idéntico, y ejecuta las mismas acciones de organización. Cassandra utiliza un protocolo peer-to-peer y gossip para mantener su lista de nodos organizados y sincronizados. Esta descentralización también significa que no hay un único punto de fallo, lo que provee una buena disponibilidad y tolerancia a errores.
Cassandra fue diseñado para tomar ventaja de las máquinas multiprocesador/multinúcleo, y para correr en docenas de éstas máquinas alojadas en distintos data centers. Escala consistentemente y sin problemas a cientos de terabytes, y performa bien bajo cargas pesadas.
2.3.3 CouchDB
Apache CouchDB es una base de datos documental, diseñada priorizando la facilidad de uso y con una arquitectura interna tolerante a fallos. Está diseñado para manejar de forma eficiente las variaciones de tráfico, absorbiendo una gran cantidad de requests sin fallar en detrimento del tiempo de respuesta promedio de cada request, pero respondiéndolos todos. Al volver a disminuir el tráfico, vuelve a su velocidad de respuesta habitual [10].
Figura 2.5: CouchDB
CouchDB toma su diseño de la arquitectura web y de los conceptos de recursos, métodos y representaciones, y aumenta ésto con una potente forma de consultar, mapear, combinar y filtrar la información. Al mismo tiempo, CouchDB no requiere de un esquema predefinido para los documentos, sino que cada documento tiene su propio esquema autocontenido.
CouchDB provee una semántica de atomicidad, consistencia, aislamiento y durabilidad, implementando una forma de control de concurrencia multiversión, lo que significa que puede manejar un gran número de lectores y escritores en paralelo, sin que surjan conflictos.
2.3.4 Oracle Database
Oracle Database es un sistema de manejo de bases de datos Objeto-Relacional desarrollado por Oracle Corporation. El sistema está creado sobre un framework de bases de datos relacionales, y es accedido mediante SQL. Su modelo de integridad se basa en las reglas ACID(Atomicity, Consistency, Isolation, Durability), y provee características de integridad como transacciones, integridad referencial y control de versión.
Figura 2.6: Oracle Database
Oracle Database está diseñado para utilizar grid computing [11], es decir crear grandes conjuntos de almacenamiento modular y servidores. Con esa arquitectura, cada nuevo sistema puede ser rápidamente provisionado desde ese conjunto de componentes. No hay necesidad de picos en la carga de trabajo, porque la capacidad puede ser fácilmente aumentada o reposicionada desde los conjuntos de recursos de ser necesario.
La información en Oracle Database está almacenada físicamente en ficheros, pero posee una división lógica de los datos por medio de espacios de tablas.
2.4 Lenguajes de programación para el servidor
2.4.1 PHP
PHP es un lenguaje de programación de uso general de código del lado del servidor, originalmente diseñado para el desarrollo web de contenido dinámico.
PHP puede ser usado de tres formas principales:
● Scripting del lado del servidor: php fue originalmente diseñado para crear contenido web de forma dinámica, y sigue siendo uno de los mejores en esta tarea. Para generar HTML, se necesita de un parser PHP y un servidor web a través del cual enviar los documentos codificados. PHP también se volvió popular para generar documentos XML, gráficos, animaciones flash y documentos PDF.
● Scripting de línea de comandos: PHP puede ejecutar scripts desde la línea de comandos, como Perl, awk o el Shell de Unix. Éstos pueden ser usados para tareas de administración del sistema, como backups o parseo de logs.
● Aplicaciones de interfaz gráfica del lado del cliente: Usando PHP-GTK se pueden crear aplicaciones completas y multiplataforma de interfaz gráfica con PHP.
Figura 2.7: PHP
PHP corre en todos los sistemas operativos principales, desde variantes de Unix incluyendo Linux, Ubuntu, Debian y Solaris hasta Windows o Mac OS X. también puede ser utilizado por todos los principales servidores web, incluyendo Apache, Microsoft IIS o servidores Netscape/iPlanet.
2.4.2 Node.js
Node.js es un entorno en tiempo de ejecución de JavaScript, basado en el motor V8 de Google. Su modelo se basa en un entorno asíncrono orientado a eventos. Fue creado con el enfoque de ser útil en la creación de programas de red altamente escalables, como servidores web [14].
Figura 2.8: Node.js
Node.js funciona con un modelo de evaluación de un único hilo de ejecución, usando entradas y salidas asíncronas, las cuales pueden ejecutarse concurrentemente en un número de hasta cientos de miles sin incurrir en costos asociados al cambio de contexto. Este diseño de compartir un único hilo de ejecución entre todas las solicitudes atiende a necesidades de aplicaciones altamente concurrentes en el que toda operación que realice entradas y salidas debe tener un callback.
Cuando una conexión se establece un callback es ejecutado. Al final de cada ejecución, el lazo de eventos es activado para ejecutar el siguiente callback. En caso de que no haya ninguno, el lazo de eventos se termina y el servidor queda en modo de espera hasta que otra conexión llegue.
Con esta forma de trabajo se logra generar el efecto de paralelismo en las conexiones sin depender de la utilización de concurrencia a nivel de threads, lo que elimina las desventajas que esta opción acarrea, y facilita la escalabilidad del sistema.
instalación y actualización de módulos, así también como el manejo de las dependencias entre los mismos.
Node.js puede ser combinado con una base de datos documental (MongoDB o CouchDB) y JSON, lo que permite desarrollar un entorno de desarrollo javascript unificado. Con la adaptación de los patrones de desarrollo del lado del servidor tales como MVC y sus variantes, Node.js facilita la reutilización de código de interfaz entre el lado del cliente y el lado del servidor.
2.4.3 Python
Python es un lenguaje de programación interpretado, multipropósito y de alto nivel. Su filosofía de diseño enfatiza la productividad del desarrollador y la legibilidad del código [15].
Figura 2.9: Python
Es un lenguaje multiparadigma, por lo que soporta programación orientada a objetos, programación imperativa y programación funcional. Utiliza tipado dinámico y manejo automatizado de memoria mediante conteo de referencias.
Python fue publicado por primera vez por Guido Van Rossum en 1991. El lenguaje tiene un modelo abierto de desarrollo basado en la comunidad administrado por la organización sin fines de lucro Python Software Foundation.
Python contiene una larga colección de funcionalidad precompilada y portable, conocida como librería standard. Ésta provee soporte para distintas tareas, desde búsqueda de patrones de texto hasta scripting de redes. Además, Python puede ser extendido con una vasta colección de librerías de terceros [16].
Capítulo 3: Análisis de requerimientos
3.1 Requerimientos Funcionales
3.1.1 Partidas
El sistema debe permitir la creación de partidas para juegos de tipo multijugador por turnos, la vinculación de éste con sus jugadores, su actualización y su posterior eliminación una vez terminada la partida.
3.1.2 Jugadores
Los jugadores deberán poder ingresar al juego mediante algún método de identificación provisto por éste. El sistema deberá guardar los datos del jugador, así también como las partidas que éste está llevando a cabo.
3.1.2 Interacción entre usuarios
El sistema deberá mantener una lista de usuarios que un jugador conozca y desee conservar para poder jugar con ellos en algún momento. Sin embargo, un jugador deberá poder jugar contra otros jugadores que no conozca, elegidos aleatoriamente.
3.1.3 Partidas aleatorias
Cuando un jugador desea hacer una partida de forma aleatoria con otro jugador desconocido, el sistema deberá encontrar un jugador que se adapte al perfil del primero, teniendo en cuenta parámetros como el idioma o la experiencia de juego de los usuarios.
3.1.4 Customización
determinados del tipo de juego, particularidades en la creación o actualización de partidas o modificaciones a los datos de los jugadores.
3.2 Requerimientos no funcionales
3.2.1 Integridad de datos
Se debe asegurar la validez de cualquier dato que entre al sistema o salga de él, verificando que cualquier modificación tanto de los jugadores como de las partidas entre ellos sea correcta y sea accesible sólo a los usuarios autorizados.
3.2.2 Volumen de datos
Para poder soportar un eventual aumento masivo de la cantidad de jugadores de un determinado juego, el sistema debe poder manejar grandes volúmenes de datos sin tener problemas de performance.
3.2.3 Portabilidad
Se requiere que el sistema pueda ser utilizado en distintas plataformas móviles. Como mínimo debe poder funcionar tanto en Android como en iOS.
3.2.4 Tecnologías libres
Es deseable la utilización de tecnologías libres para el desarrollo del sistema, en especial el lenguaje Haxe y el framework OpenFL.
3.2.5 Consumo
Capítulo 4: Arquitectura y diseño de la
solución
4.1 Selección de tecnologías utilizadas
Se puede dividir a la elección de las tecnologías utilizadas en dos decisiones importantes: Por un lado la elección del sistema de gestión de bases de datos a utilizar, por otro, la selección de la tecnología con la que se desarrollará el servidor del sistema.
Se analizaron varios posibles sistemas de gestión de bases de datos: Cassandra, CouchDB, MongoDB y Oracle Database. Oracle Database tuvo que descartarse prontamente por dos motivos: el requerimiento de utilizar tecnologías libres para el desarrollo, sumado a las limitaciones de la versión libre de la misma; y la necesidad de no estar ligado a un esquema fijo de datos, dada la diferencia de información que juegos diferentes pueden necesitar.
La flexibilidad de datos que proveen las bases de datos orientadas a documentos, sumado a la pérdida de potencial que podría ocurrir en una base de datos Cassandra que corra en un servidor pequeño que no pueda aprovechar su diseño distribuido, ponen a ésta en una situación de desventaja respecto de MongoDB y CouchDB. Al mismo tiempo, las ventajas de performance de MongoDB respecto de sus competidores [17], sumado a su facilidad para procesar tanto pequeños como grandes volúmenes de datos, hicieron de éste el sistema de gestión de bases de datos elegido.
Para la elección de la tecnología utilizada para el desarrollo del servidor, se tomó en cuenta el requerimiento de utilizar Haxe como lenguaje de desarrollo. Haxe es un Kit de herramientas open-source basado en un lenguaje de programación de alto nivel, un cross-compiler, una librería estándar multiplataforma y formas de acceder a las capacidades individuales de cada plataforma [18]. Dentro de sus posibles salidas, se encuentran PHP, Python y Node.js (javascript).
el tipado fuerte y la detección de errores en tiempo de compilación, crean un complemento perfecto para JavaScript, eficientizando el desarrollo en esta tecnología.
Así, la arquitectura general del servidor, con las tecnologías elegidas, puede verse como en la figura 4.1.
Figura 4.1: Esquema básico del servidor
4.2 Descripción de la arquitectura de la solución
4.2.1 Modelo Cliente-Servidor
El modelo cliente-servidor, es una arquitectura para aplicaciones distribuidas que divide la carga del sistema en dos grupos: los proveedores de recursos o servicios, llamados servidores, y los solicitantes de los mismos, llamados clientes.
Clientes y servidores se ejecutan en hardwares separados, comunicándose entre sí por redes computacionales. Cada servidor corre uno o más programas que se encargan de compartir sus recursos con los clientes. Estos últimos, en cambio, no comparten sus recursos con los servidores, y realizan pedidos de contenido y servicios a éstos.
Los clientes y servidores se envían información mediante un patrón de mensajes request-response. El cliente envía un request al servidor, y éste devuelve un response. Para poder comunicarse, ambos deben seguir un protocolo de comunicación, es decir, compartir un lenguaje común y seguir un conjunto de reglas que les permitan saber cómo interpretar los mensajes recibidos.
4.2.2 Instanciación en el sistema
El sistema está arquitecturado tomando como base el modelo cliente-servidor. Se posee un servidor que atiende todos los requests de los clientes y tiene acceso a la base de datos del sistema.
En cada dispositivo en el que se corre el juego desarrollado, se crea una instancia de cliente, que enviará requests al servidor para que éste le provea la funcionalidad requerida.
4.3 Diseño de la solución
4.3.1 Modelo de datos
4.3.1.1 Game
Dentro de la entidad “Game” se encuentran todos los datos concernientes a una partida específica del juego.
Figura 4.3: Entidad Game
Cada partida debe contener la siguiente información:
-ID: Se debe tener una forma de identificar a cada partida en particular.
-Estado: Debe haber una forma de clasificar las partidas dependiendo del estado de avance de la misma.
-Jugadores: Lista los jugadores implicados en la partida.
-Total de jugadores alcanzado: se debe poder saber si se espera que ingresen más jugadores a la partida o, por el contrario, la partida ya posee todos sus jugadores. -Partida aleatoria: Diferencia el tipo de partida entre las hechas entre amigos o con oponentes aleatorios. Sirve para determinar si un jugador cualquiera puede entrar a esa partida o está restringida para los amigos del creador de la misma.
-Turno: específica que jugador debe ejecutar el siguiente turno de la partida.
-Datos particulares del juego: Datos necesarios para el juego que son característicos del mismo y no necesariamente generales a todo juego por turnos, como por ejemplo datos del tablero en caso de que hubiera uno en el juego, puntajes, vida y experiencia de los jugadores durante la partida, etc.
-Nivel: El nivel de la partida se define por el nivel del creador de la misma, y es utilizado para encontrar un oponente adecuado en las partidas aleatorias.
-Última actualización: Indica cuándo fue modificada la partida por última vez. -Fecha de creación: Indica cuando fue creada la partida.
-Vistas: Listado de jugadores que han visto la partida terminada. Facilita la limpieza de partidas concluidas.
-Recompensas: Premios o castigos que deben recibir los jugadores al ganar o perder la partida.
4.3.1.2 Player
La segunda entidad que modela los datos necesarios para el funcionamiento del sistema es “Player”. En ella se encuentra la información concerniente a cada jugador que ingresa al sistema.
Figura 4. 4: Entidad Player
Los datos indispensables de la misma son:
-ID: identificador único con el cual se reconoce a cada jugador.
-Nombre: Nombre con el que el jugador puede ser reconocido por el resto de los usuarios.
-Datos específicos para el juego: información importante sobre el jugador que es característica del juego desarrollado, como por ejemplo la cantidad de monedas o el inventario que posee en el juego.
-Nivel: El grado de experiencia del jugador.
-IDs de redes sociales: Identificadores proporcionados por distintas plataformas sociales que el usuario conectó con el sistema (Facebook, Google, Twitter).
-Amigos: Lista de otros jugadores que el usuario conoce, tanto por el juego en sí como por las redes sociales conectadas con su cuenta.
4.3.2 Persistencia de datos
El sistema garantiza la persistencia de la información utilizada por medio de una base de datos MongoDB. Ésta tiene dos colecciones: La primera es utilizada para guardar las partidas del juego, mientras que en la otra se guardan los jugadores del mismo.
Tanto cada partida como cada jugador constituyen un documento individual dentro de sus respectivas colecciones, y poseen como mínimo los campos modelados en sus respectivas entidades.
4.3.3 Servidor
El servidor es el encargado de recibir los pedidos realizados por los clientes, chequear la veracidad de los mismos, procesarlos y enviar las respuestas correspondientes a esos pedidos.
Cuando el servidor HTTP recibe un pedido, éste es enviado al Request Manager para que realice los chequeos de seguridad correspondientes, verifique que el pedido es válido, y llame a la función correspondiente para que devuelva el resultado de la misma. Cuando la función termina su ejecución, llama un callback con la información resultante, el cual realiza la respuesta correspondiente al pedido original.
4.3.3.1 Chequeos de integridad de datos
el cliente envía una serie de datos que permiten comprobar la fuente del pedido, de forma que nadie ajeno al sistema pueda modificar ningún request, ni enviar otros requests al servidor sin autorización.
Figura 4.5: Flujo de chequeo de requests
En la figura 4.5 se muestra el flujo de ejecución realizado por cada request que llega al servidor. A continuación, se explican cada uno de los chequeos que se realizan.
Chequeo de versión: Conforme pasa el tiempo y el juego está en el
mercado, éste puede requerir de actualizaciones que pueden llegar a modificar aspectos importantes del juego. En caso de que estas modificaciones afecten la estructura base de los datos del juego, el desarrollador podría necesitar que los jugadores posean instalada una versión específica del juego para poder jugar correctamente. Para contemplar esta posibilidad, el servidor recibe del cliente junto con cada pedido, el número de versión de la aplicación que está haciendo el pedido. Si el número de versión no es mayor o igual al mínimo requerido por el servidor, éste enviará como respuesta un mensaje de error solicitando que se actualice la aplicación para poder seguir utilizándola.
Chequeo de tiempo de vida del request: Otro aspecto a tener en cuenta
chequeo. Si la diferencia está dentro del rango aceptable, se procesa el pedido. Si no lo está, se envía un mensaje de error notificándolo. El único inconveniente de este chequeo es su dependencia de que el dispositivo tenga una fecha y hora correctas. Para atacar este problema, en conjunto con cada respuesta, se envían la fecha y hora exactas del servidor, para que el cliente pueda calcular, en caso de ser necesario, el desfasaje respecto a la fecha y hora del dispositivo.
Chequeo de validez de origen del request: El sistema debe garantizar que
solo sea utilizado por quienes están autorizados a hacerlo. Para lograr esto, el sistema utiliza un sistema de firmas por md5+salt. El salt es un texto en común que comparten tanto el cliente como el servidor, y es conocido sólo por ellos. El cliente al enviar un request, genera el md5 de los datos a enviar más el salt, y envía esta cadena junto con los datos originales. En el servidor, cuando se llega un request se genera un nuevo md5 con el salt propio del servidor y los datos que llegaron. Para que el pedido se procese las dos cadenas md5 generadas deben coincidir. Ésto permite confirmar que el cliente que realizó el request tenía autorización, y que los datos no fueron alterados durante su envío.
Chequeo de validez de parámetros: Una vez corroborados los anteriores
chequeos, se debe comprobar si el request realizado es un pedido válido y si los parámetros enviados en él son correctos. Para esto, el servidor divide la información enviada en el request en 2 componentes: el primero es la función a la que se debe llamar, y el segundo es la lista de parámetros con la que debe llamarse a la misma. Así, se chequea que tanto el nombre de la función a llamar sea correcto, como que la cantidad y el tipo de parámetros sean los adecuados para esa función en particular. En caso de que el nombre, la cantidad o el tipo de parámetros sean incorrectos, el servidor enviará un mensaje de error informándolo en la respuesta del request. En caso contrario, la función se ejecutará normalmente.
4.3.3.2 Extensibilidad del servidor
heredando de su clase principal y re-implementando o creando nuevas funciones en la clase hijo. Al mismo tiempo, las estructuras utilizadas para guardar los datos contienen campos especiales destinados a poseer información específica del juego, en caso de que sea necesario extender los datos ya guardados del mismo.
Entre los beneficios que conlleva este aumento de potencial del servidor, se encuentran:
-Verificar la validez de las jugadas realizadas teniendo en cuenta aspectos propios del juego desarrollado, como comprobar que una jugada de una partida de ajedrez es válida antes de actualizarla.
-Crear datos específicos del juego relacionado, como por ejemplo establecer un monto de monedas inicial para cuando se crea un nuevo jugador.
-Realizar cambios en la lógica de las actualizaciones de las partidas y los jugadores, como aumentar o disminuir el nivel de un jugador dependiendo del resultado de una partida.
4.3.3.3 Identificación de los usuarios
La forma de identificar a los usuarios dentro del sistema se conforma de 2 niveles. La identificación primaria consiste en el identificador creado por el sistema para este usuario, que corresponde al id principal del documento creado para alojarlo. Este identificador es el utilizado por el sistema para realizar todas las operaciones con el jugador.
La identificación secundaria, por otra parte, está compuesta por los identificadores de las redes sociales anexadas al jugador. Estas son utilizadas para obtener el identificador principal del jugador en el momento de loguearse, o para crearlo en caso de no existir todavía.
modo “invitado” (sin identificarse), podría prescindirse de los métodos secundarios de identificación y utilizar únicamente el medio principal para ello.
Por otra parte, en caso de que un usuario se loguee y cree jugadores nuevos con distintas redes sociales en distintos dispositivos, o en el mismo habiendo borrado los datos, y luego desee conectar una de esas redes al otro de los jugadores creados por el sistema, éste permite combinarlos en uno solo, manteniendo los amigos, las partidas y todos los datos guardados de ambos.
4.3.4 Cliente
Este componente del sistema se incluye dentro del juego a desarrollar, a modo de librería, y funciona como nexo entre el juego y el servidor. De esta forma, el código de éste es incorporado con el propio código del juego, y una instancia del cliente es creada cada vez que la aplicación se ejecuta.
El cliente cumple con varias funciones principales:
● Define las posibles funcionalidades que pueden ser requeridas al servidor. ● Permite la persistencia en el dispositivo de los datos actuales del juego. ● Establece un modo de sincronización de estos datos persistidos, con los
datos almacenados en el servidor.
A continuación de describen en detalle cada una de las funciones mencionadas:
4.3.4.1 Interfaz de comunicación con el servidor
Para poder garantizar una comunicación con el servidor que sea simple para el programador, y al mismo tiempo garantizar la seguridad del sistema y la integridad de los datos enviados y recibidos, se define una única forma de comunicación con el servidor. Cada dato que se envía y se recibe de éste debe pasar por la interfaz de comunicación provista por el cliente del sistema.
De esta manera, se logra eximir al desarrollador de la necesidad de lidiar con la forma de comunicarse con el servidor, brindándole una forma limpia y fácil de comunicación, y ahorrando mucho tiempo de desarrollo y líneas de código.
Figura 4.6: Métodos de la API cliente
Como puede apreciarse en la Figura 4.6, las distintas funciones provistas por esta interfaz son:
● Agregar un jugador a la lista de amigos de otro
● Vincular o desvincular una red social a la cuenta de un jugador ● Crear un nuevo jugador
● Obtener la lista de amigos de un jugador ● Obtener una partida en particular
● Obtener la lista de partidas asociadas a un jugador ● Obtener un jugador mediante su ID
● Obtener un jugador mediante el ID de una red social asociada al mismo
● crear una partida contra un oponente aleatorio
● Desvincular la cuenta de un jugador con el dispositivo. ● Crear una nueva partida contra un amigo
● Crear una partida única contra un amigo(u obtener dicha partida si ya se está jugando una contra ese amigo)
● Actualizar los datos de una partida
● Actualizar las vistas de una partida terminada. ● Actualizar los datos de un jugador
Estas operaciones deben efectuarse de forma asincrónica, es decir, no pueden afectar a la temporalidad del juego. La principal razón es la de evitar que el juego se “congele” esperando a que se complete una operación en el caso de que la conexión a internet del dispositivo sea mala. Otra razón importante es la de hacer transparente dichas actividades al usuario del juego, ya que los cortes en la temporalidad del juego afectarían la inmersión del jugador, perjudicando la experiencia de juego.
Para lograr el asincronismo del juego, cada función recibe como parámetro un callback, otra función que es ejecutada cuando la respuesta de la primera es recibida. Este callback recibe los datos resultantes de la operación realizada o, en caso de que haya ocurrido algún error, un texto que describa cuál fue el problema. De esta manera, se puede programar el comportamiento de la aplicación tanto en el caso de que la operación sea exitosa como en el caso de que falle.
4.3.4.2 Persistencia de datos en el dispositivo
guardados, actualizarlos con la nueva información recibida desde el servidor, utilizarlos durante la ejecución de la aplicación y guardarlos en el dispositivo.
Figura 4.7: Información guardada localmente
Los datos que se manejan son los siguientes:
● Información del jugador: Al mantener los datos del jugador en la memoria del dispositivo, se permite la carga rápida del juego. facilita la actualización del mismo ya que centraliza la ubicación de los datos. ● Información sobre los amigos del jugador: el cliente también mantiene
una lista de los amigos del jugador, con información como el ID, nombre y nivel, para agilizar la carga de los datos en las partidas que involucren a los mismos.
● Nombres de jugadores: También se mantiene una lista de nombres de jugadores, asociados a sus IDs, que no necesariamente requieren ser amigos del jugador logueado en el dispositivo. Ésto ayuda a ahorrar tiempo en la creación de partidas aleatorias, identificando más rápidamente al adversario.
● Fotos de perfil: En caso de necesitar mostrar una foto del jugador o de sus amigos en el juego, el cliente permite registrar una lista de las URLs de las imágenes asociadas al ID del jugador, para evitar tener que requerirlas más de una vez a la red social a la que pertenecen. ● Partida actual: en caso de que ocurra un fallo en la aplicación cuando
el jugador se encuentra en mitad de una partida, el cliente permite guardar los datos de la partida actual, para poder recuperarlos al volver a abrir el juego y no perder los progresos del turno del jugador.
4.3.4.3 Sincronización de partidas
mayor orden en la cantidad y la frecuencia de estas actualizaciones, el cliente brinda operaciones que permiten mantener una copia local de las partidas del jugador, y una sincronización óptima de estas con la información alojada en el servidor.
Cada un cierto período de tiempo, el cliente pedirá al servidor la lista de partidas asociadas al jugador, contrastará los datos recibidos con los almacenados localmente, actualizará los datos necesarios en ambas partes y registrará si hubo cambios o no en la copia local, para que el juego pueda actualizarlos en el momento que le sea conveniente.
En caso de ser necesario, también el cliente también posee funciones para sincronizar una partida en particular, o forzar la sincronización completa de todas las partidas, en caso de que el juego lo requiera y no pueda esperar el tiempo restante hasta la siguiente actualización.
4.3.4.4 Tipos de datos
Con la finalidad de proveer una mayor información al desarrollador sobre los datos recibidos desde el servidor, se tienen dos clases que el cliente utiliza para intercambiar la información con la aplicación: Game y Friend. Estas clases engloban el conjunto posible de datos enviados y recibidos sobre cada partida y cada jugador respectivamente, de forma que el desarrollador pueda conocer la estructura de éstos y, al mismo tiempo, esté acotado por la misma, aumentando la robustez de la aplicación y previniendo posibles errores en la misma.
Game: Esta clase contiene la siguiente información almacenada sobre cada partida:
-ID: Identificador único de la partida en el sistema.
-Estado: Especifica el estado de la partida, el cual puede ser “Comenzando”, “Pendiente”, “Jugando”, “Terminada” o “Rechazada”.
-Esperando Oponentes: indica si la partida está abierta o no a la incorporación de más jugadores.
-Jugadores: Lista de los identificadores de los jugadores correspondientes a la partida.
-Data: Información específica del juego asociada a la partida.
-Última actualización: fecha de la última actualización realizada a la partida. -Serial: Número incremental utilizado para control de actualizaciones.
-Vistos: Lista de jugadores que vieron la partida una vez terminada. Utilizado para borrado de partidas finalizadas.
-Resultados: Resultados de la partida una vez finalizada.
-Recompensas: Especifica los cambios a realizar en los jugadores en caso de ganar o perder una partida.
Friend: Clase que engloba las propiedades inherentes a cada jugador.
-ID: Identificador de cada jugador dentro del sistema. -Nombre: Nombre a mostrar del jugador.
-ID de Facebook: identificador de la cuenta de Facebook asociada al jugador, en caso de tener una.
-ID de Google: identificador de la cuenta de Google asociada al jugador, en caso de tener una.
-ID de Twitter: identificador de la cuenta de Twitter asociada al jugador, en caso de tener una.
-Última actualización: Última vez que se realizaron cambios en la información del jugador.
-Partidas: Listado de las partidas en las que el jugador está involucrado. -Amigos: Listado de los amigos del jugador.
-Data: Información extra del jugador que es específica del juego. -Nivel: Número que indica el grado de experiencia del jugador.
4.3.5 MatchMaking
Para lograr una buena experiencia de juego, es necesario que los jugadores elegidos para una partida aleatoria tengan ciertas características comunes que hagan al juego más equilibrado. La principal medida a tomar por el sistema a la hora de obtener una partida para un jugador es el nivel del mismo en el juego. Se declara cierto umbral de niveles alrededor del nivel del jugador que desea comenzar una partida, y se le asigna una partida que esté dentro de ese umbral. El permitir que la partida no sea exactamente del mismo nivel que el usuario ayuda a encontrar más rápido la partida en caso de poco tráfico de jugadores, y a la vez permite al usuario tener partidas más variadas, en momentos más fáciles, en otros más difíciles.
Los tiempos largos de espera para iniciar una partida provocan que el jugador pierda el entusiasmo en el juego y eventualmente termine dejándolo de lado. Esta herramienta aprovecha las características de los juegos por turnos para minimizar el tiempo de espera desde que un jugador inicia una partida aleatoria hasta que puede comenzar a jugar. Ya que, al ser juegos por turnos, no se necesita del oponente mientras el jugador realiza su jugada, el sistema de matchmaking opera de la siguiente manera: Cuando el jugador inicia una partida, se chequea si existe alguna partida que esté esperando por un oponente dentro del umbral de nivel del jugador. Si se encuentra alguna, se agrega al jugador a la misma y se notifica al jugador para que proceda con el segundo turno de ésta.
Figura 4.8: Flujo básico de matchmaking
oponente para ésta. De esta forma, el tiempo de espera para comenzar a jugar en ambos casos es mínimo.
4.3.6 Sistema eliminación de partidas antiguas
Conforme el juego comienza a volverse popular y la cantidad de jugadores aumenta, la cantidad de partidas creadas y almacenadas por el sistema crece exponencialmente, y en casos extremos, mantener guardadas en el sistema partidas antiguas y terminadas puede decrementar la performance del sistema en general.
Por este motivo, es una buena práctica eliminar del sistema toda la información que sea antigua y haya perdido utilidad. Para ésto, esta herramienta posee un sistema de “vistos” sobre las partidas. Cuando un jugador no requiere más la información sobre una partida específica, sólo tiene que indicarle al sistema que esa partida se encuentra vista para él. De esta manera, el sistema lleva un listado de los jugadores implicados en la partida que ya la marcaron como vista.
Cuando se necesita realizar una limpieza sobre las partidas, el servidor solo debe buscar las partidas cuya cantidad de vistos sea igual a su cantidad de jugadores, es decir, que todos los jugadores involucrados en la misma la marcaron como dispensable.
Al mismo tiempo, teniendo también la fecha de la última modificación de cada partida, se puede acotar o ampliar la búsqueda basándose en el tiempo desde la última actualización, así logrando purgar los datos almacenados de la mejor manera y logrando una mejor performance.
4.3.7 Información temporal de partidas
En cualquier caso, hacer una actualización del juego no es una buena opción, ya que puede ser tedioso para los usuarios y al mismo tiempo no se garantiza que todos ellos realizan la actualización.
El sistema provee funcionalidad para el manejo de este tipo de datos, por medio de un campo especial enviado junto con los datos de la partida, que almacena los parámetros actuales utilizados por el servidor. De esta manera, cada response enviado por el servidor tendrá datos actualizados sobre estas variables globales del juego, y en caso de ser necesario un cambio en éstos, solo es necesario modificar el servidor para que los cambios alcancen al 100% de los usuarios.
Capítulo 5: Experiencia de uso del sistema
5.1 Descripción del juego desarrollado
El juego descrito en este capítulo se encuentra en desarrollo, cercano a su publicación por la empresa cliente. “Juego de Palabras” es un juego de tipo crucigrama, con reglas modificadas y adaptado a una dinámica de juego multijugador.
El juego consiste en una grilla rectangular con casilleros y espacios vacíos. Cada casillero puede estar en blanco, o poseer una letra escrita. Las filas y columnas del tablero forman distintas palabras entrecruzadas. En la figura 5.1 se muestra un ejemplo del tablero.
Figura 5.1: Tablero
El objetivo del juego es completar los casilleros en blanco con las letras faltantes para terminar de formar todas las palabras.
Figura 5.2: Selección de casilla Figura 5.3: Ubicación de letra
En las figuras 5.2 a 5.4 puede verse la secuencia de ubicación de una letra en el tablero, donde en la primer imagen se selecciona el casillero a rellenar, en la segunda se escribe la letra en todas las coincidencias sobre el tablero, y en la tercera se muestra la letra ya colocada y otro conjunto de casillas seleccionado para ubicar la siguiente.
Figura 5.4: Letra colocada
Éste juego fue adaptado para adoptar un estilo de juego de tipo multijugador por turnos, mediante la agregación de un conjunto de reglas y mecánicas:
● En cada partida juegan exactamente 2 jugadores.
● El modo de juego es competitivo y cooperativo a la vez. Los jugadores compiten entre sí pero comparten el tablero y el progreso sobre el mismo.
● Cada jugador dispone de un tiempo limitado para realizar su turno, pasado ese tiempo perderá su turno y el otro jugador deberá jugar. ● Por turno, cada jugador puede colocar hasta un máximo de 3 letras en
el tablero. En caso de que estén correctamente colocadas, el jugador sumará puntos por ellas y éstas quedarán fijas en el tablero. De ser erróneas, no se contabilizarán puntos por ellas y serán removidas del tablero.
● Al finalizar el tablero, gana el jugador que más puntos haya conseguido a lo largo de la partida.
Figura 5.5: Turno en progreso Figura 5.6: Turno del oponente
En la figura 5.5 se puede apreciar la ejecución del turno de un jugador en una partida ya avanzada. En la figura siguiente, se ve la pantalla de información de la partida luego de finalizado el turno, con los puntajes actualizados.
Figura 5.7: Desafío
El segundo caso especial, es el escenario en el que el jugador que completa el tablero no es el ganador de la partida por el puntaje acumulado. En este caso, el jugador que completó el tablero puede optar por desafiar al ganador a un juego de ahorcado por parte de la recompensa de la partida. La figura 5.7 muestra la ejecución de una jugada en el desafío del ahorcado.
5.2 Estructuras de datos específicas
5.2.1 Datos específicos del jugador
En este caso hubo un solo elemento que era necesario modelar dentro del jugador, que no estaba contemplado por los datos comunes implementados en el sistema: Para poder obtener power-ups durante la partida, el jugador deberá consumir monedas que va adquiriendo conforme gana partidas. Alojando esta información en el campo data del modelo de datos del jugador, se logra mantener toda la información dentro del esquema básico planteado para el mismo y se evita la necesidad de crear campos extra en sus documentos y agregar lógica en el servidor para eso.
5.2.2 Datos específicos de la partida
La partida posee mucha información particular que debe ser almacenada. Los campos a agregar necesarios para el funcionamiento de la partida son:
● Puntajes: se debe poder saber en cada momento cual es la puntuación actual y guardarse para ser utilizada por el otro jugador.
● Idioma: Más allá del idioma en el que está el juego o el dispositivo que lo corre, cada partida individual puede ser comenzada en un idioma distinto, por lo que es necesario controlarlo en cada partida.
● Tablero: Guardando el tablero completo dentro de la información de la partida, permite hacerla independiente a cualquier cambio en el almacenamiento de los tableros, y mejora la robustez del juego, haciendo que cada partida tenga autocontenida toda la información necesaria para su finalización.
● Letras fijas: Letras que al inicio de la partida ya están posicionadas, y ayudan a la dinámica de la partida en sus turnos iniciales.
● Letras colocadas: Lista individual de las letras que colocó cada jugador hasta el momento. Sirven para mostrar el estado intermedio de la partida.
● Estado de desafío: Código que permite identificar si en la partida actual el desafío no ha comenzado, está comenzando, fue aceptado, rechazado, ganado o perdido.
Todos estos datos son serializados y transformados en un string que es guardado en el campo data de la partida, haciendo innecesario agregar campos adicionales al modelo básico del servidor.
5.3 Generación de tableros
La calidad y variedad de los tableros utilizados en el juego conforman una de las piezas más importantes para el éxito de éste. Se debe asegurar que la cantidad de tableros existentes sea tal que la probabilidad de que un jugador juegue dos veces el mismo tablero en un período de tiempo corto sea ínfima.
Contener los tableros dentro del código de la aplicación conlleva varios perjuicios. En primer lugar, ocasiona un aumento considerable del tamaño de la aplicación, con la suficiente cantidad de tableros se podría duplicar o hasta triplicar el tamaño de la aplicación en el dispositivo. En segundo lugar, no es posible determinar de antemano en qué idiomas jugará un usuario, por lo que se deberían incluir tableros en todos los idiomas disponibles para jugar, generando un desperdicio de almacenamiento para mantener tableros de idiomas que posiblemente nunca se utilicen.
Por último, mantener los tableros dentro de la aplicación conlleva a requerir de una actualización de la misma cada vez que se quieran incorporar nuevos tableros o modificar los existentes. Las posibilidades de generar tableros especiales para cierto evento, o el recambio de tableros por otros generados a partir de un conjunto de palabras diferente se minimizarían por el costo asociado a realizar actualizaciones en la aplicación.
Figura 5.8: Entidad Board
Cuando una partida nueva es creada, se solicita a la base de datos un documento de la colección Boards cuyo idioma coincida con el idioma de la partida. Este tablero pasa a formar parte de los datos de la partida, por lo que automáticamente queda independizado de cualquier cambio en la base de datos.
5.4 Extensión de funcionalidad del servidor
En conjunto con el manejo de los tableros, se introdujeron otros cambios en el servidor que ayudan a la correcta ejecución del juego.
Dentro del modelo base del servidor se encuentran métodos para inicializar los campos “data” y “rewards” a la hora de crear nuevos documentos para las colecciones Games y Players. Estos métodos retornan Strings vacíos por defecto, y están pensados para ser sobrescritos al heredar de éste. Siguiendo este esquema, se sobrescribieron dichos métodos para que coincidieran con las estructuras anteriormente en el capítulo 5.2.