Documentación Final Tikitaka

Anuncio
DOCUMENTACIÓN FINAL
TIKITAKA
Jesús Ladevesa Medina
jesus.ladevesa@estudiants.urv.cat
Miguel Ángel Linares Herrero
miguelangel.linares@estudiants.urv.cat
Àngel Moreno Prats
amoreno@tinet.org
Javier Sánchez Alonso
javier.sanchez@estudiants.urv.cat
2
ÍNDICE
Parte I: El proyecto Tikitaka 5
1 Introducción 5
2 Especificación del estándar 5
3 Temporización 6
Parte II: Descripción técnica del proyecto Tikitaka 8
4 Tecnología utilizada 8
5 Implementación 9
5.1 Módulo de Control 9
5.1.1 Introducción 9
5.1.2 Diseño 9
5.1.2.1 Connecta 11
5.1.2.2 Inici 11
5.1.2.3 Joc 11
5.1.2.4 Gol-Ack 11
5.1.2.5 Falta 12
5.1.2.6 Fipart 12
5.1.2.7 Fipartit 12
5.2 Módulo de Comunicaciones 13
5.2.1 Introducción 13
5.3.2 Diseño 13
5.2.3 Implementación 15
5.2.3.1 Núcleo 16
5.2.3.2 Servidores 17
5.2.3.3 Gestores 18
5.2.3.4 Factorías 20
5.2.3.5 Reloj 21
5.2.3.6 Auxiliares 21
5.2.4 Modificaciones sobre el protocolo 23
5.3 Módulo de Inteligencia Artificial 23
5.3.1 Introducción 23
5.3.2 Diseño 23
5.3.2.1 Comportamiento de los agentes 24
5.3.2.2 Algoritmo de encaminamiento 25
5.3.3 Implementación 26
5.4 Módulo de Gráficos 27
5.4.1 Introducción 27
5.4.2 Diseño 28
5.4.2.1 Diseño de objetos 28
5.4.2.2 Diseño de la programación 3D 28
5.4.3 Implementación 29
6 Resultados 30
6.1.1 Módulo de Comunicaciones 30
Anexos 32
A Manual de usuario 32
A.1 Instalación 32
A.2 Uso 32
A.2.1 Servidor 32
A.2.2 Cliente 32
A.2.2.1 Inicio 32
3
A.2.2.2 Unirse a partida 33
A.2.2.3 Iniciar el juego 33
A.2.2.4 Durante el partido 34
A.2.2.5 Xiulet 35
A.2.2.6 Selección de Cámara 35
A.2.2.7 Cronómetro 35
A.2.2.8 Fin del partido 35
B Referencias 35
C Oficina Técnica 36
C.1 Sesión 2 de Febrero 36
C.2 Sesión 8 de Febrero 36
C.3 Sesión 9 de Febrero 37
C.4 Sesión 15 de Febrero 39
C.5 Sesión 16 de Febrero 43
C.6 Fe de erratas 22 de Marzo 43
C.7 Aclaraciones 12 de Abril 43
C.8 Actualización especificaciones 20 de Abril 44
D Protocolo Simulador FIRA Middle League SimuroSot 44
4
Parte I: El proyecto Tikitaka
1 Introducción
El objetivo de este proyecto es el de crear un simulador de la liga intermedia de fútbol
robótico basado en la FIRA middle league. El proceso de desarrollo se ha llevado a
cabo por varios grupos dando diferentes soluciones a un mismo problema, que debían
ser compatibles. Para ello se hicieron varias reuniones con el usuario final para decidir
que características debía tener este software.
Durante estas semanas se decidió que el sistema a realizar seria desarrollado en
dos partes, un servidor que simularía el comportamiento del campo y un software
cliente que simularía un equipo de la competición y dejaría visualizar al usuario lo que
ocurre e interactuar con el sistema. Una vez decidido esto se mostraba un nuevo
punto a tener en cuenta, las comunicaciones entre los distintos resultados.
Después de semanas de negociación se pactan unas modificaciones en las reglas
de juego originales y se especifican las partes comunes a todos los desarrollos. Una
vez concluida esta parte cada grupo puede empezar de manera libre el desarrollo
utilizando las tecnologías que crea convenientes, y marcándose sus propias metas,
siempre teniendo en cuenta la fecha límite en la cual se realizará la demostración del
producto frente al resto de grupos y se hará una competición entre ellos.
En nuestro caso como verán se ha realizado un trabajo de investigación dando con
una solución que responde a todas las especificaciones necesarias de forma más que
satisfactoria.
También remarcar la tarea de las personas involucradas en el desarrollo, ya que se
ha destinado un especialista para cada campo que resolver.
2 Especificación del estándar
En este apartado usted podrá ver como está estructurada la aplicación y una visión
global de su funcionamiento. Para ello explicaremos como se divide y después como
se realiza cada parte.
El diseño de la arquitectura de la
aplicación sigue el patrón del diseño
modular, creando así cuatro componentes
que proporcionan a la aplicación las
funcionalidades de control del flujo de
ejecución (Módulo de Control), control de
la comunicación entre cliente y servidor
(Módulo
de
Comunicaciones),
la
planificación de los movimientos de los
robots del equipo propio (Módulo de
Inteligencia Artificial) y finalmente la
representación gráfica de la simulación
del partido al usuario (Módulo de
Gráficos).
En la siguiente figura podemos
observar
gráficamente
como
están
organizados los módulos.
Por una parte tenemos la aplicación
servidor, donde entran en juego los
módulos de control y comunicaciones. El
módulo de control se encargará de
mantener el flujo del ejecución del
5
programa así como de gestionar los eventos generados por los jugadores y por otra se
encargará de la simulación física de la partida, aplicando las leyes que correspondan
sobre los participantes del juego y sus movimientos para conseguir un
comportamiento lo más parecido a la realidad posible. El módulo de comunicaciones
se encargará de mantener los canales de comunicación con los jugadores,
interactuando con el módulo de control para informarle de los eventos generados por
los jugadores (arbitraje del partido).
Por otra parte tenemos la aplicación cliente, donde entran en juego todos los
módulos. El módulo de control se encargará igualmente de mantener el flujo de
ejecución de la aplicación, así como de coordinar al resto de módulos para conseguir
un comportamiento correcto. El módulo de comunicaciones se encargará – de la
misma manera que hace en la parte cliente – de mantener los canales de
comunicación con el servidor, y interactuando con el módulo de control informándole
de los cambios producidos en la comunicación con el servidor. El módulo de
inteligencia artificial interactuará con el módulo de control durante el transcurso de
una partida para ordenar los movimientos óptimos a los robots del equipo que
representa. Finalmente el módulo de gráficos interactuará con el módulo de control
para representar gráficamente el transcurso de la partida así como dar la interfaz al
usuario para que éste pueda producir los eventos de arbitraje que corresponda.
En el anexo se puede consultar el resultado de las sesiones de la oficina técnica en
las que se especifico el comportamiento que deberian seguir todos los proyectos
desarrollados de éste simulador.
3 Temporización
La temporización real de nuestro proyecto se puede dividir en las siguientes partes:
Inicio (de 08/02/07 a 09/02/07). Durante estos días se decide el grupo de
desarrollo y se asignan las tareas que realizará cada uno. En nuestro grupo la
asignación queda como sigue:
- Miguel Ángel Linares Herreros: Encargado de Gráficos y Jefe de proyecto
- Àngel Moreno Prats: Comunicaciones
- Jesús Ladevesa Medina: Inteligencia artificial
- Javier Sánchez Alonso: Control
Análisis entre grupos (de 15/02/07 a 23/02/07). Durante este período se llevan
a cabo las negociaciones con el resto de grupos y el usuario final dando como
resultado unas especificaciones comunes.
Análisis individual (de 01/03/07 a 08/03/07). Este tiempo lo dedicamos a
aprender como solucionaremos el problema propuesto. Preparamos la presentación
que haremos al usuario con las herramientas que utilizaremos.
Presentación (de 08/03/07 a 09/03/07). Estos dos días los dedicamos a hacer
las presentaciones al usuario final. Se enseñan las tecnologías que utilizaremos y el
funcionamiento general.
6
Aprendizaje (de 12/03/07 a 16/03/07). Esta semana se dedica a documentarnos
con detenimiento sobre las herramientas que utilizaremos para más tarde poner en
práctica los conocimientos adquiridos haciendo el desarrollo más rápido.
Implementación (de 19/03/07 a 11/05/07). Este es el proceso que nos lleva más
tiempo. Después de decidir las herramientas a utilizar y analizar nuestras necesidades
nos dedicamos íntegramente al desarrollo de nuestra aplicación. Cada parte se trabaja
por separado y nos dedicamos únicamente y exclusivamente a la parte asignada.
Durante el proceso nos encontramos con varios problemas como la obligación de
tener que reimplementar una parte de las comunicaciones por falta de especificación
en el análisis. Como hay partes del proyecto que avanzan más rápidamente que otras,
también se redirigen los recursos, empleando más tiempo y personas a partes que
quedan atrasadas.
Integración (de 14/05/07 a 25/05/07). Esta parte consistió en empezar a unir las
diferentes partes y solucionar todos los problemas que aparecen en ellas.
Incompatibilidades, sincronización, etc. Todos estos problemas son resueltos poco a
poco. Se realizan pruebas por partes y se solucionan todos los problemas antes de
empezar con la siguiente. Finalmente después de mucho esfuerzo se pasa a la parte
de pruebas.
Pruebas (de 28/05/07 a 08/06/07). Se realizan pruebas de todo el conjunto. Se
corrigen pequeños errores y se siguen desarrollando partes todavía en proceso de
desarrollo y comprobación.
Documentación y empaquetado (de 11/06/07 a 12/06/07). Finalmente nos
dedicamos a documentar todo el trabajo realizado y a empaquetar el producto. De
esta manera se realiza todo lo necesario para crear un producto completo. Manuales
de usuario, instalador, documentación de módulos, etc.
7
Parte II: Descripción técnica del proyecto Tikitaka
4 Tecnología utilizada
Para el desarrollo de éste proyecto se ha utilizado el lenguaje C++, un lenguaje de
programación de propósito general, de alto nivel con funcionalidades de bajo nivel y
que proporciona la programación procedimental, abstracción de datos, programación
orientada a objetos entre otras características.
En los siguientes parágrafos se presentaran el resto de componentes y
herramientas utilizadas para el desarrollo de éste proyecto.
Microsoft Visual C++, también conocido como MSVC, es un entorno de desarrollo
(IDE) que proporciona Microsoft para los lenguajes de programación C, C++ y
C++/CLI. Incluye herramientas para desarrollar y depurar código C++, especialmente
para los que utilizan el Microsoft Windows API, el API de DirectX o el entorno de
ejecución basado en Microsoft .NET. Tiene como características el resaltado de
sintaxis, el auto completado de código mediante el componente IntelliSense y una
avanzada funcionalidad de depuración. Proporciona también funcionalidades como sus
sistemas automáticos de compilación y generación, precompilación de ficheros de
encabezado, reconstrucción minimalista o el vinculado incremental que permiten
acortar sustancialmente el tiempo de compilación y vinculación de una aplicación,
especialmente en proyectos de software extensos.
POCO, acrónimo de C++ Portable Components, es una colección de clases C++ de
código abierto que simplifican y aceleran el desarrollo de aplicaciones orientadas a la
comunicación. Ésta biblioteca de funciones se integra perfectamente con la C++
Standard Library además de cubrir muchos de los aspectos que ésta deja sin cubrir. Su
diseño modular y su eficiente implementación hacen de ésta biblioteca muy adecuada
para entornos incrustados, un área donde el lenguaje de programación C++ está
incrementando su popularidad, debido a su flexibilidad en adaptarse tanto en
programación a bajo nivel (dispositivos de E/S, gestores de interrupciones, etc.) así
como a alto nivel, en una programación orientada a objetos. Ésta biblioteca libera a
los desarrolladores de reinventar la rueda, y permite invertir el tiempo en áreas más
productivas del desarrollo como puede ser en la fase de diseño. Como características
destacables y que usaremos en éste proyecto se pueden nombrar:
- Proporciona las herramientas para la programación de un entorno multihilo (threads, sincronización entre threads, etc.)
- Acceso a sistema de ficheros y a flujos de información (streams).
- Permite la creación de librerías compartidas y la carga dinámica de clases.
- Proporciona un potente entorno de registro (logging y accounting).
- Facilita la programación en red (sockets TCP/IP, HTTP, FTP, SMTP, etc.)
- Proporciona un entorno de ficheros de configuración para las aplicaciones.
Además ésta biblioteca se puede usar en una gran variedad de plataformas,
incluyendo: Windows ©, Mac OS X, Linux, HP-UX, Tru64, Solaris y QNX.
OGRE, acrónimo de Object-Oriented Graphics Rendering Engine, es un motor de
renderización 3D flexible y orientado a la escena, desarrollado en C++, diseñado para
hacer más fácil y más intuitivo para los desarrolladores producir aplicaciones usando
hardware de aceleración 3D. La biblioteca de funciones abstrae todos los detalles del
uso de los sistemas de representación Direct3D y OpenGL y proporciona una interfaz
basada en objetos mundo y otras clases muy intuitivas. Éste motor es de software
libre, licenciado bajo la licencia LGPL y es el resultado de una comunidad muy activa
que lo mantiene actualizado. Como características destacables podemos nombrar:
- Tiene un diseño orientado a objetos, con una potente arquitectura de
plugins que permite añadir funcionalidades fácilmente.
- Es multiplataforma, con soporte para con Direct3D y OpenGL.
8
CEGUI, acrónimo de Crazy Eddie’s GUI, es una biblioteca de funciones para crear
interfaces de usuario en C++. Está diseñada particularmente para cubrir las
necesidades de los videojuegos, aunque es perfectamente utilizable para otras tareas,
así mismo está diseñada para proporcionar una gran flexibilidad en la apariencia (lookand-feel) de la aplicación así como que sea muy adaptable a las herramientas y
sistemas operativos escogidos por el desarrollador.
GIMP, acrónimo de GNU Image Manipulation Program, es un programa de
tratamiento de imágenes libre. Es ideal para tareas como retocar fotografías, crear
imágenes para la web, etc. Se distribuye bajo una licencia libre, lo que permite usarlo,
distribuirlo o incluso adaptarlo a las necesidades de cada uno.
3D Studio Max es una aplicación basada en el entorno Windows (9x/NT) que
permite crear tanto modelados como animaciones en tres dimensiones (3D) a partir
de una serie de vistas o visores (planta y alzados).
5 Implementación
En los siguientes apartados se entrará en detalle en cada uno de los módulos,
introduciendo en primer lugar sus objetivos, describiendo las decisiones y
comportamientos del módulo definidos en la fase de diseño y las características
referentes a la implementación del módulo.
5.1 Módulo de Control
5.1.1 Introducción
El objetivo principal del módulo de control, es el de gestionar el hilo de ejecución de la
aplicación poniendo todos los medios disponibles para que los diferentes módulos
puedan ejecutarse cuando es debido y actúen de forma diferente según el estado en
el que se encuentren.
De esta forma el módulo de control se ejecutará siguiendo un diagrama de estados
previamente definido y que se detallará en la parte de diseño.
A cada estado de la aplicación el control podrá hacer una de las siguientes
acciones:
- Iniciar, detener y reanudar cada uno de los módulos que integran la
aplicación.
- Actualizar las clases compartidas por los diferentes módulos. De las cuales
dichos módulos únicamente podrán consultar su contenido.
- Ejecutar la parte de simulación física siempre y cuando nos encontremos en
el estado adecuado.
- Actualizar el estado en el que se encuentra la aplicación y hacérselo saber a
todos los demás módulos.
5.1.2 Diseño
El módulo de control estará alojado tanto en el servidor como en la parte cliente. De
este modo dependiendo del rol que tenga cuando se le invoque se ejecutará un thread
u otro.
void ControlCore::run() {
if (mRole == TikitakaRoles::SERVER_ROLE) {
runServerControlCore();
} else {
runClientControlCore();
}
}
9
Ambos threads se ejecutarán cíclicamente respondiendo a las notificaciones que les
van llegando a una cola de notificaciones. Estas notificaciones las puede recibir del
módulo de comunicaciones o de sí mismo que encola una notificación para continuar
realizando tareas después de haber acabado una.
Las notificaciones responden a unos estados que están predefinidos, donde en cada
uno de ellos se realizarán una serie de operaciones. El conjunto de estos estados
representará el diagrama de estados de la aplicación global.
for (;;) {
Notificacion = DesencolarNotificacion();
Switch (Notificacion) {
case ESTADO 1
case ESTADO 2
.
.
.
case ESTADO n
}
A continuación detallaremos el diagrama de estados de la parte servidor. Donde
recibirá notificaciones del módulo de comunicaciones y donde se ejecuta la simulación
física. Los estados de la parte cliente son prácticamente los mismos.
Conect
a
Inici
FipartitAck
JOC
FipartAck
Xiulet
FaltaAck
IniciJoc
GolAck
Como hemos comentado el módulo de control es el encargado de crear este
diagrama de estados y actualizarlo dependiendo de los eventos que se vayan
produciendo en el juego. A continuación detallaremos las acciones que se realizan en
cada estado:
10
5.1.2.1 Connecta
Este es el primer estado en el que se encuentra la aplicación. En este estado el
módulo de control ya ha creado los threads correspondientes para cada uno de los
otro módulos (Comunicación, IA, y Gráficos), para que estos se inicialicen.
En este estado el control espera que los dos clientes se conecten. Cuando se
conecta un cliente se le asigna un identificador de forma aleatoria, se guarda la
información de este cliente en la clase Player (Ip, puerto Identificador, goles etc..), y
también se actualiza la clase GameData (clase que utilizan todos los módulos de la
aplicación para obtener datos relativos al juego) con el numero de conexiones
servidas.
En este mismo estado se ejecuta la función SimCalcularPosicionsInicials que
inicializa los parámetros de la física y establece los componentes geométricos que van
a ser simulados.
La última acción que se desempeña en este estado es actualizar la clase GameData
para que se pase al estado INICI, de esta forma todos los otros módulos podrán saber
que hemos cambiado de estado consultando el valor de dicha clase.
5.1.2.2 Inici
En el estado inici, el módulo de control resta a la espera de que los dos clientes inicien
el juego. Cuando hemos recibido el inicio de los dos clientes iniciaremos el timer que
controlará el tiempo de juego, y pasaremos al estado JOC.
5.1.2.3 Joc
En este estado el módulo de control recibirá a través de la clase GameData las
velocidades angular y lineal de cada uno de los objetos de la simulación a través de
los mensajes UDP que gestionará el módulo de comunicaciones.
En este caso ejecutaremos la función SimJOC. Esta función se encargará de realizar
las siguientes acciones:
1. Obtener los parámetros de cada objeto a través de la clase GameData
(velocidad lineal y angular).
2. Actualizar los cuerpos que se han creado con el simulador gráfico ODE con
estos nuevos parámetros.
3. Generar un paso en la simulación parametrizando el tiempo de esta.
4. Obtener las nuevas posiciones de los objetos de la simulación resultadas de
añadir nuevas velocidades y simular.
5. Actualizar la clase GameData con las nuevas posiciones para que tanto el
módulo de IA como el módulo gráfico puedan consultarlas y actualizar sus
clases.
En este estado no pasaremos de estado, a no ser que desde el módulo gráfico se
genere un evento que nos diga que se ha producido una de las siguientes opciones:
1. Gol
2. Falta
3. Fin de la primera parte
4. Fin del partido
5.1.2.4 Gol-Ack
A este estado se pasa cuando el usuario ha seleccionado la opción GOL en la interfaz
gráfica.
En este estado el módulo de control se encargará de realizar las siguientes
operaciones:
11
1.
2.
3.
4.
5.
Parar el timer del juego.
Calcular que equipo ha hecho el gol a partir de la posición de la pelota.
Actualizar la clase GameData sumando al equipo el gol anotado.
Actualizar la clase GameData con las posiciones de saque de centro.
Ejecutar la función SimRecalcularPosicions para actualizar las nuevas
posiciones de los objetos físicos que integran la simulación.
5.1.2.5 Falta
A este estado se pasa cuando el usuario ha seleccionado una de las siguientes
opciones en la interfaz gráfica:
1. Freball
2. Freekick
3. Penalty
En este estado el módulo de control recibe como parámetros el tipo de falta que se
ha seleccionado y al equipo al que se le ha señalado.
A partir de estos parámetros se realizan las siguientes operaciones:
1. En el caso de que se hay seleccionado un penalty o un freekick:
a. Dependiendo la parte en que nos encontremos y de quien haya
cometido el penalty, actualizaremos el GameData con las posiciones
POS_PENALTY_RIGHT o POS_PENALTY_LEFT.
2. En el caso de que se hay seleccionado un freeball:
a. Si el freeball se ha seleccionado a un equipo en concreto, el freeball se
lanzará en el campo del agresor y dependiendo de la la posición de la
pelota calcularemos en que parte del campo del agresor se tendrá que
ejecutar éste. De esta forma actualizaremos el GameData con las
posiciones
POS_FBALL_LEFT_UP,
POS_FBALL_LEFT_DOWN,
POS_FBALL_RIGHT_UP, POS_FBALL_LEFT_DOWN.
b. Si el freeball no se ha seleccionado a ningun equipo, dependiendo
unicamente de la posición de la pelota actualizaremos el GameData
con
las
posiciones
POS_FBALL_LEFT_UP,
POS_FBALL_LEFT_DOWN,
POS_FBALL_RIGHT_UP, POS_FBALL_LEFT_DOWN.
Una vez actualizado el GameData con las nuevas posiciones, ejecutaremos la
función SimRecalcularPosicions para actualizar las nuevas posiciones de los objetos
físicos que integran la simulación.
5.1.2.6 Fipart
A este estado se pasa cuando el usuario ha seleccionado la opción FI PART en la
interfaz gráfica.
En este estado el módulo de control se encargará de realizar las siguientes
operaciones:
1. Parar el timer del juego.
2. Actualizar en el GameData la parte del juego.
3. Actualizar la clase GameData con las posiciones de saque de centro.
4. Ejecutar la función SimRecalcularPosicions para actualizar las nuevas
posiciones de los objetos físicos que integran la simulación.
5.1.2.7 Fipartit
A este estado se pasa cuando el usuario ha seleccionado la opción FI PARTIT en la
interfaz gráfica.
En este estado el módulo de control se encargará de realizar las siguientes
operaciones:
12
1.
2.
3.
4.
5.
6.
Parar el timer del juego.
Inicializar todos los parámetros del GameData .
Enviar un Fipartit ack a los dos jugadores.
Liberamos la memoria de los objetos del ODE creados en la simulación.
Cerramos los dos canales de comunicación de los jugadores.
Pasar al estado de esperar conexiones, para poder empezar otra partida.
5.2 Módulo de Comunicaciones
5.2.1 Introducción
El objetivo principal del módulo de comunicaciones dentro del diseño global de
nuestra aplicación es proporcionar el medio por el cual dos jugadores puedan
interactuar entre ellos para llevar a cabo, mediante el envío de una serie de órdenes y
la recepción de una serie de resultados, una simulación de un partido de la FIRA
Middle League entre ambos.
Como se ha descrito con anterioridad, nuestra aplicación sigue un modelo de
comunicación cliente-servidor, donde el cliente corresponde a la aplicación gráfica
encargada de representar el resultado de la simulación del partido de forma amigable
para el usuario además de ejecutar cierta lógica para ordenar los movimientos de los
robots del equipo propio, y donde el servidor corresponde a la aplicación encargada de
gestionar las ordenes de los clientes y efectuar una simulación del partido mediante
las reglas de la física y en función de las órdenes enviadas por los jugadores.
Éste modelo implica la necesidad de definir un lenguaje común que todas las partes
conozcan, y que permita el intercambio de información necesaria durante el
transcurso de una partida de forma eficiente e independiente de la implementación o
plataforma donde corran los componentes cliente o servidor.
Durante las sesiones de la oficina técnica, en la que se definieron las
especificaciones generales de la aplicación, se definió también el protocolo de
comunicación que deberían implementar los simuladores para poder interactuar entre
ellos. Éste protocolo, cuya especificación podemos consultar en el anexo, está basado
en el intercambio de mensajes de texto que viajan en dos canales diferenciados en
función del objetivo de los mensajes, de control o de estado. Los mensajes de control
corresponden a aquellas acciones referentes a la gestión de la partida, como pueden
ser la unión a una partida y todas las órdenes que un árbitro puede ejecutar durante el
juego, y los mensajes de estado corresponden a la información referente a las órdenes
de movimiento de los robots y los resultados de la simulación física realista de la
partida una vez aplicados los movimientos de los robots.
La especificación del protocolo define con exactitud las características de los
canales de comunicación, así como el flujo de mensajes que se debería respetar
durante el transcurso de una partida, así como los formatos de los mensajes,
intentando así definir un estándar gracias al cual, cualquier implementación que lo
respetara seria capaz de llevar a cabo una partida con cualquier otra implementación
de cualquier otro grupo que también lo respetara.
Aún así, en el protocolo definido durante la oficina técnica hay una serie de
disfuncionalidades que de acuerdo con otros grupos se ha solucionado mediante la
corrección y ampliación del mismo tal como veremos posteriormente.
5.3.2 Diseño
Durante la fase de diseño de la aplicación, y por tanto del módulo de comunicaciones,
se definieron una serie de objetivos que debería seguir la implementación de dicho
módulo para garantizar un rendimiento óptimo.
13
Éstos objetivos vinieron marcados principalmente por la arquitectura que debería
seguir la aplicación, ya comentada en capítulos anteriores, así como por las
restricciones definidas en la especificación del protocolo de comunicación. Así pues
éstos objetivos son:
- Garantizar un alto nivel de concurrencia, dado el modelo multi-hilo en el
que se basa toda la arquitectura de nuestra aplicación se consiguen tiempos
de respuesta a los mensajes – en el caso del módulo de comunicaciones – así
como en el proceso de los mismos notablemente más rápido y eficiente que
en implementaciones basadas en un hilo de ejecución secuencial. Garantizar
el nivel de concurrencia óptimo y un eficiente proceso de los mensajes será
básico dada la frecuencia con la que los componentes servidor y cliente
deberán recibir, procesar y enviar mensajes, que especifica el protocolo que
debería de ser de 25 mensajes por segundo.
- Transparencia del módulo de comunicaciones, para el resto de módulos
de la aplicación, en el sentido el módulo de comunicaciones deberá
enmascarar todo el proceso de comunicación con los elementos remotos,
independientemente del rol – cliente o servidor – que asume la aplicación.
- Asincronismo con el módulo de control, intentando que toda interacción
de éste con el módulo de comunicaciones sean llamadas no bloqueantes en
la medida de lo posible – dado que siempre habrá un punto de sincronización
para respetar el flujo de mensajes definido en la especificación – y que toda
la lógica correspondiente a la recepción, proceso y envío de mensajes sea de
forma completamente independiente de la ejecución del módulo de control.
El diseño del módulo de comunicaciones está pues orientado para cumplir éstos
tres objetivos básicos además de garantizar la implementación del protocolo definido
en la oficina técnica.
Para cumplir los objetivos marcados así como la especificación del protocolo, se han
usado una serie de patrones estándar de programación que proporcionan una serie de
herramientas comunes usadas por todos los módulos de la aplicación:
- Bolsa de Hilos de ejecución (thread pools), patrón / herramienta que nos
permita crear un conjunto de hilos de ejecución que originalmente se
encuentran en un estado ocioso preparados para ejecutar tares de forma
paralela a medida que necesitemos de ellas. Éste patrón es muy eficiente
pues por una parte nos elimina la restricción de una ejecución secuencial y
por otra parte nos elimina la sobrecarga que nos acarrearía la creación de los
hilos a medida que se vayan necesitando.
- Factorías (factories), patrón que nos permitirá la implementación de una
serie de objetos capaces de crear otros objetos que desempeñaran una
determinada función. Éste patrón se usará para crear los gestores de las
conexiones de los jugadores, como veremos en el apartado de
implementación.
- Relojes (timers), patrón que nos permitirá la ejecución de una serie de
tareas de forma periódica, de tal forma que cada cierto número de
milisegundos se garantice que se desempeñe una función determinada.
Una vez definidos los objetivos a cumplir y los patrones de diseño o herramientas
disponibles, se está en disposición de describir el diseño interno del módulo. Éste se
ha concebido como un objeto que el módulo de control creará y destruirá en cada una
de les ejecuciones, que en función del rol que se deba asumir – cliente o servidor –
tendrá un comportamiento u otro.
A modo de resumen, si el módulo de comunicaciones asume el rol de cliente, éste
será el encargado de crear y gestionar la conexión – o el canal – de control contra el
servidor así como la de crear el reloj encargado de enviar periódicamente los
movimientos de los robots que ordene el módulo de inteligencia artificial y crear el
canal de estado por el que se recibirán los mensajes con el resultado de la simulación,
14
es decir, las posiciones de todos los robots así como de la pelota. Si el módulo de
comunicaciones asume el rol de servidor, éste será el encargado de crear y gestionar
los canales de control por los que los clientes enviaran las órdenes correspondientes a
la gestión de la partida así como crear el reloj encargado de enviar periódicamente el
estado de la partida a los jugadores y crear los canales de estado por los que recibir
los movimientos de los jugadores.
Así pues en ambos casos – cliente y servidor – se deberán crear un hilo servidor por
el que recibir los mensajes de estado, y un reloj encargado de enviar periódicamente
los resultados de los cálculos de la IA en el cliente o de la simulación física en el
servidor. Ambos componentes usaran de un canal de comunicación basado en el
protocolo de transporte UDP no orientado a la conexión, para garantizar así una
eficiencia óptima en el envío de mensajes aunque no se garantice la recepción ni el
orden. El protocolo especifica el uso de éste método para garantizar el envío de ésta
de información a un ratio muy elevado.
De la misma forma en ambos casos se deberá establecer un canal de comunicación
de control, pero con un comportamiento diferenciado en función del rol: si se asume el
rol de cliente el módulo será el encargado de gestionar una única conexión que
establecerá a petición del usuario contra el servidor correspondiente, y si se asume el
rol de servidor el módulo será el encargado de crear un hilo servidor por el que recibir
los mensajes de control de los jugadores así como crear un hilo para cada canal de
control que se establecerá posteriormente con cada uno de los jugadores y por el que
se notificaran los eventos del partido de forma bidireccional, tanto en eventos
generados desde el jugador y propagados al servidor como del servidor al jugador.
Ambos comportamientos usaran de un canal de comunicación basado en el protocolo
de transporte TCP orientado a la conexión, para garantizar así la recepción del
mensaje y el orden de recepción dado que éstas características son importantes tal y
como está definido en la especificación del protocolo.
Así pues, los componentes de ambos canales encargados de gestionar la recepción
y proceso de mensajes se implementaran mediante el patrón de bolsas de hilos de
ejecución y factorías de gestores de la conexión y los componentes de envío periódico
de información mediante relojes. Adicionalmente se implementaran una serie de
clases auxiliares que se encargaran de la creación de los diferentes mensajes
respetando el formato definido en la especificación del protocolo y de comprobar el
formato de los mensajes recibidos por cualquier de los canales.
5.2.3 Implementación
El proceso de plasmar en código los componentes definidos en la fase de diseño ha
dado como resultado una serie de clases que definen una serie de objetos con sus
funcionalidades especificas – con sus miembros y métodos correspondientes.
Los objetos resultantes los podemos organizar jerárquicamente en función de su
visibilidad para con los otros módulos, es decir, en función de quien usa sus
características. Así pues los podríamos organizar en los siguientes grupos:
- Núcleo: que corresponde al objeto CommCore, núcleo del módulo de
comunicaciones, será el objeto visible desde el módulo de control y que
creará los servidores multi-hilo, relojes y gestores y factorías en función del
rol que asume en el instante de su creación. También proporciona el API que
utilizará el módulo de control para generar mensajes a enviar a los extremos
remotos de los canales de control o estado.
- Servidores:
correspondientes
a
los
objetos
StateUDPServer
y
StateUDPServerDispatcher, encargados de implementar el servidor UDP
multi-hilo a imagen del objetos TCPServer ya disponible en la librería utilizada
en el proyecto.
15
-
-
-
-
Gestores: correspondientes a los objetos designados con los nombres de
ControlRequestHandler, ControlChannel y StateRequestHandler, encargados
de gestionar las peticiones de control al servidor en el canal TCP, de
gestionar el canal establecido con cada uno de los jugadores tanto en el
cliente como en el servidor y de gestionar las peticiones de estado el canal
UDP tanto en el cliente como en el servidor respectivamente.
Factorías: correspondientes a los objetos ControlRequestHandlerFactory y
StateRequestHandlerFactory, encargados de crear los objetos gestores del
punto anterior.
Reloj: correspondiente al objeto StateTimer, encargado de enviar
periódicamente los mensajes de movimiento de los robots en el caso de los
clientes o de los mensajes de estado de la partida en el caso del servidor.
Auxiliares: correspondientes a los objetos ControlRequest, ControlResponse,
StateRequest y StateResponse, encargados de generar mensajes y
proporcionar los métodos para validar el formato de un mensaje para los
correspondientes a las peticiones de control (conexión y interrupciones de
juego provocadas por el jugador), a las respuestas de control (confirmaciones
y interrupciones de juego propagadas desde el servidor), a las peticiones de
estado (movimientos generados por los jugadores) y las respuestas de
estado (posiciones resultantes de la simulación física) correspondientemente.
5.2.3.1 Núcleo
La parte principal del módulo de comunicaciones consiste en un objeto que enmascara
toda la arquitectura de hilos de ejecución al módulo de control, de tal forma que se le
presenta como una caja cerrada en la que se le ofrecen una serie de puntos de
entrada (API) con los que interactuar.
Así pues el módulo de control, como responsable de gestionar el resto de módulos,
se encarga de crear el módulo de comunicaciones cuando lo necesite, y en la creación
del objeto, éste despliega todas las herramientas necesarias en función del rol
asumido – cliente o servidor – desde la aplicación.
De igual forma se establece un mecanismo por el cual el módulo de comunicaciones
pueda interactuar con el módulo de control, señalándole mediante llamadas a los
puntos de entrada del módulo de control (su API) los diferentes eventos que se
puedan producir durante el transcurso de una partida. Éste mecanismo consiste en el
almacenamiento de una referencia al objeto ControlCore para llamar a sus funciones.
En definitiva, en la creación del objeto CommCore, se crea:
- El subconjunto de hilos encargados de gestionar el servidor UDP, mediante el
objeto StateUDPServer de desarrollo propio, al que se le proporciona el
objeto factoría correspondiente para el canal de estado.
- Si se asume el rol de servidor, el subconjunto de hilos encargados de
gestionar el servidor TCP, mediante el objeto TCPServer ya proporcionado por
la librería utilizada, al que se le proporciona el objeto factoría
correspondiente para el canal de comunicación.
- El reloj de envío periódico de mensajes mediante el objeto StateTimer.
Una vez creado el objeto, todos los subsistemas que contienen están en un estado
inicial parado, que el módulo de control puede cambiar a un estado arrancado
mediante el conjunto de funciones que exporta el objeto. Así mismo, el núcleo del
módulo de control también ofrece los métodos para gestionar el reloj encargado del
envío periódico de mensajes, la gestión de los canales de control (ControlChannel) y el
envío de mensajes a través de éstos.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto CommCore:
16
Método
CommCore
~CommCore
start
stop
startTimer
stopTimer
createControlChannel
getPtrControlChannel
getRefControlChannel
stopControlChannel
sendMessage
bcastEstatIni
bcastGolAck
bcastFaltaAck
bcastFiPartAck
bcastFiPartitAck
Descripción
Crea el objeto CommCore
Destruye el objeto CommCore
Arranca los servidores UDP (estado) en cualquiera de
los roles de la aplicación y TCP (control) si el rol con
el que se ha creado el CommCore es el rol de
servidor.
Para los servidores arrancados en el método start.
Arranca el reloj encargado de enviar periódicamente
los mensajes UDP de estado o movimiento en función
del rol con el que se ha creado el CommCore.
Para el reloj arrancado en el método startTimer.
Crea el ControlChannel encargado de gestionar la
conexión establecida de control con el jugador o
servidor por el socket que se le pasa como
parámetro.
Retorna el puntero al objeto ControlChannel del
jugador que se le pasa como parámetro.
Retorna la referencia al objeto ControlChannel del
jugador que se le pasa como parámetro.
Para el ControlChannel arrancado en el método
createControlChannel.
Envía el mensaje que se la pasa como primer
parámetro a través del ControlChannel que se le
pasa como segundo parámetro.
Propaga el mensaje ESTATINI a los jugadores a través
de los ControlChannel correspondientes.
Propaga el mensaje GOL-ACK a los jugadores a través
de los ControlChannel correspondientes.
Propaga el mensaje FALTA-ACK a los jugadores a
través de los ControlChannel correspondientes.
Propaga el mensaje FIPART-ACK a los jugadores a
través de los ControlChannel correspondientes.
Propaga el mensaje FIPARTIT-ACK a los jugadores a
través de los ControlChannel correspondientes.
5.2.3.2 Servidores
Como se ha comentado en el punto anterior, el núcleo del módulo de control se
encarga entre otras funciones de crear el conjunto de hilos que ejecutaran los
procesos correspondientes a los servidores que sirven peticiones de control por el
puerto TCP y peticiones de estado por el puerto UDP.
Para implementar el servidor TCP, se ha usado la clase que crea objetos de tipo
TCPServer de la librería utilizada en nuestro proyecto. Éste objeto implementa un
servidor multi-hilo para comunicaciones basadas en el protocolo de transporte TCP. En
la creación de éste objeto, se le proporciona la clase factoría correspondiente para la
creación automática del gestor que se encargaría de procesar el flujo de información
recibido en ésa comunicación. En éste caso se le proporciona la factoría
ControlRequestHandlerFactory.
Para implementar el servidor UDP, se ha desarrollado una clase que crea objetos de
tipo StateUDPServer, a imagen del comportamiento proporcionado por la clase
TCPServer para el caso anterior. Éste objeto implementa un servidor multi-hilo para
17
comunicaciones basadas en el protocolo de transporte UDP. En la creación de éste
objeto, se le proporciona la clase factoría correspondiente para la creación automática
del gestor que se encargaría de procesar los mensajes recibidos por éste canal. En
éste caso se le proporciona la factoría StateRequestHandlerFactory.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateUDPServer:
Método
StateUDPServer
~StateUDPServer
start
stop
port
Descripción
Crea un StateUDPServer usando el DatagramSocket
(UDP) proporcionado por parámetro. El servidor usa
la factoría StateRequestHandlerFactory
proporcionada por parámetro para crear los gestores
para los mensajes de estado.
Destruye el StateUDPServer y el
StateUDPServerDispatcher que genera en la creación
del objeto.
Arranca el servidor.
Para el servidor.
Retorna el puerto por el que el servidor escucha.
Adicionalmente se ha desarrollado una clase que implementa el proceso de
distribución o deliberación de mensajes a los diferentes hilos de ejecución del servidor
multi-hilo. Ésta clase es una clase auxiliar de la anterior y que hemos llamado
StateUDPServerDispatcher.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateUDPServerDispatcher:
Método
StateUDPServerDispatcher
~StateUDPServerDispatcher
duplicate
release
run
enqueue
stop
Descripción
Crea un StateUDPServerDispatcher
Destruye un StateUDPServerDispatcher
Incrementa el contador de referencias al objeto.
Decrementa el contador de referencias al objeto y
borra el objeto si el contador llega a 0.
Ejecuta el dispatcher.
Encola el mensaje para ser deliberado por el
dispatcher
Para el dispatcher.
5.2.3.3 Gestores
Para procesar la información proporcionada por los mensajes del protocolo de
comunicación en los diferentes canales de estado y control, se han implementado una
serie de gestores que realizaran las acciones que correspondan en función de la
información contenida en dichos mensajes. Éstos objetos gestores serán creados por
los objetos factoría que se han proporcionado a los objetos servidores descritos en el
punto anterior.
Hay que destacar que cada objeto gestor corresponde a un hilo de ejecución
independiente, de tal forma que durante el transcurso de una partida tendremos, en el
caso del servidor, un gestor para las conexiones establecidas en el puerto TCP del
servidor, dos gestores para las conexiones establecidas para cada uno de los
jugadores y n-gestores para el proceso de los mensajes de estado UDP que se crearan
y destruirán en función de las necesidades de proceso del servidor.
18
Adicionalmente también se podria destacar que la implementación hecha de todos
los gestores intenta corregir en la medida de lo posible los errores que se puedan
producir durante el juego.
Éstos errores pueden venir prococados por:
- El envio en un instante del flujo de mensajes de un mensaje que no
corresponde con el estado en el que está la aplicación, por ejemplo, una
vez conectados dos jugadores ser recibe la petición de recepción de un
tercer jugador, o la recepción de un mensaje de reanudación del juego
(XIULET) cuando éste está parado, etc. Todas éstas situaciones se
solucionan mediante el envio de mensajes de confirmación negativa.
- El envio de valores ilegales en los mensajes de estado, por ejemplo, que
algun jugador establezca valors de velocidad mayores de los permitidos en
las reglas definidas por la simulación física que efectua el servidor. Para
solucionarlo, se ha relajado el protocolo de tal forma que en lugar de
descartar el mensaje y, por tanto, alterar la percepción del juego, se ha
decidido aceptar los mensajes pero corrigiendo el valor para que esté
dentro del rango válido. És decir, si la velocidad lineal máxima permitida
es de 50 mm/s, si se recibe un valor de 300 mm/s se corrige y se considera
que el valor correcto es de 50 mm/s.
El objeto correspondiente al gestor de las conexiones establecidas contra el puerto
TCP del servidor es el ControlRequestHandler. Éste se encargará exclusivamente de
servir las peticiones correspondientes a los mensajes CONNECTA del protocolo de
comunicación, a los que contestará con el CONNECTA-ACK si la conexión se ha
establecido correctamente, es decir, si el módulo de control considera aceptar la unión
a la partida por parte del servidor, o contestará con el NACK si la conexión no se
puede establecer, es decir, si el módulo de control considera que el jugador no se
puede conectar.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto ControlRequestHandler:
Método
ControlRequestHandler
run
Descripción
Crea un ControlRequestHandler
Ejecuta el gestor de peticiones de control.
El objeto correspondiente al gestor del canal de control, se asuma el rol que se
asuma, es el ControlChannel. Éste se encargará de mantener el flujo de mensajes de
control con cada uno de los extremos: si se ejecuta como servidor los extremos son
ambos jugadores y si se ejecuta como cliente los extremos es el servidor en el que se
simula la partida.
El flujo de mensajes corresponde al resto de mensajes de control definidos en la
especificación del protocolo de comunicación, que en resumen son todos aquellos que
impliquen información de estado inicial con el mensaje ESTATINI, interrupciones de
juego generadas des de los jugadores con los mensajes GOL, FALTA, FIPART y
FIPARTIT y las interrupciones propagadas desde el servidor a los jugadores con los
mensajes GOL-ACK, FALTA-ACK, FIPART-ACK y FIPARTIT-ACK. Se mantendrá una
comunicación entre el canal de control y el módulo de control para informar en los dos
sentidos éstos eventos.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto ControlChannel:
Método
ControlChannel
Descripción
Crea un ControlChannel. Almacena las referencias al
módulo de control, con el que se comunicará para
notificar los eventos, y del objeto GameData, del que
19
sendMessage
stop
obtendrá la información necesaria para seguir el
control del canal. En función del rol asumido en la
creación del objeto actuará como canal de control de
cliente o de servidor.
Envía por el canal de control el mensaje
proporcionado por parámetro.
Para el canal de control.
El objetos correspondiente al gestor del canal de estado, se asuma el rol que se
asuma, es el StateRequestHandler. Éste se encargará de gestionar los mensajes
recibidos por el puerto UDP, es decir, si se actúa como servidor gestionará los
mensajes con los que los jugadores informaran al servidor sobre que movimientos se
ordenan a los robots, y si se actuá como cliente gestionará los mensajes con los que el
servidor, después del proceso de simulación informará a ambos jugadores sobre el
estado de la partida, que en definitiva serán la posiciones de la pelota y los jugadores
después de aplicar los movimientos ordenados por cada módulo de inteligencia
artificial.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateRequestHandler:
Método
StateRequestHandler
~StateRequestHandler
run
start
Descripción
Crea un StateRequestHandler.
Destruye un StateRequestHandler.
Ejecuta el gestor de peticiones de estado.
Arranca el gestor de peticiones de estado.
Los tres gestores definidos utilizan las clases auxiliares definidas en un apartado
posterior para garantizar que los mensajes recibidos y los mensajes generados para el
envío cumplen las especificaciones del protocolo de comunicación definido en la
oficina técnica.
5.2.3.4 Factorías
Para que los objetos servidores puedan crear los objetos gestores, se han
implementado dos clases que se encargaran de generar estos gestores de forma
dinámica.
Éstos objetos son el ControlRequestHandlerFactory, encargado de crear a los
gestores de las peticiones de control enviadas contra el puerto TCP del servidor, y el
StateRequestHandlerFactory, encargado de crear a los gestores de las peticiones de
estado enviadas contra los puertos UDP. Ambas clases son utilizadas exclusivamente
por los objetos servidores, por lo que se podrían catalogar como auxiliares de éstas.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto ControlRequestHandlerFactory:
Método
ControlRequestHandlerFactory
createConnection
Descripción
Crea un ControlRequestHandlerFactory.
Crea un ControlRequestHandler pasándole como
parámetro el StreamSocket asociado al canal.
Retorna un puntero a éste nuevo gestor.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateRequestHandlerFactory:
20
Método
StateRequestHandlerFactory
createHandler
Descripción
Crea un StateRequestHandlerFactory.
Crea un StateRequestHandler pasándole como
parámetro el mensaje que deberá procesar. Retorna
un puntero a éste nuevo gestor.
5.2.3.5 Reloj
En la especificación del protocolo de comunicación, se establece una recomendación
sobre la frecuencia con la que se deberían enviar los mensajes sobre el canal de
estado, es decir, los mensajes de movimientos en el caso de los jugadores y los
mensajes de estado en cado del servidor.
Se ha implementado un reloj mediante el objeto StateTimer que permite la
ejecución de una función de retrollamada que se encargará de los envíos de los
mensajes correspondientes con el rol con el que se esté ejecutando la aplicación cada
cierto número constante de milisegundos.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateTimer:
Método
StateTimer
onTimer
Descripción
Crea un StateTimer. Almacenara la referencia al objeto
GameData pasado por parámetro del que obtendrá la
información para generar los mensajes de estado.
Función de callback a ejecutar a cada tic de reloj. Se
encargará del envío de los mensajes.
5.2.3.6 Auxiliares
Así mismo, gran parte de los objetos anteriores así como el módulo de control
necesitan de una serie de funcionalidades que debería proporcionar el módulo de
comunicaciones y que no tienen sentido dentro de uno de los objetos anteriores. Por
tanto se implementan un total de cuatro clases auxiliares para proporcionar éstas
funcionalidades, que en resumen son las funciones correspondientes a la validación
del formato de los mensajes y la generación de los mensajes a enviar, siempre
respetando las especificaciones del protocolo de comunicación definido.
De forma general, el formato se valida mediate la comparación de los mensajes con
expresiones regulares, método que nos da la flexibilidad para definir reglas que deben
cumplir los mensajes de forma eficiente y que posteriormente nos garantizará la
validación también de los valores contenidos en los mensajes. Éste método de
validación lo proporcionan las clases RegularExpression de la librería utilizada en éste
proyecto.
La primera de las clases auxiliares corresponde al ControlRequest, encargado de
validar el formato y generar los mensajes con el formato correcto correspondientes a
los mensajes de petición de control, es decir, los mensajes que se envían desde los
jugadores al servidor: CONNECTA, INICI, GOL, FALTA, FIPART, FIPARTIT y XIULET.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto ControlRequest:
Método
matchFormat
Descripción
Retorna cierto si el mensaje pasado como parámetro
cumple las especificaciones del protocolo. Retorna
21
buildConnectaMessage
buildIniciMessage
buildFaltaMessage
falso en cualquier otro caso.
Retorna el mensaje CONNECTA formateado con la
información adicional pasada por parámetros.
Retorna el mensaje INICI formateado con la
información adicional pasada por parámetros.
Retorna el mensaje FALTA formateado con la
información adicional pasada por parámetros.
La segunda de las clases auxiliares corresponde al ControlResponse, encargado de
validar el formato y generar los mensajes con el formato correcto correspondientes a
los mensajes de respuesta de control, es decir, los mensajes que se envían desde el
servidor a los jugadores: CONNECTA-ACK, INICI, GOL-ACK, FALTA-ACK, FIPART-ACK, y
FIPARTIT-ACK.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto ControlResponse:
Método
matchFormat
buildConnectaAckMessage
buildEstatIniMessage
buildGolAckMessage
buildFaltaAckMessage
Descripción
Retorna cierto si el mensaje pasado como parámetro
cumple las especificaciones del protocolo. Retorna
falso en cualquier otro caso.
Retorna el mensaje CONNECTA-ACK formateado con la
información adicional pasada por parámetros.
Retorna el mensaje ESTATINI formateado con la
información adicional pasada por parámetros.
Retorna el mensaje GOL-ACK formateado con la
información adicional pasada por parámetros.
Retorna el mensaje FALTA-ACK formateado con la
información adicional pasada por parámetros.
La tercera de las clases auxiliares corresponde al StateRequest, encargado de
validar el formato y generar los mensajes con el formato correcto correspondientes a
los mensajes de petición de estado, es decir, los mensajes que se envían desde los
jugadores al servidor.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateRequest:
Método
buildMovementMessage
Descripción
Retorna el mensaje de movimiento formateado con la
información adicional pasada por parámetros.
La cuarta de las clases auxiliares corresponde al StateResponse, encargado de
validar el formato y generar los mensajes con el formato correcto correspondientes a
los mensajes de petición de estado, es decir, los mensajes que se envían desde el
servidor a los jugadores.
En la siguiente tabla se puede observar la relación de métodos públicos que ofrece
el objeto StateResponse:
Método
buildStateMessage
Descripción
Retorna el mensaje de estado formateado con la
información adicional pasada por parámetros.
22
5.2.4 Modificaciones sobre el protocolo
Durante el proceso de implementación del proyecto se detectaron una serie de
disfuncionalidades en la especificación del protocolo de comunicaciones. Estas
disfuncionalidades han sido solucionadas mediante la modificación de la
especificación de acuerdo con los compañeros de otros grupos.
Las disfuncionalidades son:
- En el flujo de mensajes correspondiente al envío desde el servidor al
jugador de los mensajes de CONNECTA-ACK y ESTATINI se puede dar el
hecho que se reciban los dos en un solo paquete, de tal forma que para la
aplicación sea difícil separarlos de una forma eficiente. Para solucionarlo
se decide terminar los mensajes añadiendo el carácter ‘$’, de tal forma
que se usará el carácter ‘\n’ para separar líneas dentro de un mismo
mensaje y el carácter ‘$’ para separar diferentes mensajes.
- La especificación original no permite el envío de velocidades lineales y
angulares negativas, por lo que los robots no podrán retroceder ni girar en
sentido horario. Para solucionarlo se modifican los formatos de los
mensajes en los que se incluye ésta información para aceptar el carácter ‘‘ delante del valor.
5.3 Módulo de Inteligencia Artificial
5.3.1 Introducción
El módulo de Inteligencia Artificial se encarga de crear y establecer el comportamiento
de los robots en la aplicación, con el objetivo final de simular una inteligencia tal que
permita al jugador ganar el partido.
Siguiendo el diseño de nuestra aplicación, este módulo pertenece exclusivamente al
cliente. A partir de los diferentes datos referentes al partido que envía el servidor
periódicamente, como las posiciones de los robots o sus velocidades, la Inteligencia
Artificial estima los movimientos que debería realizar cada uno de los robots del
jugador. Dichos movimientos serán enviados a una velocidad constante al servidor
mediante el módulo de control y el de comunicaciones, el cual calculará el efecto que
tienen sobre el campo mediante una física simulada.
En un principio se estableció en las sesiones de la oficina técnica que los
parámetros sobre los que trabajaría este módulo serían la fuerza lineal y la fuerza
angular, sin embargo más adelante se decidió substituirlos por la velocidad lineal y la
velocidad angular para así facilitar los cálculos.
Si tratamos con robots reales y no con los simulados de la Fira Middle League
Simurosoft, éstos suelen moverse mediante dos ruedas situadas en la parte izquierda
y derecha del robot que pueden avanzar hacía adelante o hacía atrás. Se puede
realizar una transformación entre la velocidad de cada rueda y los parámetros que
calcula la Inteligencia Artificial:
vl =
(vi + vd ) , va = (vi − vd )
2
L
Donde L es la distancia entre cada rueda.
5.3.2 Diseño
Hemos realizado el diseño del módulo de Inteligencia Artificial teniendo en cuenta el
objetivo a conseguir, que no es otro que ganar en un partido de fútbol entre robots.
Para ello es necesario que, como sucede en la vida real con jugadores humanos de
23
este deporte, los robots sean capaces de actuar en tiempo real tanto individual como
colectivamente ante los estímulos que reciban del mundo exterior. De los diversos
sistemas de Inteligencia Artificial, un sistema de multiagentes resulta especialmente
adecuado ya que cumple con los requisitos de la aplicación.
La base de todo sistema multiagente son los agentes. Un agente inteligente es un
proceso computacional capaz de realizar tareas de forma autónoma y que se
comunica con otros agentes para resolver problemas mediante cooperación,
coordinación y negociación. Los agentes habitan en un entorno complejo y dinámico
con el cual interaccionan en tiempo real para conseguir un conjunto de objetivos, en
nuestro caso, derrotar al rival en un partido de fútbol de robots.
Los agentes presentan una serie de características que resultan muy adecuadas
para una aplicación de este tipo, como son la reactividad, la capacidad de reaccionar
en tiempo real a los cambios en su entorno, la autonomía, pues un agente es capaz de
actuar por su cuenta, la comunicación, pues en el caso de que un solo agente no
puede realizar una tarea puede ser llevado a cabo por varios que trabajen
conjuntamente, y el razonamiento, pues son capaces de tomar decisiones. En
conclusión,
Así pues, cada robot será un agente distinto, teniendo dos tipos de agentes
claramente diferenciados según su funcionalidad: el portero y el jugador. El rol de
portero lo llevará a cabo el robot que juega en dicha posición, teniendo así pues un
comportamiento defensivo: su principal objetivo será proteger la portería. El rol de
jugador es asumido por el resto de robots quiénes actuarán de forma ofensiva o
defensiva según la situación, es decir, según los datos sobre el estado de juego que
periódicamente recibimos del servidor.
5.3.2.1 Comportamiento de los agentes
Los dos tipos de agentes, portero y jugador, tienen comportamientos claramente
diferenciados, según los roles ya comentados anteriormente. Cada agente tomará sus
propias decisiones y actuará por su cuenta o en combinación con sus compañeros si
es necesario, según el estado del campo del juego.
A continuación se detalla el comportamiento de los dos tipos de agente, indicando
las acciones que realizan según las diferentes circunstancias en las que se puede
encontrar durante el partido.
Comportamiento del agente: Portero
1. Nuestro equipo tiene la posesión
a. El portero controla el balón.
i. Si es posible realiza un pase a un compañero, pasa a un
compañero y protege el centro de la portería
ii. Si no, es posible, despeja el balón
b. El portero no controla el balón
i. Proteger el centro de la portería
2. Nuestro equipo no tiene la posesión
a. Defender Portería
El objetivo de este agente es simple, como el de los porteros reales: evitar que los
robots rivales marquen goles. Para ello evita realizar acciones arriesgadas, tomando
siempre la decisión más segura de cara a minimizar las posibilidades de poner en
peligro su portería.
Un resumen breve y conciso de las diferentes acciones que puede adoptar éste
agente es el siguiente:
- Pasar: Pasa al jugador desmarcado situado en una posición más avanzada.
- Despejar: Despeja el balón a una posición libre.
24
-
Proteger el centro de la portería: Se sitúa en el centro de la portería.
Defender Portería: Protege la portería de los tiros de los robots rivales.
Comportamiento del agente: Jugador
1. Nuestro equipo tiene la Posesión
a. El jugador controla el balón
i. El jugador está desmarcado
1. Si puede tirar a puerta, tira a puerta
2. Si no, avanza hacía la portería rival
ii. El jugador está marcado
1. Si puede pasar, pasa
2. Si no, despeja el balón
b. El jugador no controla el balón
i. Si el jugador es un Delantero, se desmarca
ii. Si no, realiza una defensa especulativa
2. Nuestro equipo no tiene la Posesión
a. Jugador está cerca del balón
i. Intenta recuperarlo
b. Jugador no está cerca del balón
i. Jugador es el defensa más retrasado
1. Defiende la portería
ii. Jugador no es el defensa más retrasado
1. Si puede cubrir un pase, cubre el pase
2. Si no, defiende la portería
El comportamiento del agente jugador resulta más complejo que el del portero, ya
que realiza tantos aspectos defensivos como ofensivos y es capaz de realizar un
número de acciones considerablemente superior. Su objetivo es, básicamente,
participar en el ataque ya sea directamente o apoyando al jugador con el balón, o
defendiendo la portería cuando ésta se encuentra en peligro. Debido a este hecho
este agente necesita conocer el estado del juego con una mayor precisión.
Como en el caso anterior, explicamos brevemente las diferentes acciones que
puede realizar este agente:
- Tirar a puerta: Realiza un tiro a la portería rival.
- Avanzar a portería rival: Avanza con el balón hacía la portería rival.
- Pasar: Idéntico al agente Portero.
- Despejar: Idéntico al agente Portero.
- Desmarcarse: Se sitúa en una posición desde la que pueda recibir un pase sin
ser interceptado por los robots rivales.
- Defensa especulativa: Avanza lentamente mientras cubre posibles pases a
robots rivales.
- Recuperar el balón: Avanza hacía el balón para recuperarlo.
- Defender portería: Retrocede a defender la portería.
- Cubrir pase: Se sitúa cubriendo el pase a un jugador rival.
5.3.2.2 Algoritmo de encaminamiento
Debido a los estrictos requisitos en cuanto a los tiempos de respuesta, consideramos
más adecuada implementar una estrategia reactiva que no una que lleve a cabo
grandes planificaciones de trayectorias que tarden mucho tiempo en obtener
resultados, lo que llevaría a que el módulo obtuviese resultados para estados de juego
pasados, y por tanto, no válidas.
1. Estamos en la posición deseada
a. Si no estamos en la orientación adecuada, corregirla
25
2. No estamos en la posición deseada
a. Si existe una trayectoria sin obstáculos hacia el punto, realizar dicha
trayectoria
b. Si no existe, dirigirse hacia el punto más cercano posible sin
obstáculos
c. Si no existe dicho punto, tomar una dirección sin obstáculos
Mediante este algoritmo un robot puede acceder a cualquier punto del campo del
juego, siempre y cuando exista una trayectoria desde su posición. Si se encuentra
rodeado de obstáculos, permanecerá inmóvil a la espera de que cambie la situación.
5.3.3 Implementación
Se utilizan los hilos que proporciona la librería POCO C++ para implementar el sistema
de agentes. De esta manera, cada agente se ejecuta en un hilo independiente de
manera concurrente y separada al del resto de agentes, tal como deseamos para
cumplir los requisitos de la aplicación. Estos hilos son creados cuando el cliente se
conecta al servidor y mientras el partido no acabe calculan las velocidades que debe
tomar cada robot.
Los distintos objetos generados y utilizados para este módulo pueden agruparse
según su funcionalidad, siendo los siguientes:
- IA: Ésta es el único objeto visible desde fuera del módulo. Se encarga de
crear los agentes, inicializar sus hilos y destruirlos una vez se ha acabado el
partido.
- Agentes: Corresponde a las objetos Agentes, Jugador y Portero. Estas dos
últimos implementan el comportamiento de los agentes de mismo nombre,
heredando del objeto Agente los comportamientos comunes a ambos.
- Mensajes: Los agentes se comunican entre sí dejándose mensajes en
buzones implementados mediante este objeto.
- Campo: Este objeto contiene una referencia a los datos globales de la
aplicación, entre ellos las posiciones de la pelota y los robots de ambos
equipos, así como sus velocidades. Implementa las diversas funciones
matemáticas necesarias para calcular trayectorias de robots, detectar
colisiones entre ellos y demás. Así pues, es accedido por los agentes para
consultar el estado del juego
Resulta especialmente interesante analizar con más profundidad el objeto Campo,
pues es de vital importancia para el correcto funcionamiento de la Inteligencia
Artificial, pues permite a los agentes tanto ser conscientes de su entorno como
razonar cual es la mejor opción que pueden tomar entre las disponibles.
A continuación mostramos la lista de métodos públicos que son accedidos desde los
objetos Agentes, clasificándolos según su funcionalidad.
Respecto a la reacción ante el entorno, los siguientes métodos son utilizados por
los objetos agentes para consultar el estado del campo de juego y así poder
reaccionar adecuadamente ante ellos. Informan de la situación del robot en relación a
sus compañeros, rivales y balón.
Método
DetrasBalon
getPosesion
ControlaBalon
Delantero
Desmarcado
CercaBalon
Descripción
Retorna cierto
Retorna cierto
posesión.
Retorna cierto
Retorna cierto
delantero.
Retorna cierto
Retorna cierto
si el jugador esta detrás del balón.
si nuestro equipo tiene el balón en
si el jugador controla el balón.
si el jugador está en posición de
si el jugador esta desmarcado.
si el jugador esta cerca del balón.
26
UltimoDefensa
getCampoBalon
getCampoPlay
Retorna cierto si el jugador es el defensa más
retrasado de su equipo.
Retorna cierto si el balón esta en el campo.
Retorna 1 si jugamos en el campo izquierdo, 2 si
jugamos en el campo derecho.
Respecto a los cálculos matemáticos, todos los cálculos matemáticos necesarios
para establecer las trayectorias de movimiento, detectar futuras colisiones así como
evitarlas son implementados por el objeto Campo utilizando el lenguaje C++ sin usar
librerías adicionales.
Método
BalonPeligroso
TrayectoriaBalon
TrayectoriaLibre
TrayectoriaLibrePuntos
TrayectoriaOrientacion
TrayectoriaAzar
TiroLibre
AvanzarPorteria
RetrocederPorteria
DistanciaPJ
DistanciaJPorteria
getPosDespeje
Descripción
Retorna cierto si el balon es peligroso para nuestra
porteria.
Retorna cierto si el jugador puede interponerse en la
trayectoria del balon.
Retorna cierto si entre los dos jugadores se puede
realizar un pase sin que sea interceptado.
Retorna 0 si existe una trayectoria libre entre un
jugador y un punto,1 si existe a la espalda del
jugador,2 si no existe.
Calcula con que orientacion podemos llegar a la
posicion deseada.Devuelve la orientacion o -1 si no
encuentra ninguna.detras es cierto si la trayectoria
esta a la espalda del robot.
Calcula una trayectoria al azar libre de obstaculos y
que no se acerque a los limites del campo. back es
true si la trayectoria esta a la espalda del robot.
Retorna cierto si se puede realizar un buen tiro a la
porteria enemiga.
El jugador avanza a la porteria rival. salx y saly puntos
a los que debe ir.
El jugador retrocede a defender su porteria. salx y saly
puntos a los que debe ir.
Retorna la distancia entre dos puntos.
Retorna la distancia de un punto a la porteria.
xd e yd es el punto al cual debe despejar el pase.
5.4 Módulo de Gráficos
5.4.1 Introducción
El módulo gráfico se encarga de todo lo que se refiere a visualización e interacción con
el cliente. Como especificaciones iniciales se pedía que fuera en tres dimensiones y
que permitiera cambios de vista. Se debería poder ver el juego desde una perspectiva
cenital y desde la vista subjetiva de cada jugador.
A parte de estas especificaciones iniciales también se ha de tener en cuenta el
diseño de la interfaz de usuario, que sea manejable y sencilla. Para todo ello se ha
utilizado un estilo de "videojuego" alejado de los típicos esquemas de ventanas de los
sistemas operativos. De esta manera nuestro producto se desmarca del resto dando
un aspecto mucho menos técnico pero igual de efectivo. Al ser la parte gráfica se
deseaba que al usuario le llamase la atención. También se han tenido en cuenta
posibles configuraciones de la máquina sobre la que ha de correr la aplicación. Esto se
27
puede solucionar gracias al motor utilizado, OGRE, que nos permite seleccionar las
características básicas que deseamos en nuestra visualización.
5.4.2 Diseño
El diseño de este módulo se puede dividir en dos partes. El diseño de objetos que
utilizamos y el diseño de la programación 3d.
5.4.2.1 Diseño de objetos
Esta parte del diseño hace referencia a muchos elementos que mostramos por
pantalla ya que en nuestro desarrollo no generamos todos los objetos desde código.
Para ello se diseñan los objetos más importantes que necesitamos con otras
herramientas.Para empezar se realizan dos objetos que representan los robots que
vemos por pantalla.
Se han generado con 3d Studio y se han exportado a archivos mesh, formato que
utiliza Ogre 3D. A estos objetos se le unen texturas realizadas con Gimp y scripts de
los materiales que utilizaremos.
También se realiza el diseño del campo siguiendo los parámetros especificados en
los documentos de análisis.
5.4.2.2 Diseño de la programación 3D
Una vez tenemos todos los componentes necesarios pasamos a describir la estructura
del módulos. Al no realizar ninguna otra tarea que visualización y interficie gráfica, se
puede realizar un modelo Vista-Control. Se diseña una clase principal llamada
GameManager. Esta clase implementa una interficie que nos sirve para comunicarnos
con el módulo de control y deriva de otras que harán que reaccione a todos los
eventos de teclado y ratón, también es la encargada de cumplir todas las
especificaciones para poder utilizar Ogre.
Como veremos se encarga de todo el control gráfico gracias a una pila de
GameStates encargada de redirigir la entrada a la clase GameState que se encuentre
en el top. Así podemos hacer independientes los diferentes estados del módulo gráfico
únicamente teniendo en cuenta que al entrar en un estado hay que crearlo todo como
si no existiera nada previamente y al salir de un estado limpiar todo lo que se haya
hecho.
Una vez inicializada la clase GameManager lo que hace es apilar el primer estado
IntroState que nos muestra la primera pantalla, reaccionando a los diferentes eventos
podremos "navegar" por los distintos estados de juego realizando la interacción
adecuada.
Aquí se nos muestra la estructuración de las clases más importantes de este
modulo y la relación entre ellas:
28
5.4.3 Implementación
Una vez realizado el diseño modular la implementación se simplifica al poder
comprobar cada estado por separado. Durante la implementación también se añaden
a la estructura todas aquellas funciones que atienden eventos y se generan mediante
código la interfaz de usuario. Como cada estado tiene sus propios eventos, cada uno
29
de ellos los atiende de forma independiente, así que la modularidad sigue intacta.
También se añaden las llamadas necesarias al control. Para ello se referencia una
clase del tipo ControlCore a la que se le llamarán las funciones necesarias.
Se perdemos un poco de modularidad al hacer que la clase GameManager tenga
que llamar funciones de unos GameStates específicos, pero la idea base sigue intacta.
Además se configuran todos los archivos necesarios para el funcionamiento de OGRE.
Así pues después de la implementación el sistema sigue el mismo patrón que el
diseñado. La clase GameManager es la que realiza todas las operaciones de entrada y
salida, redirigiendo estas al GameState activo. Estos GameStates trabajan de maneras
distintas y se pueden explicar cada uno de ellos por separado:
- IntroState: presenta la pantalla inicial, reaccionando a los botones
mostrados y cambiando de GameState según el botón al que reaccione. Así
pues si pulsamos "Créditos" iremos al GameState CreditsState, si pulsamos
"Ayuda" iremos a AyudaState, si pulsamos "Unir a partida" nos dirigimos al
UnirState y si pulsamos "Salir" cerraremos la aplicación. Todos estos eventos
son controlados por los diferentes "handlers" de la clase. Cada uno de ellos
hace referencia a un botón. Como se puede apreciar en el desarrollo de todo
el módulo todas las funciones "handler" van seguidas del nombre del botón al
que hacen referencia.
- CreditsState: Muestra los créditos y al pulsar Aceptar vuelve al estado
IntroState.
- AyudaState: Muestra la ayuda en la aplicación.
- UnirState: Este estado es el encargado de recoger la información de
conexión y de parte de la visualización que tendremos durante el partido. Es
el primero, en una ejecución normal de la aplicación, que utiliza el control
para comunicarse con el resto de módulos cuando el usuario ordena
conectarse. Una vez se ha hecho la conexión pasa al siguiente estado,
PlayState, al ser avisado mediante la función gfxEstatIni().
- PlayState: es el estado encargado de cargar todos los elementos 3d
diseñados y leer la información necesaria del estado del juego para mostrarla
por pantalla. Es el más importante y crítico de todos. Como el resto reacciona
por si mismo a los eventos necesarios. Además reacciona a muchos de los
eventos generados por el control a la interfaz gráfica y a cada frame
actualiza todo la información de pantalla. Gracias a la estructuración de
OGRE en forma de árbol nos permite cambiar la cámara de posición
ajustándola a las especificaciones y simplifica el posicionamiento de los
robots y la pelota haciendo que estos elementos dependan del nodo campo.
- PauseState: este estado se utiliza sobre el estado PlayState para desactivar
todos los controles del anterior aunque lo podamos ver. Tiene un único botón
que avisa al módulo de control del deseo de iniciar el partido.
6 Resultados
6.1.1 Módulo de Comunicaciones
Para comprobar el correcto funcionamiento y validar el módulo de comunicaciones se
ha desarrollado una aplicación de texto, que hemos nombrado TikitakaServerTestUnit,
que emula el comportamiento del cliente gráfico, en éste cliente de texto se ha
implementado una pequeña línea de comandos (shell) en la que poder ordenar las
mismas acciones que se ordenarían desde el cliente gráfico a la vez que permite ver el
flujo de mensajes.
Adicionalmente, en el módulo de comunicaciones se ha implementado un sistema
de registro (logging) personalizable mediante el fichero de configuración
correspondiente que permite almacenar en fichero o mostrar en pantalla los mensajes
30
de error o de información durante el transcurso de una conversación entre el cliente y
el servidor con el intercambio de mensajes especificados en el protocolo de
comunicación.
Así pues, para validar la implementación se han emulado múltiples partidas usando
la implementación del servidor TikitakaServer con el sistema de registro activado en
modo trace, dos clientes TikitatakaServerTestUnit también con el sistema de registro
activado en modo trace, y ejecutando diversas combinaciones de órdenes que
pudieran provocar un funcionamiento erróneo de la aplicación.
En todos los casos, la simulación ha sido satisfactoria, aportando una
implementación completamente determinista, robusta y estable del módulo de
comunicaciones.
31
Anexos
A Manual de usuario
Este es el manual de usuario de “Tikitaka” el simulador de la FIRA middle league.
A.1 Instalación
Ejecute Tikitaka-setup.exe y siga las instrucciones.
A.2 Uso
Este software se divide en dos partes. Primero explicaremos la parte del servidor ya
que es necesaria para que la parte del cliente funcione en su totalidad.
A.2.1 Servidor
Para hacer funcionar funcionar simplemente tiene que ejecutar el programa
“TitakaServer.exe”. Este se encargará automáticamente de los procesos necesarios.
Abrirá el puerto 10000 para recibir conexiones de los software cliente. Para que los
clientes puedan conectarse solo han de saber la IP del ordenador en el que se
encuentra el servidor.
Cuando quiera detenerlo simplemente tiene que presionar Ctrl+c.
A.2.2 Cliente
La parte del cliente consta de los controles necesarios para que el jugador se
conecte a cualquier servidor de juego del mismo tipo que el creado en esta aplicación.
Cuando arranque la aplicación podrá ver las siguientes pantallas.
A.2.2.1 Inicio
En esta pantalla podemos ver los siguientes botones que actúan de la siguiente
manera:
32
-
Unirse a partida: Nos permitirá conectarnos a un servidor para poder jugar.
Ayuda: Nos muestra un pequeño tutorial que nos recuerda como utilizar la
aplicación.
Créditos: Muestra el equipo que ha hecho posible este producto.
Salir: Termina el juego.
A.2.2.2 Unirse a partida
Aquí podemos indicar donde nos queremos conectar y los nombres de los equipos.
Cuando haya introducido los datos necesarios, dirección IP del servidor, puerto que
utilizaremos para recibir información y el nombre de los equipos, podemos “Conectar”.
Esta conexión preparará el inicio del juego. En caso de no querer siempre podemos
volver “Atrás”.
A.2.2.3 Iniciar el juego
33
Una vez conectados se nos mostrará una pantalla como la siguiente.
Cuando quiera que empiece el juego clique Iniciar.
Una vez que los dos jugadores hayan iniciado, que empiece el partido!!
A.2.2.4 Durante el partido
Durante el partido podrá ver el avance de este. Los jugadores que muestra la
aplicación con banda amarilla son el equipo controlado por el cliente que utiliza,
mientras que los que tienen una banda azul son los del contrario. Como puede
apreciar se puede interactuar con la aplicación mediante los botones que aparecen y
desaparecen o activan y desactivan.
A continuación tiene una lista de los botones existentes y la utilidad de cada uno
cada uno.
En la zona destinada al arbitro y de arriba a abajo tenemos:
- Goal: Marca un gol. Este gol subirá al marcador del equipo contrario al
campo donde se encuentre el balón.
- Free Ball: Se pita una falta de tipo Free Ball. Como no se indica equipo esta
falta se lanzará en el punto de cuarto de campo más cercano.
- Half Time: Se indica la media parte del partido.
- End Game: Se finaliza el partido.
En la zona destinada al equipo propio:
- Penalty: Penalty en contra de nuestro equipo.
- Free Kick: Se señala una falta del tipo Free Kick en contra nuestra.
- Free Ball: Este Free Ball se lanzara desde el punto de cuarto más cercano al
balon en nuestro campo.
En la zona destinada al equipo propio:
- Penalty: Se pita un penalti en contra del equipo contrario.
- Free Kick: Free Kick a nuestro favor.
- Free Ball: Free Ball que se lanzará en el punto de cuarto más cercano al
balón en el campo contrario.
34
A.2.2.5 Xiulet
Siempre que se pare el juego aparecerá un texto indicativo de porque y aparecerá
un botón “Xiulet” con el que se puede indicar la reanudación del partido.
A.2.2.6 Selección de Cámara
Con esta lista usted puede elegir desde que cámara quiere ver la acción. La cámara
seleccionada aparece con fondo amarillo. Puede seleccionar una cámara cenital o la
correspondiente a lo que ve cada jugador.
A.2.2.7 Cronómetro
Puede ver como avanza el juego y mediante el crono situado en la parte superior
derecha, junto a la parte del partido que se está disputando, saber en que momento
se encuentra. En cualquier momento puede ver el marcador del partido situado en la
parte superior central.
A.2.2.8 Fin del partido
Una vez el arbitro indique el final del partido usted podrá ver una pantalla como la
siguiente:
En ella se indica el marcador final así como el resultado del encuentro. También
aparece un botón Aceptar que le conducirá a la pantalla de inicio.
Y aquí finaliza el manual de la aplicación. Esperamos que les sea de utilidad.
B Referencias
-
POCO C++ Libraries – http://www.appinf.com/poco/info/index.html
OGRE3D: Open Source Graphics Engine – http://www.ogre3d.org/
35
C Oficina Técnica
C.1 Sesión 2 de Febrero
Ordre
-
del dia:
Física del joc.
Arquitectura en xarxa.
Mòduls.
Acords:
- La pilota i els jugadors només tenen 2 graus de llibertat, o sigui només es
poden moure en el pla, i no poden xutar.
- Els graus de llibertat del robot seran:
o força lineal.
o força angular.
- S'utilitzaran llibreries físiques externes per a la simulació dels moviments i les
interaccions. En la propera reunió es presentaran diferents alternatives i se'n
votarà una.
- En el joc multijugador, un ordinador farà de servidor i l'altre de client. El
servidor serà l'encarregat de calcular els estats del joc (llibreria física) a partir
de les dades que rebrà de la IA del client i de la seva pròpia IA.
- S'annexa una imatge amb el diagrama general de comunicacions.
- En cas que en el moment
d'executar-se la física el servidor no
hagi rebut moviments del client,
usarà els últims moviments que
havia rebut d'aquest.
- El missatge d'estat estarà compost
per 11 registres cada un dels quals
constarà de:
o Id
o Posició
o angle d'orientació
o velocitat lineal
o velocitat angular
- El missatge de moviments constarà de 5 registres cada un dels quals
constarà de:
o Id
o força lineal
o força angular
- Per unanimitat s'ha decidit que el missatge d'estat no inclogui informació
sobre les forces aplicades.
- Per normativa del joc, el servidor no podrà utilitzar la última acceleració
coneguda del client per tal de calcular la seva IA.
- El codi font de l'aplicació estarà disponible per als altres grups una vegada
hagi acabat el desenvolupament.
C.2 Sesión 8 de Febrero
Acuerdos:
- Libreria fisica : Cada grupo usara la libreria que quiera.
- Libreria grafica: Cada grupo usara la libreria que quiera.
- Parametros de la fisica:
36
-
CAMPO : Fregamiento (sin perdida de energia en el rebote)
PELOTA : Massa
ROBOT : Massa, Fuerza Maxima ( Fuerza Lineal + Fuerza Angular)
Unidad Metrica : velocidad* : mm/s
fuerza* : mN
posicion*: mm
orientacio*/../velocitat angular : 0..360º
Sin decimales(enteros)
Sistema de coordenada : adjunto fichero
PROTOCOL XARXA:
- Se ha decidido crear dos conexiones:
o TCP para control de la partida.
o UDP comunicacion fisica.
o Puerto de conexion UDP/TCP es el 10000
- Protocolo inicio de partida :
o El servido espera 4 conexiones ( 2 por cliente), 1ª conexion a s
servidor, 2ª preparado para empezar la partida.
o Posicion inicial de los jugadores: Posiciones fijas elegidas por el
servidor. 2 posiciones : ataque ,defensa.
o La partida se inicia en cuando los dos equipos esten preparados, sin
tiempo de espera.
CONEXION UDP (SERVER --> CLIENTE) Por acuerdo entre grupos:
sprintf(miss,"%d \n", milis);
sprintf(miss,"%d,d,%d,%d,%d,%d \n",id_jugador, pos_x,pos_y,
vel_lineal,vel_angular); X 11
orientacion,
CONEXION UDP (CLIENTE --> SERVIDOR)
sprintf(miss,"%d.%d \n",milis,id); id--> del client.
sprintf(miss,%d ,%d,%d \n",id_jugador,força_lineal, força_angular);
%d id (client)--> 4 caracteres sin 0 delante 0..9999
%d del resto enteros de 32 bits.
C.3 Sesión 9 de Febrero
Modificaciones del acta anterior
1.- orientacio*/../velocitat angular : 0..359º
2.- Se elimina el id de jugador en los mensajes UDP
CONEXION UDP (SERVER --> CLIENTE)
Por acuerdo entre grupos:
sprintf(miss,"%d\n", milis);
sprintf(miss,"%d,%d,%d,%d,%d\n", pos_x,pos_y, orientacion, vel_lineal,vel_angular); X
11
Ejemplo:
tttttt = timestamp de la partida en milisegundos. Máximo 6 carácteres.
xxxx = pos_x
yyyy = pos_y
ooo = orientación
vl = velocidad lineal
va = velocidad angular
37
tttttt\n <- timestamp
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
xxxx,yyyy,ooo,vl,va\n
<<<<<<<<<<<-
pelota
portero izquierda
jugador 1
jugador 2
jugador 3
jugador 4
portero derecha
jugador 1
jugador 2
jugador 3
jugador 4
CONEXION UDP (CLIENTE --> SERVIDOR)
sprintf(miss,"%d,%d\n",milis,id); id--> del client.
sprintf(miss,%d,%d\n",força_lineal, força_angular);
Ejemplo:
iiii = identificador del cliente proporcionado por el servidor
fl = fuerza lineal
fa = fuerza angular
tttttt,iiii\n
fl,fa\n <- portero
fl,fa\n <- jugador
fl,fa\n <- jugador
fl,fa\n <- jugador
fl,fa\n <- jugador
1
2
3
4
3.- Se elimina la linea:
%d del resto enteros de 32 bits.
Acta del dia:
Se han acordado los siguientes puntos:
1 .- Como base se utilizarán las reglas de juego definidas en el documento de marzo
de 2006
2 .- Se elimina el Goal Kick.
3 .- No hay timeout.
4 .- El cronometro será mantenido por el servidor ( Modificación de la regla 3.3 )
5 .- Las fuerzas angulares y lineales pueden ser negativas
6 .- Las posiciones iniciales y de faltas son fijas, y para todos los grupos iguales, y
serán establecidas por el sevidor a los clientes. Queda por concretar cuales serán.
7 .- Se utiliza el identificador del cliente más bajo para decidir el primer atacante. De
esto se encarga el servidor.
Propuestas para la siguiente sesión:
Concretar posiciones fijas
Tener en cuenta o no las porterias en el eje de cordenadas para no tener números
negativos.
Para agilizar la definición de mensajes los responsables de comunicaciones podrian
reunirse a parte.
38
C.4 Sesión 15 de Febrero
1.- Ordre del dia
1.1.- Concretar posicions fixes
1.2.- Replantejar origen eixos de coordenades (porteria esquerra, té valors negatius?)
1.3.- Definir protocol comunicacions en alt nivell
2.- Conceptes clarificats
2.1.- En indicar una posició d'algun robot o de la pilota, el valor (x,y) d'aquesta es
refereix al centre de la figura geomètrica que el representa (quadrat i circumferència
respectivament).
2.2.- Els robots poden entrar dins les porteries.
3.- Acords
3.1.- Orientació dels robots: Els robots miren cap on apunta la fletxa segons aquesta
imatge (van endavant si segueixen el sentit de la fletxa, i enrere en cas contrari):
3.2.- Les posicions fixes i corresponents orientacions dels jugadors per al sac inicial i
els diferents tipus de faltes són les que hi ha representades en imatges al document
“FIRA Middle League SimuroSot Game Rules (Mar 2006)”. Com que en les imatges no
s'especifiquen valors exactes de les posicions, serà responsabilitat de cada grup donar
uns valors numèrics raonables en els respectius servidors.
3.3.- Les línies del camp (que la normativa diu que són de 3 mm) també es consideren
part del terreny de joc i per tant els robots les poden trepitjar, però no les poden
sobrepassar (hi ha parets).
3.4.- L'origen dels eixos de coordinades queda fixats de forma que les posicions
sempre siguin valors positius. Aquest punt és l'inferior esquerra del camp de joc,
alineat verticalment amb la porteria i horitzontalment amb la banda inferior del camp:
39
3.5.- Quan l'arbitre pita una falta i fins que aquesta es treu, NO s'atura el cronòmetre.
3.6.- Les posicions dels jugadors i la pilota en els missatges UDP i TCP són sempre
fixes i en aquest ordre:
Pilota
Jugador 1 (equip 1)
Jugador 2 (equip 1)
Jugador 3 (equip 1)
Jugador 4 (equip 1)
Jugador 5 (equip 1)
Jugador 1 (equip 2)
Jugador 2 (equip 2)
Jugador 3 (equip 2)
Jugador 4 (equip 2)
Jugador 5 (equip 2)
3.7.- Protocol: connexió dels programes al servidor i inici del joc:
El missatge ESTAT (que tindrà diferent contingut per a cada equip) conté els següents
paràmetres -en aquest ordre-:
Equip (int, p.ex 1 o 2)
40
Atacant (bool)
Posicions x 11 (veure punt 3.6)
En començar a rebre paquets UDP s'inicia la partida.
3.8.- Protocol de control: Format del missatge de GOL
El missatge d'estat té el mateix format que al punt 3.7
3.9.- Protocol de control: Format del missatge de FALTA
El missatge d'estat té el mateix format que al punt 3.7
41
3.10.- Protocol de control: Format del missatge de MITJA PART
El missatge d'estat té el mateix format que al punt 3.7
3.11.- Protocol de control: Format del missatge de FI DE PARTIT
El missatge d'estat té el mateix format que al punt 3.7
3.12.- S'ha acordat que farem servir els següents paràmetres de física en la
configuració inicial (després de fer el CONNECT, el missatge ID a més de l'identificador
d'equip passarà també aquests paràmetres, en aquest ordre), però es deixa per més
endavant acordar els valors i/o rangs d'aquestos:
- Pes robot
- Pes pilota
- Fregament amb el terra
- Velocitat màxima angular
- Velocitat màxima lineal
- Força màxima angular
- Força màxima lineal
42
C.5 Sesión 16 de Febrero
Acords arribats:
- Quan l'arbitre assenyala que hi ha hagut un gol, el servidor entendrà que el gol
ha estat fet a la portaria la qual la pilota està més aprop en el moment de rebre
el missatge
- S'ha acordat també el protocol de comunicació que s'adjunta. Aquest protocol
de comunicació és el que les diferents implementacions de la pràctica hauran
de complir per tal de poder interactuar entre elles correctament.
C.6 Fe de erratas 22 de Marzo
Final del partit amb empat::
- En cas d'acabar el partit en empat, es considerarà aquest resultat com un
resultat vàlid del partit sense necessitat de jugar temps de pròrroga o penals.
- En cas de voler desempatar s'haurà de jugar una nova partida entre els dos
equips.
C.7 Aclaraciones 12 de Abril
Els caps de grups presents a la tarda d'avui hem decidit els següents punts per aclarir
alguns casos i facilitar el treball.
- Existeix un cas no contemplat a l'actual definició de missatges, en cas de que
l'arbitre xiuli un Free Ball sense ser falta de cap equip. Per solucionar-ho s'ha
afegit al missatge de Free Ball l'opció d'equip 0 que indicarà aquest cas.
Quan es xiula una falta d'aquest tipus el servidor decideix en quin quart del
camp es xiulara, aquet quart ha de ser el més proper a la posició de la pilota.
- Igualment si es xiula un Free Ball per part d'un equip, es treu al punt més
proper del camp corresponent.
Finalment per facilitar la feina s'ha decidit l'orientació inicial dels porters per tal de
col·locar les cameres correctament si es vol. Els porters s'han d'orientar de la següent
manera (veure fitxer adjunt) per tal de que tots parin amb la part esquerra.
43
C.8 Actualización especificaciones 20 de Abril
Como ya se hablo el viernes pasado. se ha realizado el siguiente cambio en las
especificaciones del proyecto:
- En el protocolo de red los parámetros que les pasan los clientes al servidor se
sustituyen la fuerza lineal y la angular por velocidad lineal y angular,
respectivamente.
- Se elimina la restricción de giro del 10% a velocidad máxima.
- En los parámetros que les envian los clientes al servidor, con el fin de no
modificar el protocolo, la fuerza lineal máxima y angular máxima se
mantienen, aunque no sirvan para nada.
Los cambios se han realizado para facilitar los cálculos de la IA.
D Protocolo Simulador FIRA Middle League SimuroSot
Protocol Simulador FIRA Middle League SimuroSot
Sistemes Informàtics II '06/'07
Extracte
Aquest document descriu els detalls de implementació del protocol de
comunicació consensuat en les diferents reunions de oficina tècnica, que
han de respectar les diferents implementacions del simulador de partits
de futbol de robots proposat com a projecte en la assignatura Sistemes
Informàtics II de la Enginyeria Informàtica de la Universitat Rovira i
Virgili en el curs 2006/2007.
Taula de Continguts
1. Protocol Client-Servidor
1.1 Interacció Client-Servidor TCP/IP
1.2 Interacció Client-Servidor UDP/IP
1.3 Interacció Client-Servidor TCP/IP
1.4 Interacció Client-Servidor TCP/IP
1.5 Interacció Client-Servidor TCP/IP
1.6 Interacció Client-Servidor TCP/IP
2. Especificació dels missatges
2.1 CONNECTA
2.2 CONNECTA-ACK
2.3 ESTATINI
2.4 INICI
2.5 ESTAT
2.6 MOVIMENT
2.7 GOL
2.8 GOL-ACK
2.9 XIULET
2.10 FALTA
2.11 FALTA-ACK
2.12 FIPART
2.13 FIPART-ACK
2.14 FIPARTIT
2.15 FIPARTIT-ACK
2.16 NACK
-
Registre a un joc
Flux dades joc
Interrupció joc per Gol
Interrupció joc per Falta
Finalització mitja part
Finalització del joc
1. Protocol Client-Servidor
1. El servidor escoltarà peticions per dos ports: el 10000 TCP per als
missatges de control i el 10000 UDP per als missatges de joc.
2. El client escoltarà per dos ports, un TCP (per rebre els missatges de
control iniciats pel servidor) i un UDP (per rebre els missatges d'estat
del joc) a lliure elecció, que en la fase de registre a un partit,
comunicarà al servidor per a que aquest li pugui enviar els missatges de
44
estat del joc.
3. Es recomanació que el servidor enviï els missatges d'estat del joc
a raó de 1 estat cada 40ms (o de 25 estats per segon).
4. El protocol està basat en missatges de text.
1.1 Interacció Client-Servidor TCP/IP - Registre a una joc
1. El client envia un missatge CONNECTA al servidor. El missatge contindrà
el Port (TCP i UDP) que farà servir el client on el servidor enviarà els
missatges de control (TCP) i els d'estat durant el joc (UDP).
2. El servidor envia un missatge CONNECTA-ACK al client. El missatge
contindrà el Id (número aleatori entre de 0x0 a 0xFFF que assigna el
servidor al client per identificar-ne posteriorment els missatges UDP de
moviment) i els paràmetres de la física: FLM (força lineal màxima),
FAM (força angular màxima), PR (pes robot), PP (pes pilota),
FT (fregament terra), VLM (velocitat lineal màxima) i VAM (velocitat
angular màxima).
Si el servidor no pot atendre satisfactòriament al missatge CONNECTA
(ex: ja hi han dos client connectats, el joc està en un estat en el
que no s'espera un CONNECTA, etc), el servidor contestarà al client
amb un missatge NACK i s'atura la interacció.
En aquest moment el client està connectat al servidor. Quan el servidor
rebi les CONNECTA de dos clients, reanudarà el flux de missatges:
3. El servidor envia un missatge ESTATINI al client. El missatge contindrà
el Equip (número entre 1 i 2, més endavant es veu el significat),
el Atacant (número entre 0 i 1, indicant si el client comença el joc
com atacant o defensor), 11 x Posició (posició d'inici de joc de la
pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors
equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2).
4. El client envia un missatge INICI al servidor. El missatge contindrà el
Id assignat en el missatge CONNECTA-ACK. Indica que està preparat per
començar el joc.
En aquest moment s'inicia pel port UDP l'enviament dels paquets d'estat del
joc i de moviments de jugadors.
Exemple:
Client
Servidor
Client
v
v
v
|
|
|
|\
| _____________/|
| \_________
|/
CONNECTA
|
|
CONNECTA\
|\
|
|
\ | \____________ |
|
\ | CONNECTA-ACK\|
|
\|
Espera
| _____________/|
.
|/ CONNECTA-ACK |
.
Espera
|
.
.
/|\
.
. ___________/ | \___________ .
. / ESTATINI
|
ESTATINI \ .
./
|
\.
|
|
|
.\_____________ |
/.
.
INICI
\| ____________/ .
Espera
|/
INICI
.
.
|
Espera
45
.
Comença flux UDP
.
1.2 Interacció Client-Servidor UDP/IP - Flux dades joc
1. El servidor envia un missatge ESTAT al client. El missatge contindrà
el Cronòmetre (temps que es porta de joc en milisegons),
11 x Posició (posició en joc de la pilota i dels 10 robots jugadors,
és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1,
6-10 = jugadors equip amb el codi Equip 2).
2. El client envia un missatge MOVIMENT al servidor. El missatge contindrà
5 x Moviment (forces lineals i angulars de cada un dels robots jugadors).
Exemple:
Client
Servidor
Client
v
v
v
|
/|\
|
| ___________/ | \___________ |
| /
ESTAT
|
ESTAT
\ |
|/
|
\|
|
|
|
|\_____________ |
/|
|
MOVIMENT \| ____________/ |
|
|/ MOVIMENT
|
|
|
|
1.3 Interacció Client-Servidor TCP/IP - Interrupció joc per Gol
1. El client envia un missatge GOL al servidor.
2. El servidor envia un missatge GOL-ACK als clients. El missatge
contindrà l'Equip (codi Equip que ha marcat el gol), Marcador (resultat
del partit en aquest moment, indicant gols equip 1 - gols equip 2).
Si el servidor no pot atendre satisfactòriament al missatge GOL
(ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera
un GOL-ACK, etc), el servidor contestarà al client amb un missatge NACK
i s'atura la interacció.
En aquest moment el joc està aturat, tot i que el cronòmetre continua, i
per tant el servidor descarta qualsevol paquet que arribi al port UDP i
els clients queden a la espera de la reanudació del joc.
3. El servidor envia un missatge ESTATINI al client. El missatge contindrà
el Equip (número entre 1 i 2, més endavant es veu el significat),
el Atacant (número entre 0 i 1, indicant si el client comença el joc
com atacant o defensor), 11 x Posició (posició d'inici de joc de la
pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors
equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2).
4. El client envia un missatge XIULET al servidor.
En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat del
joc i de moviments de jugadors.
Exemple:
Client
Àrbitre
Servidor
v
v
|
|
|\
|
| \___________ |
|
GOL
\ |
|
\|
Client
v
|
|
|
|
|
46
| _____________/|\_____________ |
|/
GOL-ACK
|
GOL-ACK
\|
Espera
|
Espera
.
/|\
.
. ___________/ | \___________ .
. / ESTATINI
|
ESTATINI \ .
./
|
\.
Espera
|
|
.
|
/. Àrbitre
.
| ____________/ .
.
|/
XIULET
.
.
|
.
.
Comença flux UDP
.
1.4 Interacció Client-Servidor TCP/IP - Interrupció joc per Falta
1. El client envia un missatge FALTA al servidor.
2. El servidor envia un missatge FALTA-ACK als clients. El missatge
contindrà l'Equip (codi Equip al qui se li ha xiulat la falta) i el
Tipus (tipus de falta comesa).
Si el servidor no pot atendre satisfactòriament al missatge FALTA
(ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera
un FALTA, etc), el servidor contestarà al client amb un missatge NACK
i s'atura la interacció.
En aquest moment el joc està aturat, tot i que el cronòmetre continua, i
per tant el servidor descarta qualsevol paquet que arribi al port UDP i
els clients queden a la espera de la reanudació del joc.
3. El servidor envia un missatge ESTATINI al client. El missatge contindrà
el Equip (número entre 1 i 2, més endavant es veu el significat),
el Atacant (número entre 0 i 1, indicant si el client comença el joc
com atacant o defensor), 11 x Posició (posició d'inici de joc de la
pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors
equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2).
4. El client envia un missatge XIULET al servidor.
En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat
de joc i de moviments de jugadors.
Exemple:
Client
Servidor
Client
v
v
v
|
|
|
Àrbitre |\
|
|
| \___________ |
|
|
FALTA
\ |
|
|
\|
|
| _____________/|\_____________ |
|/
FALTA-ACK | FALTA-ACK
\|
Espera
|
Espera
.
/|\
.
. ___________/ | \___________ .
. / ESTATINI
|
ESTATINI \ .
./
|
\.
Espera
|
|
.
|
/. Àrbitre
.
| ____________/ .
.
|/
XIULET
.
.
|
.
.
Comença flux UDP
.
47
1.5 Interacció Client-Servidor TCP/IP - Finalització mitja part
1. El client envia un missatge FIPART al servidor.
2. El servidor envia un missatge FIPART-ACK als clients.
Si el servidor no pot atendre satisfactòriament al missatge FIPART
(ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera
un FIPART, etc), el servidor contestarà al client amb un missatge NACK
i s'atura la interacció.
En aquest moment el joc està aturat, i el cronòmetre de joc es posa a 0,
per tant el servidor descarta qualsevol paquet que arribi al port UDP i
els clients queden a la espera de la reanudació del joc.
3. El servidor envia un missatge ESTATINI al client. El missatge contindrà
el Equip (número entre 1 i 2, més endavant es veu el significat),
el Atacant (número entre 0 i 1, indicant si el client comença la part
com atacant o defensor), 11 x Posició (posició d'inici de joc de la
pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors
equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2).
4. El client envia un missatge XIULET al servidor.
En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat de
joc i de moviments de jugadors.
Exemple:
Client
Servidor
Client
v
v
v
|
|
|
Àrbitre |\
|
|
| \___________ |
|
|
FIPART
\ |
|
|
\|
|
| _____________/|\_____________ |
|/ FIPART-ACK | FIPART-ACK \|
Espera
|
Espera
.
/|\
.
. ___________/ | \___________ .
. / ESTATINI
|
ESTATINI \ .
./
|
\.
Espera
|
|
.
|
/. Àrbitre
.
| ____________/ .
.
|/
XIULET
.
.
|
.
.
Comença flux UDP
.
1.6 Interacció Client-Servidor TCP/IP - Finalització de joc
1. El client envia un missatge FIPARTIT al servidor.
2. El servidor envia un missatge FIPARTIT-ACK als clients.
Si el servidor no pot atendre satisfactòriament al missatge FIPARTIDA
(ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera
un FIPARTIT, etc), el servidor contestarà al client amb un missatge NACK
i s'atura la interacció.
En aquest moment el joc està aturat, i el cronòmetre continua es posa a 0,
per tant el servidor descarta qualsevol paquet que arribi al port UDP i
els clients queden a la espera de la reanudació del joc.
48
3. El servidor envia un missatge ESTATINI al client. El missatge contindrà
el Equip (número entre 1 i 2, més endavant es veu el significat),
el Atacant (número entre 0 i 1, indicant si el client comença la part
com atacant o defensor), 11 x Posició (posició d'inici de joc de la
pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors
equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2).
4. El client envia un missatge XIULET al servidor.
En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat de
joc i de moviments de jugadors.
Exemple:
Client
Servidor
Client
v
v
v
|
|
|
Àrbitre |\
|
|
| \___________ |
|
|
FIPART
\ |
|
|
\|
|
| _____________/|\_____________ |
|/ FIPART-ACK | FIPART-ACK \|
|
|
|
2. Especificació dels missatges
2.1 CONNECTA
Descripció:
Flux:
Transport:
Interacció:
Petició de connexió
Del client al servidor
TCP/IP
1.1
+----------+
|CONNECTA\n|
|Port: p
|
+----------+
on p
= número de fins a 4 xifres sense zeros davant i codificat en
hexadecimal amb les lletres en majúscules
2.2 CONNECTA-ACK
Descripció:
Flux:
Transport:
Interacció:
Confirmació d'una petició de connexió
Del servidor al client
TCP/IP
1.1
+--------------+
|CONNECTA-ACK\n|
|Id: iii\n
|
|FLM: flm\n
|
|FAM: fam\n
|
|PR: pr\n
|
|PP: pp\n
|
|FT: ft\n
|
|VLM: vlm\n
|
|VAM: vam
|
+--------------+
on iii
= número de fins a 3 xifres sense zeros davant i codificat en
hexadecimal amb les lletres en majúscules
flm, fam, pr, pp, ft, vlm i vam = número sense zeros davant i codificat
en hexadecimal amb les lletres en majúscules
49
2.3 ESTATINI
Descripció:
Flux:
Transport:
Interacció:
Estat inicial
Del servidor al client
TCP/IP
1.1, 1.3
+-------------------+
|ESTATINI\n
|
|Equip: e\n
|
|Atancant: a\n
|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va |
+-------------------+
on e
a
xxx
yyy
ooo
vl
va
<- pilota
<- porter equip 1
<jugador 1 equip 1
<jugador 2 equip 1
<jugador 3 equip 1
<jugador 4 equip 1
<- porter equip 2
<jugador 1 equip 2
<jugador 2 equip 2
<jugador 3 equip 2
<jugador 4 equip 2
= número, 1 ó 2
= número, 0 = no atacant, 1 = atacant
= pos_x (0 .. 2499), número de fins a 3 xifres sense zeros davant i
codificat en hexadecimal amb les lletres en majúscules
= pos_y (0 .. 1799), número de fins a 3 xifres sense zeros davant i
codificat en hexadecimal amb les lletres en majúscules
= orientació (0 .. 359), número de fins a 3 xifres sense zeros
davant i codificat en hexadecimal amb les lletres en majúscules
= velocitat lineal, valor absolut de la velocitat lineal, número
sense zeros davant i codificat en hexadecimal amb les lletres en
majúscules
= velocitat angular, valor absolut de la velocitat angular, número
sense zeros davant i codificat en hexadecimal amb les lletres en
majúscules
2.4 INICI
Descripció:
Flux:
Transport:
Interacció:
Indica preparat per iniciar el joc
Del client al servidor
TCP/IP
1.1
+-------+
|INICI\n|
|Id: iii|
+-------+
on iii
= número de fins a 3 xifres sense zeros davant i codificat en
hexadecimal amb les lletres en majúscules
2.5 ESTAT
Descripció:
Flux:
Transport:
Interacció:
Mostra l'estat d'un joc en un instant de temps concret
Del servidor al client
UDP/IP
1.2
+-------------------+
|tttt\n
|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
<- pilota
<- porter equip 1
<jugador 1 equip 1
<jugador 2 equip 1
50
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va\n|
|xxx,yyy,ooo,vl,va |
+-------------------+
<jugador 3 equip
<jugador 4 equip
<- porter equip 2
<jugador 1 equip
<jugador 2 equip
<jugador 3 equip
<jugador 4 equip
1
1
2
2
2
2
on tttt = cronòmetre, temps de joc en milisegons, número de fins a 4
xifres sense zeros davant i codificat en hexadecimal amb les
lletres en majúscules
xxx = pos_x (0 .. 2499), número de fins a 3 xifres sense zeros davant i
codificat en hexadecimal amb les lletres en majúscules
yyy = pos_y (0 .. 1799), número de fins a 3 xifres sense zeros davant i
codificat en hexadecimal amb les lletres en majúscules
ooo = orientació (0 .. 359), número de fins a 3 xifres sense zeros
davant i codificat en hexadecimal amb les lletres en majúscules
vl
= velocitat lineal, valor absolut de la velocitat lineal, número
sense zeros davant i codificat en hexadecimal amb les lletres en
majúscules
va
= velocitat angular, valor absolut de la velocitat angular, número
sense zeros davant i codificat en hexadecimal amb les lletres en
majúscules
2.6 MOVIMENT
Descripció:
Flux:
Transport:
Interacció:
Accions de moviment aplicats als robots jugadors
Del client al servidor
UDP/IP
1.2
+----------+
|tttt,iii\n|
|fl,fa\n
|
|fl,fa\n
|
|fl,fa\n
|
|fl,fa\n
|
|fl,fa
|
+----------+
<- porter
<jugador
<jugador
<jugador
<jugador
1
2
3
4
on tttt = segell de temps de l'últim missatge de ESTAT rebut, número de
fins a 4 xifres sense zeros davant i codificat en hexadecimal amb
les lletres en majúscules
iii = número de fins a 3 xifres sense zeros davant i codificat en
hexadecimal amb les lletres en majúscules
fl, fa = números sense zeros davant in codificat en hexadecimal amb les
lletres en majúscules
2.7 GOL
Descripció:
Flux:
Transport:
Interacció:
L'àrbitre indica gol
Del client al servidor
TCP/IP
1.3
+---+
|GOL|
+---+
2.8 GOL-ACK
Descripció:
Flux:
Transport:
Interacció:
Confirmació missatge de l'àrbitre indicant gol
Del servidor al client
TCP/IP
1.3
51
+-------------+
|GOL-ACK\n
|
|Marcador: g-g|
+-------------+
on g
= gols equip 1, caràcter '-', gols equip 2, números sense zeros
davant i codificat en hexadecimal amb les lletres en majúscules
2.9 XIULET
Descripció:
Flux:
Transport:
Interacció:
L'àrbitre indica reanudar el joc
Del client al servidor
TCP/IP
1.3, 1.4
+------+
|XIULET|
+------+
2.10 FALTA
Descripció:
Flux:
Transport:
Interacció:
L'àrbitre indica falta
Del client al servidor
TCP/IP
1.4
+----------+
|FALTA\n
|
|Equip: e\n|
|Tipus: t |
+----------+
on e
t
= número, 1 ó 2
= número, 0 = Penalty, 1 = Free-Kick, 2 = Free-Ball
2.11 FALTA-ACK
Descripció:
Flux:
Transport:
Interacció:
Confirmació missatge de l'àrbitre indicant falta
Del servidor al client
TCP/IP
1.4
+-----------+
|FALTA-ACK\n|
|Equip: e\n |
|Tipus: t
|
+-----------+
on e
t
= número, 1 ó 2
= número, 0 = Penalty, 1 = Free-Kick, 2 = Free-Ball
2.12 FIPART
Descripció:
Flux:
Transport:
Interacció:
L'àrbitre indica fi de la primera part
Del client al servidor
TCP/IP
1.5
+------+
|FIPART|
+------+
2.13 FIPART-ACK
Descripció:
Flux:
Transport:
Confirmació missatge de l'àrbitre indica fi de la primera part
Del servidor al client
TCP/IP
52
Interacció:
1.5
+----------+
|FIPART-ACK|
+----------+
2.14 FIPARTIT
Descripció:
Flux:
Transport:
Interacció:
L'àrbitre indica fi del joc
Del client al servidor
TCP/IP
1.6
+--------+
|FIPARTIT|
+--------+
2.15 FIPARTIT-ACK
Descripció:
Flux:
Transport:
Interacció:
Confirmació missatge de l'àrbitre indica fi de joc
Del servidor al client
TCP/IP
1.6
+------------+
|FIPARTIT-ACK|
+------------+
2.16 NACK
Descripció:
Flux:
Transport:
Interacció:
Confirmació negativa a un missatge de control
Del servidor al client
TCP/IP
1.1, 1.3, 1.4, 1.5
+----+
|NACK|
+----+
53
Descargar