Gérez un grand nombre d'acteurs indépendants en temps réel


8

Je travaille sur un jeu de stratégie en temps réel à grande échelle - idéalement avec des milliers d'unités actives à la fois - mais j'ai du mal à gérer toutes les unités à la fois sans qu'il devienne incroyablement lent. Le problème est qu'il faut un certain temps pour mettre à jour les positions et les états de tout à chaque pas de temps. Connaissez-vous des modèles / méthodologies / conseils de conception pour atténuer cela?


1
bien que votre question puisse sembler beaucoup différente, vous pouvez utiliser le même algorithme que celui expliqué ici . il n'est pas nécessaire d'utiliser le traitement parallèle dans cet algorithme, avec un seul, vous obtiendrez une amélioration des performances.
Ali1S232

La mise à jour en parallèle n'aidera pas si, par exemple, vous avez deux cœurs et la mise à jour de la moitié d'entre eux prend déjà trop de temps, mais si vous avez plusieurs cœurs disponibles et que vous ne les utilisez pas déjà, cela devrait aider. Idéalement, vous souhaiterez une solution qui ne vous oblige pas à mettre à jour chaque unité à chaque pas de temps, ou un moyen de simplifier la mise à jour afin que vous puissiez. Quelle est la taille de ce pas de temps? C'est indépendant des cadres de dessin, non?
Blecki

4
La première chose que vous pouvez faire est de reconnaître que votre vitesse n'a rien à voir avec la quantité d'acteurs indépendants. Cela a à voir avec ce que font ces acteurs . Je peux avoir cent mille mises à jour d'acteurs indépendants> 60fps si tout ce qu'ils font est if not dead position += 1ou une mise à jour d'acteur <1fps si ça va dans une boucle infinie. Certains de vos algorithmes - certaines parties de ce que font ces unités - sont tout simplement trop chers comme vous les faites et c'est tout. Il existe probablement de nombreuses causes différentes et de nombreuses stratégies différentes pour chacune.
doppelgreener

Réponses:


4

Il y a deux choses distinctes à considérer lors de la mesure et de l'optimisation des performances d'un système d'entités à si grande échelle.

Au bas niveau, vous avez la représentation physique de vos entités qui se résume à utiliser des dispositions de stockage efficaces comme SoA (structures de tableaux) pour réduire le coût d'itération et de mise à jour de toutes les entités actives.

Au niveau supérieur, vous avez la logique de prise de décision, la logique générale du jeu, l'IA et la recherche de chemin. Ce sont toutes des tâches qui ont en commun de ne pas avoir à s'exécuter au même taux de mise à jour que votre rendu.

Comme vous obtiendrez une durée de trame inégale si vous adoptez l'approche naïve de simplement effectuer ces tâches toutes les N trames, il est généralement avantageux d'amortir le coût sur plusieurs trames.

Si la tâche est de nature incrémentielle, vous pouvez exécuter une partie de l'algorithme à chaque trame et utiliser des résultats partiels dans vos mises à jour.

Si la tâche est en grande partie monolithique mais séparable par entité, vous pouvez effectuer cette tâche pour un sous-ensemble de vos entités de jeu par image, en effectuant une rotation entre elles de manière circulaire. Cela a l'avantage de réduire la complexité de choses comme l'orientation et l'IA, car tout le monde n'essaie pas d'agir en même temps.

Dans le RTS tactique à grande échelle sur lequel j'ai travaillé, nous nous sommes concentrés sur des structures de données robustes pour interroger la représentation de bas niveau dans les algorithmes de haut niveau, pour trouver les voisins des entités de jeu. Le processus de mise à jour de bas niveau a agi selon les intentions fournies par la simulation de haut niveau à mise à jour lente, et s'est finalement soldé par une simulation de particules bon marché, évoluant bien en milliers.


