• No results found

6.2 Result Analysis of SC MPC Simulations

6.2.1 Constant Load System Performance

En este subapartado vamos a comentar cómo se implementa un cliente que mueva de forma aleatoria a sus unidades y tenga la opción de gráficos en 3D.

Nuestro cliente va a estar formado por tres ficheros:

 waypoints_main.c

 ClientEventHandler.h

 ClientEventHandler.c

El fichero waypoints_main.c contiene la función void add_options(), la función int main(int

argc, char **argv) y la clase Looper.

La función void add_options(), simplemente sirve para incluir las opciones que nuestro cliente va a considerar válidas, en nuestro caso –usegfx para el modo gráfico en 3D.

La función main realiza todas las comprobaciones e inicializaciones necesarias para poder ejecutar el cliente. Entre ellas, comprueba si el modo gráfico está o no activo para realizar las correspondientes gestiones.

Por último, la clase Looper contiene una estructura ClientAIState (definida en el fichero

ClientEventHandler.h), un constructor y el método void loop().

El constructor inicializa el atributo state de tipo ClienteAIState con la estructura

ClientAIState que recibe por parámetros. Dicha estructura se explica en detalle más adelante.

El método loop se va a ejecutar hasta que el juego termine o el cliente finalice (es llamado desde el main). Dicho método busca mensajes entrantes procedentes del servidor, si los hay llama a los handlers y si no se duerme un milisegundo. Además, realiza gestiones del modo gráfico.

El fichero ClientEventHandler.h contiene la definición de la estructura ClientAIState y la definición de la clase ClientEventHandler.

Sergio Núñez Covarrubias Anexo C. Tutorial de iniciación a ORTS

BlackRose: Un modelo de razonamiento

con incertidumbre en juegos de estrategia 176


La estructura ClientAIState contiene la información necesaria para conocer el estado actual del juego. Los elementos que forman dicha estructura son los siguientes:

 gsm es un puntero a GameStateModule, gracias al cual podemos conocer información relativa al estado del juego.

 gfxm es un puntero a GfxModule, gracias al cual se actualiza la imagen gráfica del juego. Si el modo gráfico 3D no está activado, gfxm vale 0.

 just_drew es una variable de tipo bool que indica si hay que dibujar en el instante actual.

 quit es una variable de tipo bool que indica si hay que salir o no del juego.

 error es una variable de tipo bool que indica si se ha producido o no un error.

 el constructor inicializa los punteros gsm y gfxm con los parámetros que recibe, además de inicializar just_drew, quit y error a false.

La clase ClientEventHandler contiene un constructor, una referencia a una estructura

ClientAIState, un objeto random y los prototipos de los métodos bool handle_event(const Event &e) y void compute_actions().

El constructor inicializa la referencia a la estructura con el parámetro que recibe.

El fichero ClientEventHandler.c contiene la implementación de los métodos bool

handle_event(const Event &e) y void compute_actions().

El primero recibe eventos y los trata. Diferencia entre tres tipos diferentes:

 STOP_MSG indica que hay que salir del juego.

 READ_ERROR_MSG indica que se ha producido un error y por ello hay que salir del juego.

 VIEW_MSG indica que ha recibido un mensaje vista, lo que quiere decir que se ha actualizado el estado del juego. Por ello, se llama al método void compute_actions(),

Sergio Núñez Covarrubias Anexo C. Tutorial de iniciación a ORTS

BlackRose: Un modelo de razonamiento

con incertidumbre en juegos de estrategia 177


se mandan las acciones al servidor y se realizan unas gestiones de los gráficos, a la vez que se imprimen por pantalla unas estadísticas del estado actual.

El método void compute_actions() (aproximadamente línea 86) es el que determina las acciones de cada una de las unidades del cliente. Por ello, es el único método que va a ser diferente al segundo cliente que vamos a implementar. En este método se concentra toda la inteligencia artificial del cliente.

