¿Cómo implementar un enemigo inteligente en un shoot-em-up?

13

Imagina un shoot-em-up muy simple, algo que todos sabemos:

shoot-em-up 1

Eres el jugador (verde). Su movimiento está restringido al Xeje. Nuestro enemigo (o enemigos) está en la parte superior de la pantalla, su movimiento también está restringido al Xeje. El jugador dispara balas (amarillas) al enemigo.

Me gustaría implementar una IA para el enemigo que debería ser realmente buena para evitar las balas de los jugadores. Mi primera idea fue dividir la pantalla en secciones discretas y asignarles pesos:

shoot-em-up ponderado

Hay dos pesos: el "peso de la bala" (gris) es el peligro impuesto por una bala. Cuanto más cerca esté la bala del enemigo, mayor será el "peso de la bala" ( 0..1donde 1 es el mayor peligro). Los carriles sin bala tienen un peso de 0. El segundo peso es el "peso de distancia" (verde lima). Para cada carril agrego el 0.2costo de movimiento (este valor es un poco arbitrario ahora y podría modificarse).

Luego simplemente agrego los pesos (blanco) y voy al carril con el peso más bajo (rojo). Pero este enfoque tiene una falla obvia, porque puede pasar por alto los mínimos locales, ya que el lugar óptimo para ir sería simplemente entre dos balas entrantes (como se indica con la flecha blanca).

Entonces, esto es lo que estoy buscando:

destrucción total de shoot-em-up

  • Debería encontrar un camino a través de la tormenta de balas, incluso cuando no haya un lugar que no imponga la amenaza de una bala.
  • El enemigo puede esquivar balas de manera confiable eligiendo una solución óptima (o casi óptima).
  • El algoritmo debería ser capaz de tener en cuenta la velocidad de movimiento de la bala (ya que podrían moverse con diferentes velocidades).
  • Formas de ajustar el algoritmo para que se puedan aplicar diferentes niveles de dificultad (tontos a enemigos súper inteligentes).
  • El algoritmo debe permitir diferentes objetivos, ya que el enemigo no solo quiere evadir las balas, sino que también debe poder disparar al jugador. Eso significa que las posiciones donde el enemigo puede disparar al jugador deben preferirse al esquivar balas.

Entonces, ¿cómo abordarías esto? Al contrario de otros juegos de este género, me gustaría tener solo unos pocos, pero muy "hábiles" enemigos en lugar de masas de enemigos tontos.

bummzack
fuente
2
¿Has considerado usar algo como comportamientos de dirección? Hay uno para evitar obstáculos específicamente: red3d.com/cwr/steer/Obstacle.html
Tetrad
@Tetrad He pensado en los comportamientos de dirección ... también porque se pueden cambiar muy bien, como "tratar de disparar al jugador" y cuando el peligro está por delante, cambiar a "evadir". Me temo que una versión de evasión 1D (eso es con lo que básicamente estoy lidiando) será demasiado tonta para tomar buenas decisiones. Aunque podría estar equivocado.
bummzack

Respuestas:

8

Creo que su idea básica es sólida, pero no es analógica. Necesita un campo de valor analógico que se ejecute en la pantalla. Entonces, gradiente de difusión 1D, del cual puede derivar un valor en un punto exacto en esa línea, sobre la marcha. Los gradientes de difusión son baratos y pueden ser utilizados por múltiples enemigos a la vez, ya que describen el entorno y no la vista de la entidad (un poco como la iluminación de radiosidad), probablemente por qué ha optado por el enfoque que tiene en su pregunta . Este gradiente debe ser relativamente suave, para evocar un movimiento orgánico del enemigo, y obviamente se actualiza como lo hace tu estado de juego. Quizás media móvil ?

El gradiente debe combinar:

  • Proximidad
  • Velocidad
  • Ancho de bala
  • (opcionalmente) Posición de los objetivos (jugadores)

Para esquivar, tenemos que poder encontrar una solución con precisión siempre que exista una solución . Tal es el caso siempre que haya un espacio lo suficientemente pequeño como para que el enemigo pueda esquivarlo. Es decir, solo puede hacer lo que puede hacer, por lo que el enfoque de gradiente no funcionará peor que cualquier otro enfoque en este sentido, diría.

El gradiente de difusión debería empujar al enemigo hacia los óptimos locales (que son los picos en el gráfico) con menos imperativo para moverse, cuanto más cerca estemos de un mínimo local, por lo tanto, un efecto de retorno decreciente al esquivar. Esto abre la puerta a una toma de decisiones más inteligente sobre cuándo el enemigo tiene una buena apertura para disparar.

Si la necesidad de disparar es mayor que la necesidad de moverse, entonces hágalo; su código también puede determinar esto por cuánto difieren. Puede implementar esto como parte del gráfico base, en cuyo caso la posición del jugador reduce los valores circundantes en el gráfico (suponiendo que los enemigos gravitan hasta el punto más bajo), que combina toda la toma de decisiones en un gráfico, o puede mantener el " gráfico "deseo de disparar" separado del gráfico principal "deseo de esquivar", que le ofrecerá un control más directo.

