Une ligne de vue Java 2D efficace pour de nombreuses entités?

7

Mon problème aujourd'hui est le suivant:

Image d'une tonne de personnes sur une carte

J'ai beaucoup de civils qui circulent, ce sont des classes stockées par un arrayliste.

L'idée est quand ils voient une autre panique civile, ils vont commencer à paniquer et ça va se propager.

D'abord, j'appelle chaque Step()fonction de classe en passant en boucle dans un itérateur. Ensuite, dans la Step()fonction, il passe par un autre itérateur civillian.Au fur et à mesure, il essaie de détecter s'il peut voir l'autre civillian dans l'itérateur, c'est là que le temps de performance passe de 0 à 50 millisecondes pour avoir 100 Civillians.

C'est le problème que je dois résoudre, j'ai essayé de trouver un moyen facile de détecter si des objets gênent du point a au point b.

Voici le code de la ligne de visée:

public static Object LOS(int x, int y, int x2, int y2, String Scan, Object Me, Object You) {
   DirectionX = (x-x2)/Quality;
   DirectionY = (y-y2)/Quality;
   CurrentX = x;
   CurrentY = y;
   String[] ScanArray = Scan.split(":");
   for(int I=0;I<=Quality;I++) {
      for(String Type: ScanArray) {
         if(Type.equals("Boxs")) {
            Iterator it=Level.Boxs.iterator();
            while(it.hasNext()) {
               Box Box = (Box)it.next();
               if(Me!=Box&&You!=Box) {
                  //Collision = Tools.Collision((int)(CurrentX-(Width/2)), (int)(CurrentY-(Width/2)), Width, Width, Box.GetX(), Box.GetY(), Box.GetWidth(), Box.GetHeight(), 1);
                  boolean Col = Tools.BasicCollision((int)(CurrentX-(Width/2)), (int)(CurrentY-(Width/2)), Width, Width, Box.GetX(), Box.GetY(), Box.GetWidth(), Box.GetHeight());
               }
            }
         }
      }

      CurrentX-=DirectionX;
      CurrentY-=DirectionY;
   }
   return null;
}

Si vous avez mal à la tête, les principes fondamentaux sont:

Il détermine 10 points entre les deux et détecte s'il se trouve à l'intérieur, en utilisant BasicCollision:

public static boolean BasicCollision(int x, int y, int width, int height, int x2, int y2, int width2, int height2) {
   if(x<x2+width&&x+width>x2&&y<y2+height&&y+height>y2) {
      return true;
   } else {
      return false;
   }
}

Ma question est la suivante: existe-t-il un moyen plus simple de détecter cette ligne de visée qui n'affecte pas sérieusement mes performances en grand nombre? Tous les commentaires?

user940982
la source
2
1. 404 sur LOS.txt2. Nous ne voulons pas voir tout votre code. Fournir un SSCCE .
Matt Ball
Merci pour l'aide à l'édition Matt, j'ai corrigé le 404 :) Je n'ai montré que le code qui comptait.

Réponses:

5

Une idée serait de maintenir les personnes non paniquées et paniquées dans des listes distinctes N et P, puis de limiter vos contrôles LOS à <n, p> ∈ N × P. De cette façon, vous ne vérifiez jamais les personnes dans le même état, ce qui accélérera les choses vers le haut.

Une autre chose (ce que vous faites peut-être déjà - vous n'êtes pas sûr) serait de vous assurer qu'une fois que vous avez déterminé qu'un non-voleur est devenu un panique, arrêtez immédiatement les contrôles restants pour cet ancien non-voleur. Cela aidera votre algorithme à évoluer avec l'augmentation de la taille de la population pour une carte fixe. Lorsque la population devient très importante, vous devriez converger vers une panique à 100% assez rapidement, ce qui signifie qu'aucun contrôle supplémentaire n'est nécessaire, comme indiqué dans les commentaires ci-dessous.


la source
Bon conseil, je viens d'ajouter ce filtre, à 0% de panique, il est à 1 milliseconde, à 100%, il atteint 50, mais cela le rend certainement pratique, merci.
Quelque chose ne sonne pas bien - le nombre de vérifications doit être (tp) * p, où t = total, p = panique. Ainsi, lorsque p = t, le nombre de vérifications doit être égal à 0. Intuitivement, une fois que tout le monde panique, il n'y a aucune raison de faire d'autres vérifications. Etes-vous sûr que votre liste N contient les non- paniqueurs, au lieu de contenir toute la population? Je suppose qu'à 100%, vous comparez chaque panique à l'ensemble de la population, c'est pourquoi il est plus lent.
2

D'après votre description, il semble que votre code soit en train d'itérer sur tous les appariements possibles de deux civils. Le dessin suggère que cela n'est pas nécessaire. Vous pouvez utiliser une sorte d'indexation géométrique pour garder une trace des civils à proximité. Testez-les d'abord. S'ils sont dans le LOS, alors paniquez. Sinon, testez les civils plus loin.

Emory
la source
Merci, je l'ai déjà fait, avant les optimisations, c'était à 100 millisecondes.
0

Vous avez plusieurs options:

A) Supposons que les gens peuvent paniquer en entendant aussi d'autres personnes crier, donc le code de ligne de vue n'est pas si important que XD.

B) Dans le cas où A n'est pas une option, vous devez le faire pour chaque civil:

  1. Calculez si le segment entre deux civils a une longueur inférieure ou égale à une valeur constante.
  2. Calculez si ce segment croise un poligon (rectangle, dans votre cas).

Vous devez effectuer 1 avant 2 car cela réduit considérablement la quantité de travail, étant donné que 2 est le calcul le plus cher. Vous devez également considérer une sorte de "mémoire" sur les calculs que vous avez déjà faits, par exemple: Si vous venez de traiter le segment C1-C2, ne recommencez pas C2-C1.

En plus de cela, vous devez optimiser 2. Tester si un segment intersecte avec un rectangle est équivalent à tester si un segment donné intersecte avec 4 segments. Lorsque vous avez croisé l'un d'eux, nous sommes sûrs que les civils ne se voient pas, donc cela n'a aucun sens de traiter les segments restants dans le rectangle.

Comme il s'agit d'un problème géométrique typique, connu sous le nom de problème d'intersection de segments de ligne , vous pouvez trouver de nombreux codes open source sur Internet. La plupart des gens utilisent un algorithme de ligne de balayage avec une certaine structure de données.

Monsieur Smith
la source
Merci pour la perspicacité approfondie, je fais maintenant des recherches sur ces algorithmes wiki.
user940982
0

Si vous traitez les pièces comme des zones, jointes par des portails , vous n'avez qu'à effectuer des analyses de visibilité dans chaque pièce et dans les parties des pièces adjacentes qui sont visibles à travers les portails prédéterminés.

Votre ligne de vue ne tient probablement pas compte de la direction à laquelle le civil fait face? Dans un tel cas, si vous divisez des pièces contenant des obstacles tels que des piliers ou que vous contournez des coins dans des zones convexes distinctes et en supposant que tous les civils dans la même zone sont tous visibles les uns des autres. Vous pouvez aller plus loin en ayant des zones concaves qui se chevauchent et en permettant aux civils d'être dans plus d'une zone à la fois afin d'en trouver autant que possible dans la même zone que l'autre civil afin d'éviter tous les autres contrôles de visibilité.

Si votre terrain est inégal et que vous avez un grand nombre d'agents, ce balayage O (n) peut vous intéresser (où N est la granularité d'une grille dans laquelle vous avez divisé le terrain):entrez la description de l'image ici

Volonté
la source