Planificación del movimiento

La planificación del movimiento te ayuda a mover una instancia de un punto a otro esquivando otras instancias que pudiera encontrarse por el camino (por ejempo, paredes). Resulta imposible dar funciones generales que funcionen en cualquier situación. Así mismo, las operaciones necesarias para calcular un camino libre de colisiones consumen bastantes recursos, así que debes usar estas funciones con criterio. Ten todo esto en cuenta cuando uses las siguientes funciones.

Game Maker dispone de diferentes formas de planificar el movimiento. La más simple consiste en hacer que una instancia de un paso hacia la posición final, intentando ir en línea recta pero tomando otra dirección si esto último resulta imposible. Estas funciones deben usarse en el evento step de la instancia y se corresponden a las acciones ya comentadas:

mp_linear_step(x,y,stepsize,checkall) Esta función hace que la instancia de un paso hacia la posición (x,y). La longitud del paso se indica con el parámetro stepsize. Si la instancia ya ha llegado a esa posición no se moverá. Si checkall es true la instancia se parará cuando choque con una instancia de cualquier objeto. Si es false, sólo se parará al chocar con un objeto sólido. Esta función no propone un camino alternativo, simplemente se parará si encuentra un obstáculo. La función devuelve si se ha alcanzado el destino.
mp_linear_step_object(x,y,stepsize,obj) Igual que la anterior, pero esta vez sólo se tienen en cuenta las instancias del objeto obj. obj puede ser un objeto o una id de una instancia particular.
mp_potential_step(x,y,stepsize,checkall) Igual que las anteriores, pero en este caso la instancia intentará esquivar los obstáculos que encuentre. Cuando la instancia se choque con un obstáculo cambiará su dirección para tratar de esquivar el objeto, moviéndose alrededor de él. Puede que no siempre se consiga llegar a la meta, pero la función siempre intentará acercar lo más posible a la instancia. Devuelve true si se llega a la meta.
mp_potential_step_object(x,y,stepsize,obj) ) Igual que la anterior, pero esta vez sólo se tienen en cuenta las instancias del objeto obj. obj puede ser un objeto o una id de una instancia particular.
mp_potential_settings(maxrot,rotstep,ahead,onspot) La función anterior hace su trabajo usando un número de parámetros que pueden ser cambiados con esta función. El método funciona como sigue: primero la instancia intenta moverse en línea recta hacia la meta. Para ello, mira un número de pasos adelante para ver si hay algún obstáculo. Este número de pasos corresponde al valor ahead (por defecto 3). Reduciendo este valor la instancia comenzará a cambiar su dirección más tarde si encuentra un obstáculo. Aumentándolo cambiará antes de dirección. Si detectamos una colisión, la función mira a la derecha y a la izquierda para encontrar un camino libre. Esto se realiza en pasos de tamaño rotstep (por defecto 10). Reduciéndolo conseguimos que la instancia tenga más posibilidades para moverse pero la función será más lenta. El parámetro maxrot (por defecto 30) indica cuánto puede cambiar como máximo la dirección en un paso. Así que aunque pueda moverse en línea recta hacia la meta no lo hará si debe girar más de lo indicado por este parámetro. Aumentándolo conseguimos que la instancia pueda girar más en cada paso, haciendo que sea más fácil encontrar un camino aunque éste será menos uniforme. Disminuyendo su valor el camino será más suave pero la instancia realizará giros más largos, haciendo que a veces no pueda llegar exactamente a la meta. Cuando la instancia no se puede mover en ninguna dirección el comportamiento dependerá del valor de onspot. Si onspot es true la instancia rotará en su posición la cantidad indicada por maxrot. Si es false se parará (esto es útil para coches, por ejemplo, pero reduce las posibilidades de encontrar un camino hacia la meta).

Observa que el acercamiento potencial sólo usa información local. Así que sólo encontrará un camino si la información es suficiente para determinar la dirección correcta. Por ejemplo, normalmente no podrá encontrar el camino para escapar de un laberinto.

El segundo tipo de funciones calcula un camino libre colisiones. Una vez que el camino se ha calculado puedes asignárselo a la instancia para que se mueva hacia la meta como si fuera un path normal que tú hubieras creado. El cálculo del camino tarda un poco pero una vez hecho la ejecución del path es muy rápida. Por supuesto, esto es válido si la situación no cambia (por ejemplo, si los obstáculos se mueven). Entonces necesitarás volver a calcular el path. De nuevo, estas funciones pueden fallar en algunas circunstancias. Estas funciones sólo están disponibles en la versión registrada de Game Maker.

Las dos primeras funciones usan el acercamiento por movimiento lineal y potencial que se usan en las funciones anteriores.

mp_linear_path(path,xg,yg,stepsize,checkall) Calcula un path en línea recta para la instancia desde su posición hasta (xg,yg) usando el paso especificado en stepsize. Usa pasos como en la función mp_linear_step(). El path indicado debe existir con anterioridad a la llamada de la función y será sobreescrito por el nuevo path (consulta el capítulo sobre cómo crear y destruir paths). La función devuelve si se ha encontrado un path. Si no consigue encontrar un camino, la función devolverá un path hasta la posición donde la instancia quedó bloqueada.

