Determinar la ubicación final para el movimiento de IA en grupos en un RTS 2D


8

He escrito un juego de estrategia en tiempo real (una demostración para una especie de motor de juego, en realidad) en el que la interacción básica del usuario con el juego es seleccionar un grupo de soldados y luego hacer clic derecho en el mapa para moverlos a la ubicación especificada. Esto está en JavaScript y puedes jugar con él aquí ( código ).

Ignorando el problema de cómo se mueven los soldados desde su ubicación actual hasta su destino, mi pregunta es sobre determinar cuál es su destino real. Esto es lo que he probado hasta ahora:

  • Intento 1: Indique a todos los soldados seleccionados que se muevan a las coordenadas en las que hizo clic el mouse. Esto tiene el extraño comportamiento de que todos los soldados se agruparán alrededor del objetivo de forma antinatural.
  • Intento 2: Encuentre las coordenadas promedio de todos los soldados seleccionados, luego encuentre el desplazamiento desde ese punto central para cada soldado, y finalmente traduzca ese desplazamiento alrededor de las coordenadas del mouse. Esto funciona bien, excepto que si los soldados seleccionados están muy separados, no se acercarán al objetivo.
  • Intento 3: Construya una cuadrícula alrededor de las coordenadas del mouse y coloque a cada soldado seleccionado en una celda de la cuadrícula. Si cada soldado llega a su celda asignada, esto funciona muy bien. Sin embargo, los soldados se asignan a las celdas de la cuadrícula en el orden en que se generaron los soldados, por lo que a veces chocan (es decir, todos los soldados en el lado derecho intentarán ir al lado izquierdo), lo que parece antinatural.
  • Intento 4: use una cuadrícula como antes, pero primero ordene a los soldados por ubicación para que se alineen con sensatez, es decir, si hizo clic debajo del grupo, los soldados en la parte inferior del grupo terminarán en la parte inferior de la cuadrícula cuando llegar a su destino Esto funciona bastante bien, pero a veces hay fallas y no estoy seguro de por qué.

Aquí está la función que determina las coordenadas de destino:

function moveSelectedSoldiersToMouse() {
  var w = 0, h = 0, selected = [];
  // Get information about the selected soldiers.
  myTeam.soldiers.forEach(function(soldier) {
    if (soldier.selected) {
      selected.push(soldier);
      w += soldier.width;
      h += soldier.height;
    }
  });
  var numSelected = selected.length, k = -1;
  if (!numSelected) return;
  // Build a grid of evenly spaced soldiers.
  var sqrt = Math.sqrt(numSelected),
      rows = Math.ceil(sqrt),
      cols = Math.ceil(sqrt),
      x = Mouse.Coords.worldX(),
      y = Mouse.Coords.worldY(),
      iw = Math.ceil(w / numSelected), // grid cell width
      ih = Math.ceil(h / numSelected), // grid cell height
      wg = iw*1.2, // width of gap between cells
      hg = ih*1.2; // height of gap between cells
  if ((rows-1)*cols >= numSelected) rows--;
  w = iw * cols + wg * (cols-1); // total width of group
  h = ih * rows + hg * (rows-1); // total height of group
  // Sort by location to avoid soldiers getting in each others' way.
  selected.sort(function(a, b) {
    // Round to 10's digit; specific locations can be off by a pixel or so
    var ax = a.x.round(-1), ay = a.y.round(-1), bx = b.x.round(-1), by = b.y.round(-1);
    return ay - by || ax - bx;
  });
  // Place the grid over the mouse and send soldiers there.
  for (var i = 0; i < rows; i++) {
    for (var j = 0; j < cols; j++) {
      var s = selected[++k];
      if (s) {
        var mx = x + j * (iw+wg) - w * 0.5 + s.width * 0.5,
            my = y + i * (ih+hg) - h * 0.5 + s.height * 0.5;
        // Finally, move to the end destination coordinates
        s.moveTo(mx, my);
      }
    }
  }
}

Puede pegar esta función en la consola de JavaScript de su navegador al ver la demostración y jugar con ella para cambiar el comportamiento de los soldados.

Mi pregunta es: ¿hay una mejor manera de determinar la ubicación del objetivo para que se mueva cada soldado?


Algo llamado "flocado" puede ser muy útil para usted y puede proporcionarle el tipo de funcionalidad que está buscando. Pruebe: processing.org/examples/flocking.html o simplemente google "flocado" o "Boids". Eso puede ponerlo en la dirección correcta.
Dean Knight

2
Relacionado: gamedev.stackexchange.com/questions/44361 Diría que los "problemas técnicos " que estás experimentando son de unidades que están tratando de moverse a una posición que ya ha sido reclamada. Asegúrate de que la posición en la que se están moviendo no sea el objetivo de otra unidad, y debes tener resultados bastante decentes.
MichaelHouse

@DeanKnight, soy consciente de cómo funcionan los comportamientos de flocado, pero eso gobierna cómo los bots llegan del punto A al punto B, no qué es el punto B.
IceCreamYou

@ Byte56: gracias por el enlace. Literalmente, no estoy colocando unidades en ranuras de cuadrícula: en la implementación no hay forma de que varias unidades se dirijan al mismo lugar. Parece que el problema es más que la clasificación a veces se confunde.
IceCreamYou

1
Otra idea: Enjambre Pathfinding . En este caso, no le daría a cada unidad un punto final diferente; simplemente haría que se detuvieran cuando no quedara camino hacia el punto final (porque todas las demás unidades están en el camino), o no se detenga en absoluto y deje que la detección de colisiones haga su trabajo.
BlueRaja - Danny Pflughoeft

Respuestas:


2

Aquí están mis sugerencias sobre sus ideas:

Intento 1: para solucionar esta situación, podría implementar la idea "lo suficientemente cercana" que planteó Spencer. Haría algo como dibujar una burbuja alrededor del punto final, que crece en función de una proporción del número y el tamaño de las unidades que ya están en él. Digamos que la burbuja comienza el tamaño de una unidad, luego, cuando llega la primera, el radio se duplica para las siguientes dos unidades, etc.

Intento 2: una solución para esto sería tomar la distancia promedio del grupo entre sí, luego reducir la distancia de los valores atípicos a eso, para que el grupo termine más agrupado de lo que originalmente eran (la métrica podría ser más corta / más largo que el promedio, lo que sea que lo haga parecer decente, o posiblemente establezca un tamaño de formulario máximo basado en el número / tamaño de tropas nuevamente) Lo único por lo que tendrá que preocuparse es cuando altera el camino de un valor atípico, usted ' tendría que verificar y asegurarse de que no interfiera con los otros caminos

Intento 3: Has mejorado este en el intento 4

Intento 4: Suena como si este funcionara bien si encuentras cualquier problema que lo esté descartando. Sin embargo, recomendaría jugar con spahes que no sean solo una formación de cuadrícula, para que el movimiento se vea un poco más natural, a menos que vaya por un realismo / estilo militar, en cuyo caso podría ser bueno tenerlos "formados "antes de moverse, pero eso podría ser molesto para el jugador después de un tiempo.

El intento 4 parece ser el más cercano a eliminar el comportamiento de fresado en su problema, pero en términos de mantener el movimiento fluyendo sin ningún ajuste que no sea necesario, mi favorito probablemente sería el intento 2.

Pero como una solución completamente diferente, puede tener dos tipos de objetos cuando se trata de encontrar rutas; cada unidad, así como un objeto invisible "escuadrón".

Escuadrón: construyes el objeto del escuadrón en el centro del grupo, como las otras soluciones, y usas tu búsqueda de ruta para dirigirlo hacia el objetivo.

Unidades: las unidades ignoran el objetivo por completo y, en su lugar, utilizan la búsqueda de ruta para mantenerse dentro de una cierta distancia (o formación, o cualquier otra métrica que haga que el movimiento se vea mejor) del objeto del escuadrón.

Esto separa los diferentes aspectos de la búsqueda de rutas y le permite ajustar cualquiera de los lados de forma aislada para tener más control sobre cómo se ve.


Gran respuesta. Gracias por las nuevas ideas. El enfoque de Escuadrón + Unidad es interesante, probablemente requiere que las unidades puedan moverse más rápido en el modo "ponerse al día"
IceCreamYou

Sí, una solución es establecer la velocidad de movimiento del objeto "escuadrón" a un poco por debajo del máximo que las unidades individuales pueden mover, para permitirles cambiar de lugar si es necesario sin quedarse atrás.
David M

2

El intento 3 podría funcionar, pero necesita un poco de refinamiento.

Piensa en el concepto de formación (tu grilla es un comienzo). Una formación debe tener una ubicación (es decir, las coordenadas del clic o el soldado / edificio objetivo) y una rotación (esto podría ser fijo, aleatorio o determinista). La formación debe tener el mismo número de posiciones que el número de soldados seleccionados.

Un ejemplo simple de formación puede ser un círculo alrededor del objetivo. Espacie las posiciones equitativamente alrededor y aumente el radio del círculo para adaptarse a todos los soldados sin chocar.

El siguiente problema es decidir qué soldado camina a qué posición en la formación. Una solución simple podría ser hacer que cada soldado se mueva a la posición más cercana a él. Si ese ya está 'elegido' por otro soldado, toma la siguiente posición más cercana, etc.

Las formaciones pueden volverse bastante interesantes. A continuación se muestra una imagen de la 'formación de cuerno de toro' utilizada con gran éxito por Shaka the Zulu . (La imagen proviene de TotalWar Formation Mod )

formación de cuerno de toro


"El siguiente problema es decidir qué soldado camina a qué posición en la formación". En realidad, ese es todo el problema de esta pregunta. :) Votaron por la sugerencia de una formación circular en lugar de una cuadrícula, pero eso no es efectivo para más de unos pocos soldados, y mover soldados al lugar más cercano a ellos causa más conflictos que mi solución anterior de ordenar las unidades por ubicación.
IceCreamYou

0

Al hacer clic en el usuario, dibuje un vector de cada soldado en la ubicación en la que se hizo clic. Obtenga el ángulo de vector promedio de los vectores dibujados para cada soldado y mueva a cada soldado la longitud de su vector individual en esa dirección con el mismo ángulo. Esto debería dar la apariencia de que las unidades se mueven en formación hasta el punto y deben evitar que las unidades se agrupen.

Si desea que las unidades salgan de la formación, puede apuntar el ángulo de cada soldado directamente a la ubicación en la que se hizo clic. Sin embargo, sin colisión, las unidades comenzarán a converger. Para contrarrestar esto, agregue la colisión y obligue a las unidades a dejar de moverse una vez que estén "lo suficientemente cerca" del punto en el que se hizo clic. Las primeras unidades que lleguen estarán exactamente en el punto y las últimas en llegar deberán dirigirse a dejar de moverse una vez que estén lo suficientemente cerca o haya pasado un cierto tiempo.

Puede calcular la longitud de la ruta y la velocidad de la unidad para determinar cuándo debe llegar una sola unidad y luego forzar a la unidad a dejar de moverse si excede ese tiempo en una cierta cantidad. Tendrás que jugar un poco con ese número.


La solución vectorial que está sugiriendo es la misma que en mi intento 2 anterior. Uno de los requisitos de esta pregunta es que las unidades seleccionadas pueden no estar en una formación.
IceCreamYou

Y escribí sobre una solución en la que no se moverían en formación. (2º párrafo)
Spencer
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.