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?
8
if not dead position += 1
ou 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.Réponses:
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.
la source
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:
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)).
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.
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.
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.
la source