mp_linear_path_object(path,xg,yg,stepsize,obj) Igual que la anterior, pero esta vez sólo se tienen en cuenta las instancias del objeto obj. obj puede ser un objeto o una id de una instancia particular.
mp_potential_path(path,xg,yg,stepsize,factor,checkall) Esta función calcula un camino para instancia desde su posición actual y orientación hasta (xg,yg) usando el paso especificado en stepsize e intentando evitar colisionar con los obstáculos. Utiliza pasos potenciales como la función mp_potential_step() y los parámetros se pueden configurar con mp_potential_settings(). El path indicado debe existir con anterioridad a la llamada de la función y será sobreescrito por el nuevo path (consulta el capítulo sobre cómo crear y destruir paths). La función devolverá si se ha encontrado un camino. Para evitar que la función continúe calculando para siempre debes especificar un factor mayor que 1. La función se detendrá y devolverá un mensaje de error si no puede  encontrar un camino que sea más corto que la distancia del origen a la meta multiplicada por factor. Un factor de 4 es normalmente suficiente pero si crees que la instancia tendrá un camino largo puedes aumentarlo. Si la función falla se crea el camino en dirección a la meta pero la instancia no llegará  la meta.
mp_potential_path_object(path,xg,yg,stepsize,factor,obj) Igual que la anterior, pero esta vez sólo se tienen en cuenta las instancias del objeto obj. obj puede ser un objeto o una id de una instancia particular.

 

Las demás funciones usan un mecanismo mucho más complejo basado en rejillas (un algoritmo A*). Tiene más sexito a la hora de encontrar caminos y hacerlos más cortos, pero requiere más trabajo por tu parte. Además, también puede fallar en algunas ocasiones. El funcionamiento es como sigue: primero situamos una rejilla sobre la parte del cuarto afectada. Puedes usar si quieres usar una rejilla fina (más lento) o más espaciada. Después, determinamos las celdas de la rejilla ocupadas por objetos relevantes (usando colisión precisa o la caja de contorno) y marcamos estas celdas como prohibidas. Así que una celda estará prohibida si parte de un obstáculo la está ocupando. Finalmente especificamos la posición inicial y final, que deben estar en celdas libres de la rejilla y la función calcula el camino más corto entre ellas. El camino irá de centro a centro de las celdas libres. Así que las celdas deben ser lo suficientemente grandes como para que la instancia entre totalmente dentro de ellas. Ahora puedes asignar el path a una instancia y hacer que lo siga.

Este sistema es muy potente (se usa en muchos juegos profesionales) pero requiere que lo planifiques con cuidado. Debes determinar la zona del cuarto sobre la que situar la rejilla y el tamaño de las celdas con la mayor precisión posible. También debes decidir qué objetos deben tomarse en cuenta y si es necesaria la colisión precisa o no. Todos estos parámetros afectan de manera muy notable a la eficiencia del método.

En particular, el tamaño de las celdas es crucial. Recuerda que las celdas deben lo suficientemente grandes como para que la instancia que se mueve entre totalmente dentro de ellas (ten cuidado con la posición del origen de la instancia y recuerda que puedes mover el path para hacer que el centro del objeto coincida con el centro de la celda). Por otro lado, cuanto menores sean las celdas más caminos diferentes podrás encontrar. Si haces las celdas demasiado grandes puede que unos pocos objetos ocupen todas las celdas cerrando todos los caminos posibles.

Las funciones para el método de rejilla son:

mp_grid_create(left,top,hcells,vcells,cellwidth,cellheight) Esta función crea la rejilla. Devuelve un índice que debe ser usado en las demás funciones. Puedes crear y mantener varias rejillas al mismo tiempo. left y top indican la posición de la esquina superior izquierda de la rejilla y hcells y vcells indican el número de celdas horizontales y verticales respectivamente. Finalmente, cellwidth y cellheight indican la anchura y altura de las celdas.

mp_grid_destroy(id) Destruye la rejilla indicada y libera la memoria usada. No olvides llamar a esta función cuando no necesites usar más la rejilla.
mp_grid_clear_all(id) Marca todas las celdas como libres.
mp_grid_clear_cell(id,h,v) Marca la celda indicada como libre (la primera celda es la 0,0).
mp_grid_clear_rectangle(id,left,top,right,bottom) Marca como libres todas las celdas que intersectan el rectángulo definido en coordenadas absolutas del cuarto.
mp_grid_add_cell(id,h,v) Marca ls celdas indicadas como prohibidas.
mp_grid_add_rectangle(id,left,top,right,bottom) Marca todas las celdas que intersectan el rectángulo como prohibidas.
mp_grid_add_instances(id,obj,prec) Marca todas las celdas que intersectan una instancia del objeto indicado como prohibidas. También puedes especificar una id de una instancia concreta, o la palabra clave all para indicar todas las instancias. prec indica si hay que usar colisión precisa (sólo funcionará si en el sprite de la instancia está activada la misma opción).
mp_grid_path(id,path,xstart,ystart,xgoal,ygoal,allowdiag) Calcula el path a través de la rejilla. El path indicado debe existir con anterioridad a la llamada de la función y será sobreescrito por el nuevo path (consulta el capítulo sobre cómo crear y destruir paths). xstart e ystart indican el comienzo del path y xgoal e ygoal las coordenadas de la meta. allowdiag indica si se permiten movimientos diagonales entre celdas o sólo horizontales y verticales. La función devuelve si consiguió calcular un path (observa que el path es independiente de la instancia actual).
mp_grid_draw(id) Esta función dibuja la rejilla marcando las celdas libres y prohibidas (muy útil para buscar errores).