Comment puis-je mesurer le nombre et le défi des ennemis dans une vague d'attaque à mesure que le jeu progresse?

9

Je fais actuellement un jeu de défense où les ennemis apparaîtront et attaqueront l'armée du joueur. C'est similaire à un jeu Tower Defense, sauf qu'il n'y a qu'un seul niveau. Les ennemis continueront d'apparaître jusqu'à ce que l'utilisateur meure ou qu'il amasse une armée suffisamment grande pour éliminer tout ennemi qui apparaît instantanément (j'espère que ce sera assez difficile pour que cela ne se produise pas).

Ce avec quoi je me bats en ce moment, c'est comment rendre ce jeu de plus en plus difficile et la probabilité qu'un ennemi se reproduise atteigne finalement 100%.

Jusqu'à présent, j'ai quelque chose de similaire au suivant

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

Mais cela semble trop uniforme pour commencer. Pour le moment, je n'engendre qu'un type d'ennemi, l'idée étant que les ennemis les plus coriaces apparaissent également au fil du temps.

Je pense également que je dois randomiser un spawnTimerpeu plus mes données et les rendre plus rapides à mesure que le temps avance, mais je n'arrive pas à comprendre à quoi devrait ressembler ma logique pour toute cette section. Quelqu'un peut-il nous aider avec une idée approximative de ce type de formule?

J'utilise actuellement javascript pour écrire le jeu, mais il s'agit évidemment davantage du concept.

TommyBs
la source
Quel est le temps écoulé? Est-ce cela qui s'est passé jusqu'à maintenant? À quelle fréquence appelez-vous cette condition?
AturSams
Salut, ouais désolé le temps écoulé est le temps écoulé depuis le début du jeu et cela est appelé dans mon cycle de mise à jour des jeux () qui est basé sur window.requestAnimationFrame
TommyBs

Réponses:

3

La fonction que vous avez choisie n'est probablement pas adaptée à votre objectif. Premièrement, si vous suivez cette route, une condition aléatoire échouée devrait entraîner un délai avant la prochaine fois que vous lancez les dés. En outre, il est peu probable que le maintien du minuteur d'apparition dans une plage constante soit bon pour votre objectif.

Soit threshun seuil de difficulté que vous pensez être élevé. Nous l'utilisons plus tard pour décider quand ralentir le rythme auquel le jeu devient plus difficile.

Soit ratela quantité de monstres que vous souhaitez voir apparaître à chaque minute (ou tour).

Soit GROWTH_RATEle taux d'augmentation de la difficulté (pour l'instant, ce sera le cas 0.2).

Disons que vous commencez par rate = 10. Maintenant, le joueur a tué des 5monstres afin que vous puissiez augmenter le taux de GROWTH_RATE * 5 = 1.0et le nouveau rate = 11.

Comment implémenter une condition qui générera des ratemonstres à chaque minute:

Régler la minuterie de spawn à un nombre entre 0.5à 1.0 multiplied by 60 seconds ortemps ronde and divided bytaux . Also leave a0.25` chance que aucun monstre est donné naissance lorsque la minuterie atteint 0 et le temps est aléatoire à nouveau.

Si ratejamais threshvous atteignez, vous devez ralentir. Maintenant, au lieu d'augmenter ratede GROWTH_RATE, vous pouvez l'augmenter de 1 / math.sqrt(rate). De cette façon, le joueur ne sera pas détruit instantanément dans le cadre le plus difficile.

Vous pouvez réinitialiser threshà environ 80% du rateniveau auquel le joueur a perdu la partie.

Si vous souhaitez randomiser la force du monstre, faites attention au chronomètre. Par exemple, si vous décidez que player-score(déterminé par des monstres tués à ce jour) sera utilisé pour déterminer la force maximale d'un monstre qui pourrait se reproduire, vous pouvez faire quelque chose comme ceci: max-monster-strength = player-score / 1000. Ensuite, randomisez un floatou doubleentre 0.0à 1.0et multipliez le résultat par lui-même.

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;

Maintenant, lorsque vous randomisez la minuterie, vous devez probablement prendre en compte le niveau de puissance. Par exemple, vous pouvez multiplier le résultat du chronomètre par la racine carrée de la puissance du prochain monstre.

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

Il y a beaucoup d'options, deux avec votre configuration actuelle:

  • Rendre les ennemis plus durs
  • Générez plus d'ennemis (soit plus souvent, soit plusieurs à la fois)

Plus encore avec des fonctionnalités supplémentaires:

  • Les ennemis commencent à infliger différents types de dégâts et le joueur doit se défendre différemment contre chacun. Par exemple, attaques à distance, magie, etc.
  • Les ennemis commencent à se défendre contre différents types de dégâts. Le joueur doit construire plusieurs types de dispositifs infligeant des dégâts pour contrer. Par exemple, le joueur commence par des attaques de flèches et des attaques de boulets de canon. Un ennemi qui a une résistance très élevée aux flèches apparaît, donc le joueur doit s'assurer qu'il a équilibré ses attaques.

Quant à faire une courbe de difficulté, il n'y a vraiment pas de bonne réponse. Il faudra beaucoup de tests de jeu et de réglages pour bien faire les choses. Cela dépendra de la durée du jeu et de la difficulté que vous souhaiterez. Je vous suggère d'utiliser Excel ou un site comme WolframAlpha et de voir quel type de courbe différentes fonctions créent. Essayez des augmentations exponentielles, des augmentations linéaires, etc. Trouvez celle qui vous convient.

MichaelHouse
la source
Merci pour les idées mais je pense que la réponse choisie correspond davantage à ce dont j'ai besoin. Mais vous m'avez certainement donné plus matière à réflexion et j'ai voté pour votre réponse
TommyBs
2

Au lieu d'avoir un nombre fixe d'ennemis (un) apparaissant avec une probabilité variable, vous pouvez le retourner et faire apparaître un nombre variable d'ennemis avec une probabilité fixe.

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()
   }
}

Au niveau de difficulté 1, cela aura 1% de chances de faire apparaître un ennemi par tick.

Au niveau de difficulté 1000, il fera apparaître jusqu'à 1000 ennemis, chacun avec une chance distincte de 1%. Cela signifie qu'en moyenne 10 apparaîtront par tick, mais cela pourrait aussi être plus ou moins. Il est possible qu'un nombre très différent de 10 apparaisse en même temps, peut-être même tous les 1000. mais c'est un événement très improbable en raison du fonctionnement de la probabilité (comparer: Loi des grands nombres ).

Lorsque vous ajoutez plus d'ennemis différents avec des comportements et des statistiques différents, vous voudrez peut-être que certains des ennemis les plus coriaces commencent uniquement à apparaître sur des difficultés plus élevées et même avec une faible densité au début. Pour ce faire, vous pouvez ajouter un modificateur de difficulté qui est soustrait de la difficulté actuelle. De cette façon, l'ennemi n'apparaîtra pas avant que ce niveau de difficulté soit atteint et même alors avec seulement une chance inférieure au début:

for (EnemyType enemyType: allEnemyTypes) {
    for (int i = 0; i < currentDifficulty - enemyType.getDifficulty(); i++) {
        if(Math.random() < enemyType.spawnChance() ){
            spawnEnemy(enemyType);
        }
    }
}
Philipp
la source
1
C'est stimulant mais il faut l'optimiser avant de l'utiliser. Par exemple, vous pouvez utiliser Math.random () une fois pour décider du nombre d'ennemis à faire apparaître. Si vous souhaitez laisser une moindre chance à un grand nombre d'ennemis, vous pouvez implémenter la "Distribution normale" plus efficacement. stackoverflow.com/questions/2325472/…
AturSams