IRL, no me molestaría en esquivar un proyectil hasta que esté dentro de una distancia que sé, a mi velocidad de esquiva máxima, está empezando a ser difícil de evitar. Experiencia de primera mano al tirar piedras como muchacho. Una bala a x distancia que viaja a velocidad y tiene la misma clasificación de peligro que una bala a 2x distancia que viaja a 2y. Por lo tanto, esto debe tenerse en cuenta correctamente.

Las formas de ajustar el algoritmo para la dificultad del enemigo incluyen

  • Introducir una latencia en las actualizaciones del gráfico (Born Too Slow)
  • Introducir imprecisiones aleatorias y localizadas en el gráfico
  • simplemente no hacer que los enemigos obedezcan lo que el gráfico les dice, a lo largo de una secuencia de actualizaciones (digamos de 1 a 10 cuadros) debido a la simple pereza de la IA.

Nuevamente, puedes implementar todos los factores en un gráfico (menos control y menos útil para múltiples enemigos), o en varios gráficos que miras juntos para obtener los resultados (más modular, probablemente funciona mejor para múltiples enemigos). Es difícil ser más específico, ya que hay muchas direcciones en las que puede tomar este enfoque.

Ingeniero
fuente
1
Querido Nick Seguí adelante e implementé una pequeña versión de prueba de ese comportamiento en flash y estoy muy satisfecho con el resultado (las viñetas se generan aleatoriamente). Actualmente estoy usando 3 gradientes, uno para amenaza, costo de movimiento y uno estático para los bordes (para que los bordes de la pantalla sean menos deseables). Se visualizan en la aplicación flash. Siento que con algunos ajustes puedo lograr muy buenos resultados y también tener en cuenta otros pesos como las posiciones de disparo. Muchas gracias amigo.
bummzack
1
Hola @bummzack, es un compañero de placer, ¡es una pequeña demostración genial! Su visión del problema era nueva para mí y parecía interesante. ¡Me alegra ver que funciona! Me alegro de ayudarlo, y gracias por compartir.
Ingeniero
7

Esto puede ser visto como un problema de ruta. En lugar de pensar en cómo el malvado evita las balas, imaginando que las balas son estáticas y el malvado debe viajar a través de ellas hasta la parte inferior de la pantalla.

    E    
B  B**B
  B***B  B
 B***B   B
B**B** B 
 B**B**BB
B*****B B
      P

E = enemigo
B = bala
P = jugador
* = opciones de ruta a la parte inferior de la pantalla

Una vez que el malo ha trazado un camino exitoso, solo necesita dar el siguiente paso cada vez. Probablemente ya existan algunos buenos algoritmos para encontrar rutas como este. Si el baddy se mueve a la misma velocidad que las balas, podría ser un algoritmo de ejemplo;

Comience en el baddy y marque posiciones seguras en espacios vacíos a la izquierda, directamente debajo y debajo a la derecha. Luego considere cada espacio seguro que acaba de crear y repita. Si en algún momento encuentra que no hay espacios seguros debajo, marque el espacio como no seguro y retroceda.

Qwerky
fuente
1
Enfoque interesante Sin embargo, me temo que esto es algo costoso ya que el entorno cambia muy rápido y es difícil usar algoritmos comunes de búsqueda de rutas, ya que funcionan mejor con "mapas" discretos.
bummzack
No debería ser demasiado costoso, no olvides que solo tienes que calcular la fila inferior cada turno, no tienes que volver a calcular todo.
Qwerky
@bummzack Environment no es "rápido", al menos, en términos de computadora. Para los desarrolladores de juegos, debes entender que casi todos los juegos están basados ​​en pasos, es solo el tamaño de ese paso. Pero, en cada paso, se pueden hacer cálculos, por lo que la solución de Qwerky es lo que necesita.
Deele
En realidad, estoy de acuerdo con @bummzack. Si bien este enfoque es lógicamente sólido, será más costoso que el enfoque 1D propuesto en la pregunta. Puede ser una optimización prematura, pero creo que ese enfoque es mucho más elegante. Vea mi respuesta para una explicación sobre eso.
Ingeniero
2
Esta es probablemente la respuesta correcta , pero no exactamente realista . En el tiempo que le toma al enemigo elaborar un camino, el campo puede tener otro conjunto de balas que invalidan el camino por completo, lo que significa que volver a calcular el camino sería imprescindible. Y el recálculo es una perra . Además, su idea de propagarse hacia atrás hasta un punto en que sea seguro lo hace aún más caro. @ Nick Wiggill No creo que sea una optimización prematura, solo una buena previsión para garantizar que no te patees en la entrepierna.
Ray Dey