Nuestro método para el primer cliente es muy sencillo, ya que únicamente mueve a todos sus objetos a un punto elegido de forma aleatoria.

Podríamos decir que el método se divide en dos partes. En la primera, obtenemos la información necesaria sobre el estado actual del juego. Dicha información es la siguiente:

 Nuestro id de jugador. Se obtiene mediante la siguiente sentencia:

const sint4 cid = game.get_client_player();

cid es la variable que va a contener el id del jugador después de ejecutar el método get_client_player mediante el objeto game. Dicho objeto es de tipo Game y hay que actualizarlo en cada iteración31 mediante la siguiente sentencia:

const Game &game = state.gsm->get_game();

game es una referencia al propio juego, mediante la cual podemos obtener información relativa al estado del juego (mapa, objetos, etc.). Por otro lado, state es el atributo público de tipo estructura ClientAIState de la clase ClientEventHandler.

 Todos nuestros objetos. Se obtienen mediante la siguiente sentencia:

const Game::ObjCont &objs = game.get_objs(cid);

objs es una referencia a un vector de punteros, en el que cada uno apunta a un objeto concreto. cid es el id del jugador del que se quieren obtener todos sus objetos. Al igual que la referencia al juego (game), los objetos hay que obtenerlos









31


Cada
vez
que
se
ejecuta
el
método
compute_actions,
es
decir,
cada
vez
que
cambia
el
estado
del
juego
después
de
que
se


hayan
procesado
las
últimas
instrucciones
enviadas
al
servidor.


Sergio Núñez Covarrubias Anexo C. Tutorial de iniciación a ORTS

BlackRose: Un modelo de razonamiento

con incertidumbre en juegos de estrategia 178


en cada iteración porque pueden cambiar de una iteración a otra (debido a que se hayan creado nuevos objetos, haya cambiado la información del algún objeto concreto, etc.).

 El ancho del mapa, medido en puntos. Se obtiene mediante la siguiente sentencia:

const sint4 points_x = map.get_width() * game.get_tile_points();

points_x contiene el resultado de multiplicar el número de tiles del mapa (a lo

ancho) por el número de puntos/tile. Mediante la referencia al juego, podemos obtener cuantos puntos forman una tile32. Por otro lado, map es una referencia al

mapa actual del juego que se obtiene mediante la siguiente sentencia:

const Map<GameTile> &map = game.get_map();

Por ultimo, el método get_width devuelve el número tiles que forman el ancho del mapa.

 El largo del mapa, medido en puntos. Se obtiene mediante la siguiente sentencia:

const sint4 points_y= map.get_height() * game.get_tile_points();

points_y contiene el resultado de multiplicar el número de tiles del mapa (a lo largo)

por el número de puntos/tile. El método get_height devuelve el número tiles que forman el largo del mapa.

Como podemos observar, toda esta información se obtiene gracias a la referencia del juego (game) y como ella se tiene que obtener/actualizar en cada iteración, toda la información con la que está relacionada también se tiene que actualizar en cada una de las iteraciones.

La segunda parte, consta de un bucle for para cada uno de nuestros objetos. Dentro del bucle, comprobamos que el objeto actual exista, esté en juego, dentro del mapa y no esté muerto. Si es así, preguntamos si nuestro objeto está quieto o en movimiento, ya que si está en movimiento hay que dejarle que llegue a su destino. Si está quieto, calculamos unas nuevas coordenadas de









32


Se
supone
que
las
tiles
son
cuadradas
y
que
el
método
get_tile_points
devuelve
el
número
de
puntos
(a
lo
largo
o
a
lo


ancho)
que
forman
una
tile.


Sergio Núñez Covarrubias Anexo C. Tutorial de iniciación a ORTS

BlackRose: Un modelo de razonamiento

con incertidumbre en juegos de estrategia 179


forma aleatoria y le asignamos la acción move. Todo esto se puede ver en el código adjunto, que está detalladamente comentado.