Détection de collision 2D plus rapide

13

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.

eShredder
la source
Je me demande comment vous l'avez fait pour aller à 90K en premier lieu. le mien s'étouffe à 20K (je fais cependant une détection SAT MTV complète). Mais parcourir tous les ennemis en boucle est la seule chose qui semble possible. Cependant, ce que vous devez faire, c'est de vérifier s'ils ont déjà été vérifiés, car si vous aimez ce que vous dites, alors tout le monde est testé deux fois avec tout le monde.
Delusional Logic
3
Ceci est un doublon possible de gamedev.stackexchange.com/questions/39931/…
Markus von Broady
Il y a une très bonne réponse à la question que @MarkusvonBroady a liée.
Cypher

Réponses:

11

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.

James
la source
1
Ceci est une réponse vague. Et peut-on accepter de rater quelques collisions ?? Beaucoup plus simple, utilisez une structure de données qui fera le partitionnement de surface pour vous, comme le Quad Tree dont je parle ici. Même un arbre quadruple a besoin d'un réglage fin pour éviter les frais généraux, donc je ne peux pas imaginer la complexité de la «solution» dont vous parlez. Règle de programmation de base: utilisez simplement la bonne structure de données.
GameAlchemist
@VincentPiel Un graphe de scène n'est pas plus complexe qu'un arbre quadruple.
Cypher
@James: c'est évidemment plus complexe. Si cela ne vous dérange pas de saisir la pleine vitesse du QuadTree, vous pouvez obtenir une bibliothèque QuadTree sur le net et la faire fonctionner parfaitement en quelques heures. Aucune question comme: que dois-je mettre dans la première liste, la deuxième, la troisième, comment puis-je décider de mettre une entité dans une autre liste ... et aucune collision manquée. Pourquoi utiliser un vélo quand on peut avoir une voiture?
GameAlchemist
@VincentPiel Je pense que vous vouliez @ votre commentaire à Cypher au lieu de moi ici. N'importe quel arbre quadruple n'est qu'un type de graphique de scène et vous devez vous rappeler que vous exécutez à X images par seconde. Si vous remarquez des collisions manquées, vous devez ajuster vos seuils de portée pour mieux équilibrer les choses. Ma solution est simplement une approche très simple pour vous assurer de ne vérifier que chaque élément qui a une chance d'être heurté, puis de faire des mises à jour en arrière-plan / limitées sur le reste pour voir si elles remplissent les conditions pour une priorité plus élevée.
James
6

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.)

GameAlchemist
la source
Oui, un arbre quadruple n'est vraiment qu'un type de graphique de scène. Je suppose simplement que les gens qui sont ici veulent écrire des choses eux-mêmes, ne pas utiliser la bibliothèque de quelqu'un d'autre, auquel cas pourquoi s'arrêter à un arbre quadruple, trouver simplement une bibliothèque complète de collisions.
James
0

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.

kchoi
la source
3
C'est plus approprié d'être un commentaire. Pensez à ajouter plus à votre réponse.
0

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.

user3042253
la source