Récemment, je travaille sur un jeu de tir 2D rapide et je suis tombé sur un problème majeur. Détection de collision. Bien sûr, cela fonctionne, mais c'est très lent. Mon objectif est: Avoir beaucoup d'ennemis à l'écran et les empêcher de se toucher. Tous les ennemis poursuivent l'entité du joueur. La plupart d'entre eux ont la même vitesse, donc tôt ou tard, ils finissent tous par prendre le même espace tout en poursuivant le joueur. Cela fait vraiment chuter le facteur amusant car, pour le joueur, il semble que vous ne soyez poursuivi que par un seul ennemi. Pour les empêcher de prendre le même espace, j'ai ajouté une détection de collision (une détection 2D très basique, la seule méthode que je connaisse) qui est.
Enemy class update method
Loop through all enemies (continue; if the loop points at this object)
If enemy object intersects with this object
Push enemy object away from this enemy object
Cela fonctionne bien. Tant que je n'ai que <200 entités ennemies, c'est. Lorsque je me rapproche de 300 à 350 entités ennemies, ma fréquence d'images commence à chuter fortement. J'ai d'abord pensé que c'était un mauvais rendu, j'ai donc supprimé leur appel de tirage. Cela n'a pas aidé du tout, bien sûr, j'ai réalisé que c'était la méthode de mise à jour. La seule partie lourde de leur méthode de mise à jour est cette partie de chaque ennemi en boucle à travers chaque ennemi. Lorsque je me rapproche de 300 ennemis, le jeu fait une itération par étapes de 90000 (300x300). Mon mon ~
Je suis sûr qu'il doit y avoir une autre façon d'approcher cette détection de collision. Bien que je ne sache pas comment. Les pages que je trouve sont sur la façon de faire réellement la collision entre deux objets ou comment vérifier la collision entre un objet et une tuile. Je connais déjà ces deux choses.
tl; dr? Comment puis-je aborder la détection de collision entre BEAUCOUP d'entités?
Édition rapide: si c'est pour toute aide, j'utilise C # XNA.
la source
Réponses:
Vous avez déjà touché votre problème directement sur la tête, vous faites vérifier chaque entité par rapport à toutes les autres entités. Ce que vous voudrez, c'est un type de système de «niveau de détail» (c'est à peu près un graphique de scène très simple, vous l'utilisez simplement pour autre chose que le rendu :)) où les candidats à la collision possibles sont mieux sélectionnés.
Je fais généralement trois collections pour des systèmes comme celui-ci. Et lorsque vous parlez du nombre d'entités que vous souhaitez avoir, vous devrez peut-être même utiliser un graphique de scène complet, car les données de suivi (3 listes par entité avec une entrée pour chaque autre entité) peuvent rapidement sortir. de contrôle.
Fondamentalement, bien que vous ayez trois listes. La première devrait être une très petite liste d'entités que vous allez vérifier avec les interactions à chaque image. Vous déterminez cela car ils se trouvent dans la plage X de l'entité en question. Comme mentionné, le but de cette liste est de contenir chaque entité qui peut raisonnablement entrer en collision avec une autre cette trame.
La liste suivante sont celles qui seraient dans une plage de tampons qui pourraient se déplacer dans la plage de l'entité sans trop d'effort. Nous appellerons cette plage X * 1.5 juste pour des raisons d'argument. Il s'agit d'une liste découpée dans le temps où vous n'en mettrez à jour qu'une poignée par image, mais assurez-vous de les parcourir assez rapidement pour conserver l'apparence des choses qui fonctionnent correctement.
La troisième liste est la liste `` tout le reste '' et un moyen d'éviter d'avoir celle-ci peut valoir la peine (balayer la liste d'entités entière et peut-être vérifier si elle est dans l'une des autres listes avant de progresser peut-être? Selon la taille de la liste, cela peut fonctionner ou aggraver les choses.) Les objets de cette liste sont moins vérifiés car il faut certainement plus de quelques images pour être placés dans l'une des deux autres listes.
Ce que vous devrez également faire pour maintenir cela, c'est lorsque vous effectuez les tests de collision, assurez-vous de mettre à jour la liste des entités. Ceux qui se déplacent hors de portée doivent être rétrogradés et de même ceux qui se rapprochent doivent être mis à niveau dans un liste plus activement vérifiée.
En supposant que vous gardiez les choses assez simples, cela devrait répondre à vos besoins. Si vous pouvez ajouter des informations supplémentaires à un graphique de scène de rendu existant (en supposant que vous en avez un), vous pouvez donc l'interroger pour obtenir une liste d'entités qui sont raisonnablement dans la plage qui serait encore meilleure car c'est le point entier d'un graphique de scène de toute façon (accès rapide à une liste de données pertinentes en fonction d'une position). Cela nécessiterait simplement plus de travail et vous devriez toujours considérer ce que vous devez faire par rapport à ce que vous devriez faire pratiquement.
J'espère que cela t'aides.
la source
Vous devez gérer les collisions avec une structure de données triée, vous pouvez donc avoir n * log (n) fois au lieu du terrible n ^ 2. Et n * log (n) est presque linéaire comme vous le savez peut-être. Un exemple (classique) est un quadtree, il y a un tutoriel assez simple et bien écrit ici, avec des graphiques et du code (Java):
http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/
Rq: il est assez facile de trouver une implémentation pour QuadTrees dans n'importe quelle langue. Pourtant, vous devez penser à la bonne «granularité» de l'arbre, et plus la taille de l'arbre est grande, plus nous avons d'entités qui ne rentrent pas dans un nœud.
Rq 2: puisque votre partitionnement de l'espace est effectué uniquement pour la détection de collision, vous avez une liberté parfaite pour diviser l'espace comme vous le souhaitez. Par exemple, je ne diviserais pas en quatre parties égales, mais plutôt j'utiliserais le baricentre des entités de niveau actuel comme centre pour la nouvelle division. 1) l'algorithme est toujours n * log (n), 2) vous perdez la possibilité de `` reconstruire '' la scène hors de l'arbre -mais vous ne vous souciez pas- et 3) vous avez un arbre beaucoup plus équilibré, moins de frais généraux .
Rq3: Une fois que vous avez votre arbre, une 'collision' entre l'écran et les entités vous donne ... les entités visibles !! dans un temps plus comme log (n), alors pourquoi pas si n est grand? (le pire des cas est évidemment un temps en n pour cette approche.)
la source
L'arbre de partition d'espace binaire, quadtree, octree (pour 3D) sont des arbres possibles que vous pouvez générer (ou maintenir, si vous êtes ambitieux) à chaque appel de mise à jour pour chaque objet que vous souhaitez appliquer à la collision.
la source
Je suis assez naïf quand on parle d'arbre quad ou oct. Mais je pense que cette méthode devrait faire:
Vous devrez modifier la structure / classe du joueur. Ajoutez un tableau / vecteur de pointeurs à une autre structure de joueur.
Chaque seconde distance de contrôle entre chacun des deux joueurs. S'il est si bas qu'il est possible d'atteindre en 1 seconde, ajoutez le pointeur de ce joueur au tableau de collision du joueur actuel.
Maintenant, vérifiez uniquement la collision entre les joueurs dans la liste des autres.
la source