¿Cómo puedo escalar el número y el desafío de los enemigos en una ola de ataque a medida que avanza el juego?

9

Actualmente estoy haciendo un juego de defensa donde los enemigos aparecerán y atacarán al ejército del jugador. Es similar a un juego de Tower Defense, excepto que solo hay un nivel. Los enemigos seguirán engendrando hasta que finalmente el usuario muera o acumule un ejército lo suficientemente grande como para eliminar a cualquier enemigo que se genere instantáneamente (con suerte, será lo suficientemente desafiante como para que esto no suceda).

Con lo que estoy luchando en este momento es cómo hacer que este juego se vuelva cada vez más difícil y la probabilidad de que aparezca un enemigo básicamente llegue al 100%.

Hasta ahora tengo algo similar a lo siguiente

if(Math.random() < 1 - (1/elapsed_time) && spawnTimer <= 0 ){
    spawnEnemy()
    spawnTimer = rand(); // random number between 1 and 3
}

Pero parece demasiado uniforme para empezar. Por el momento solo estoy engendrando un tipo de enemigo, la idea es que los enemigos más duros se generan a medida que pasa el tiempo también.

También creo que necesito aleatorizar un spawnTimerpoco más y hacer que sea más rápido a medida que pasa el tiempo, pero simplemente no puedo entender cómo debería ser mi lógica para toda esta sección. ¿Alguien puede ayudar con una idea aproximada de este tipo de fórmula?

Actualmente estoy usando JavaScript para escribir el juego, pero obviamente se trata más del concepto.

TommyBs
fuente
¿Qué es el tiempo transcurrido? ¿Es lo que pasó hasta ahora? ¿Con qué frecuencia llamas a esta condición?
AturSams
Hola, lo siento, el tiempo transcurrido es el tiempo transcurrido desde que comenzó el juego y esto se llama en mi ciclo de actualización de juegos () que se basa en window.requestAnimationFrame
TommyBs

Respuestas:

3

No es probable que la función que elija sea adecuada para su propósito. Primero, si sigue esta ruta, una condición aleatoria fallida debería ocasionar un retraso antes de la próxima vez que tire los dados. Además, es poco probable que mantener el temporizador de generación dentro de un rango constante sea bueno para su objetivo.

Sea threshun umbral de dificultad que creas que es alto. Lo usamos más tarde para decidir cuándo reducir el ritmo al que el juego se vuelve más difícil.

Deja que ratesea ​​la cantidad de monstruos que quieres que entren cada minuto (o ronda).

Sea GROWTH_RATEla tasa en la que aumenta la dificultad (por ahora será 0.2).

Digamos que comienzas con rate = 10. Ahora el jugador mató a los 5monstruos para que puedas aumentar la tasa GROWTH_RATE * 5 = 1.0y la nueva rate = 11.

Cómo implementar una condición que generará ratemonstruos cada minuto:

Temporizador desove conjunto a un número entre 0.5a 1.0 multiplied by 60 seconds or-tiempo de ida and divided bytasa . Also leave a0.25` posibilidad de que ningún monstruo se genera cuando el temporizador llega a 0 y el tiempo es aleatorio nuevo.

Si ratealguna vez llega threshnecesita reducir la velocidad. Ahora, en lugar de aumentar ratemediante GROWTH_RATE, podría aumentarlo 1 / math.sqrt(rate). De esa forma, el jugador no será destruido instantáneamente en la configuración más difícil.

Puede restablecer threshpara ser alrededor del 80% del momento rateen que el jugador perdió el juego.

Si deseas aleatorizar la fuerza del monstruo, ten cuidado con el temporizador. Por ejemplo, si decide que player-score(determinado por los monstruos muertos hasta ahora) se utiliza para determinar la fuerza máxima de un monstruo que podría generar, se puede hacer algo como esto: max-monster-strength = player-score / 1000. Entonces aleatorizar un floato doubleentre 0.0a 1.0y multiplicar el resultado por sí mismo.

float monster_power = Math.random();
monster_power *= monster_power; // Multiply result by itself
    // Makes hard monsters less frequent than weak ones
monster_power *= max_monster_strength;

Ahora, cuando aleatorices el temporizador, probablemente deberías tener en cuenta el nivel de potencia. Por ejemplo, podrías multiplicar el resultado del temporizador por la raíz cuadrada del siguiente poder de monstruos.

spawn_timer *= math.sqrt(monster_power);
AturSams
fuente
6

Hay muchas opciones, dos con su configuración actual:

  • Haz enemigos más duros
  • Genera más enemigos (ya sea con más frecuencia o múltiples a la vez)

Luego más con características adicionales:

  • Los enemigos comienzan a causar diferentes tipos de daño, y el jugador debe defenderse de manera diferente contra cada uno. Por ejemplo, ataques a distancia, magia, etc.
  • Los enemigos comienzan a defenderse contra diferentes tipos de daño. El jugador debe construir múltiples tipos de dispositivos de daño para contrarrestar. Por ejemplo, el jugador comienza con ataques de flecha y ataques de bala de cañón. Un enemigo que tiene una resistencia muy alta a las flechas genera, por lo que el jugador debe asegurarse de haber equilibrado sus ataques.

En cuanto a hacer una curva de dificultad, realmente no hay una respuesta correcta. Se necesitarán muchas pruebas de juego y ajustes para hacerlo bien. Dependerá de cuánto dure el juego y de lo difícil que quieras que sea. Le sugiero que use Excel o un sitio como WolframAlpha y vea qué tipo de curva crean las diferentes funciones. Pruebe aumentos exponenciales, aumentos lineales, etc. Encuentre uno que funcione para usted.

MichaelHouse
fuente
Gracias por las ideas, pero creo que la respuesta seleccionada es más de lo que necesito. Pero definitivamente me has dado más para pensar y he votado tu respuesta
TommyBs
2

En lugar de tener un número fijo de enemigos (uno) engendrados con una probabilidad variable, podrías darle la vuelta y tener un número variable de enemigos engendrados con una probabilidad fija.

static const double SPAWN_CHANCE_ON_DIFFICULTY_1 = 0.01;

for (int i = 0; i < currentDifficulty; i++) {
   if(Math.random() < SPAWN_CHANCE_ON_DIFFICULTY_1 ){
       spawnEnemy()
   }
}

En el nivel de dificultad 1, tendrá un 1% de probabilidad de generar un enemigo por tic.

En el nivel de dificultad 1000, generará hasta 1000 enemigos, cada uno con una probabilidad separada del 1%. Esto significa que en promedio se generarán 10 por marca, pero también podría ser más o menos. Existe la posibilidad de que se genere un número muy diferente de 10 a la vez, tal vez incluso todos los 1000. pero ese es un evento muy poco probable debido a cómo funciona la probabilidad (compárese: Ley de números grandes ).

Cuando agregas más enemigos diferentes con diferentes comportamientos y estadísticas, tal vez quieras que algunos de los enemigos más difíciles solo comiencen a aparecer en dificultades más altas e incluso con una baja densidad al principio. Para hacer esto, puede agregar un modificador de dificultad que se resta de la dificultad actual. De esa forma, el enemigo no se generará antes de que se alcance ese nivel de dificultad e incluso entonces solo con una menor probabilidad al principio:

for (EnemyType enemyType: allEnemyTypes) {
    for (int i = 0; i < currentDifficulty - enemyType.getDifficulty(); i++) {
        if(Math.random() < enemyType.spawnChance() ){
            spawnEnemy(enemyType);
        }
    }
}
Philipp
fuente
1
Esto es estimulante, pero debe optimizarse antes de usarse. Por ejemplo, podrías usar Math.random () una vez para decidir cuántos enemigos engendrar. Si quieres dejar una pequeña posibilidad de una gran cantidad de enemigos, puedes implementar la "Distribución Normal" de manera más eficiente. stackoverflow.com/questions/2325472/…
AturSams