+1. Mes pensées exactement, en particulier en réduisant la logique aux groupes gérés qui ne sont traités que tous les quelques cycles, tous ces groupes pouvant être échelonnés pour un traitement uniforme.
Ingénieur

1

pour autant que je me souvienne, vous aurez toujours moins de 10 000 unités par match. il n'y a pas de jeu dont je me souvienne avec plus que ce nombre, bien que la terre d'empire puisse aller jusqu'à 14000 sans un piratage, mais personne n'arrivera jamais à ce point. donc avoir juste un tableau statique de 10 000 objets semble être plus que nécessaire.

comme vous le savez, itérer plus de 10000 objets n'est pas un gros problème, mais cela peut prendre beaucoup de temps si votre algorithme s'exécute plus lentement que O (n). par exemple, si vous essayez de vérifier tous les deux objets pour la détection de collision, cela prendra du temps O (n ^ 2), ce qui signifie beaucoup de temps. vous devez donc briser vos algorithmes en quelque sorte. passons en revue un exemple d'algorithme pour tout ce à quoi je peux penser en ce moment:

  1. détection de collision: pour chaque algorithme de détection de collision, vous devez vérifier tous les deux objets, mais vous pouvez éliminer certaines vérifications lors du démarrage des boucles. comme je l'ai suggéré dans les commentaires, vous pouvez utiliser le même algorithme donné pour cette question . il n'est pas nécessaire d'utiliser plusieurs threads ou quoi que ce soit, même avec un thread et 4 régions, vous réduirez vos vérifications de n * (n-1) à 4 * (n / 4) ((n-1) / 4), et en optimisant le nombre de régions, vous pouvez obtenir des résultats encore meilleurs. Je pense qu'en utilisant les meilleures régions numériques, vous pouvez même accéder à O (n log (n)).

  2. vous devez générer un chemin pour chaque objet en mouvement. le système habituel que j'ai vu jusqu'à présent est une chose très simple: chaque fois que le joueur ordonne aux unités de se déplacer quelque part, l'ordinateur calcule son chemin, après cela, à chaque cycle, si l'objet peut se déplacer, il se déplace s'il ne peut pas sauter ce cycle. il n'y a rien de spécial. bien que vous puissiez également changer les algorithmes donnés ici pour réduire vos appels de recherche de chemin et avoir un cheminement en temps réel pour chaque groupe d'unités, mais ce n'est vraiment pas nécessaire.

  3. vous devez vérifier si une balle ou une bombe ou quelque chose de similaire frappe l'une des unités: vous pouvez utiliser les mêmes régions que vous avez créées pour la détection de collision ici.

  4. pour sélectionner des unités, vous pouvez également utiliser les mêmes régions.

en général, je suggère d'utiliser un tableau statique (ou un tableau dynamique avec une taille réservée) de 10 000 ou 20 000 au maximum. puis utilisez quelque chose autour de 10 ou 15 boucles chacune itérant sur toutes les unités. c'est un vrai grand tableau contenant toutes les unités de tous les joueurs. ainsi, chaque index contient à la fois des données sur le propriétaire et le type d'unité. vous pouvez également créer d'autres tableaux pour chaque joueur. dans chaque index de ces tableaux secondaires, vous n'aurez qu'à stocker des pointeurs vers des objets du tableau principal.

si vous avez d'autres questions, ajoutez des commentaires pour les ajouter à ma réponse.


Je me souviens d'avoir plus de 40 000 dans Empires Dawn of the Modern World :). Dommage que le moteur de rendu ne puisse garder que 1000 à l'écran avant de commencer à disparaître, mais le reste du jeu a bien fonctionné :).
deceleratedcaviar

@daniel: ce n'est pas grave, les généraux n'avaient pas de limites sur le nombre d'unités. Je donnais juste une certaine mesure d'un bon nombre d'unités sur lesquelles baser mes calculs mathématiques. 40000 et 10000 ne sont pas très différents l'un de l'autre.
Ali1S232
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.