Efficiente 2d Java Line of Sight per molte entità?


7

Il mio problema oggi è questo:

Immagine di una tonnellata di persone in una mappa

Ho molti civili in giro, sono classi immagazzinate da un arraylist.

L'idea è che quando vedranno un altro panico civile, inizieranno a prendere il panico e si diffonderà.

Per prima cosa chiamo ciascuna Step()funzione delle classi eseguendo il ciclo attraverso un iteratore. Quindi nella Step()funzione passa attraverso un altro iteratore civillian Mentre attraversa, cerca di rilevare se riesce a vedere l'altro civillian nell'iteratore, è qui che il tempo di esecuzione va da 0 a 50 Millisecondi per avere 100 Civillian.

Questo è il problema che devo risolvere, ho provato a fare un modo semplice per rilevare se vi sono oggetti nel punto da a a b.

Ecco il codice per la linea di vista:

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;
}

Se hai mal di testa i fondamenti sono:

Calcola 10 punti in mezzo e rileva se è dentro, usando 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;
   }
}

La mia domanda è: esiste un modo più semplice per rilevare questa linea di vista che non influisce gravemente sulle mie prestazioni in gran numero? Qualche feedback?


2
1. 404 su LOS.txt2. Non vogliamo vedere tutto il tuo codice. Fornire un SSCCE .
Matt Ball,

Grazie per l'aiuto alla modifica Matt, ho corretto il 404 :) Ho mostrato solo il codice che contava.

Risposte:


5

Un pensiero sarebbe quello di mantenere le persone non in preda al panico e in preda al panico in elenchi separati N e P, e quindi limitare i controlli LOS a <n, p> ∈ N × P. In questo modo non si controllano mai le persone dello stesso stato, il che accelererà le cose su.

Un'altra cosa (cosa che potresti già fare - non sono sicuro) sarebbe quella di assicurarti che una volta determinato che un nonpanicker è diventato un panicker, interrompi immediatamente i controlli rimanenti per quell'ex nonpanicker. Ciò aiuterà il tuo algoritmo a scalare con l'aumento della dimensione della popolazione per una mappa fissa. Quando la popolazione diventa molto grande, dovresti convergere verso il panico al 100% abbastanza rapidamente, il che significa che non sono necessari ulteriori controlli, come indicato nei commenti qui sotto.


Un buon consiglio, ho appena aggiunto quel filtro, allo 0% in panico è a 1 millisecondo, al 100% colpisce 50, ma questo lo rende sicuramente pratico, grazie.

Qualcosa non suona bene - il numero di controlli dovrebbe essere (tp) * p, dove t = totale, p = panico. Quindi quando p = t il numero di controlli dovrebbe essere 0. Intuitivamente, una volta che tutti sono nel panico, non c'è motivo di fare altri controlli. Sei sicuro che la tua lista N contenga i non- panicker, invece di contenere l'intera popolazione? Immagino che al 100% stai confrontando ogni panico con l'intera popolazione, motivo per cui è più lento.

2

Dalla tua descrizione sembra che il tuo codice stia ripetendo ogni possibile accoppiamento di due civili. Il disegno suggerisce che ciò non è necessario. È possibile utilizzare una sorta di indicizzazione geometrica per tenere traccia dei civili vicini. Quindi testarli prima. Se sono nella LOS, allora panico. Altrimenti prova i civili più lontani.


Grazie, l'ho già fatto, prima delle ottimizzazioni era a 100 millisecondi.

0

Hai diverse opzioni:

A) Supponiamo che le persone possano farsi prendere dal panico anche sentire altre persone urlare, quindi il codice della linea di vista non è così importante XD.

B) Nel caso in cui A non sia un'opzione, devi farlo per ogni civile:

  1. Calcola se il segmento tra due civili ha una lunghezza inferiore o uguale a un valore costante.
  2. Calcola se questo segmento si interseca con un poligono (rettangolo, nel tuo caso).

Devi eseguire 1 prima di 2 perché riduce notevolmente la quantità di lavoro, dato che 2 è il calcolo più costoso. Inoltre, devi considerare una sorta di "memoria" sui calcoli che hai già effettuato, ad esempio: se hai appena elaborato il segmento C1-C2, non ripetere C2-C1.

Inoltre, è necessario ottimizzare 2. Testare se un segmento si interseca con un rettangolo equivale a testare se un determinato segmento si interseca con 4 segmenti. Quando ti sei intersecato con uno di loro, siamo sicuri che i civili non si vedranno, quindi non ha senso elaborare i segmenti rimanenti nel rettangolo.

Poiché si tratta di un tipico problema geometrico, noto come problema di intersezione del segmento di linea , è possibile trovare un sacco di codice open source su Internet. Molte persone usano un algoritmo di sweep line insieme ad alcune strutture di dati.


Grazie per la visione approfondita, sto facendo alcune ricerche wiki su questi algoritmi ora.
user940982,

0

Se trattate le stanze come zone, unite da portali , dovete solo eseguire scansioni di visibilità all'interno di ogni stanza e quelle parti delle stanze adiacenti che sono visibili attraverso i portali predeterminati.

La tua visuale probabilmente non sta spiegando la direzione che il civile sta affrontando? In tal caso, se si dividono stanze che contengono ostacoli come pilastri o si aggira angoli in zone convesse separate e assumendo che tutti i civili nella stessa zona siano tutti visibili l'uno all'altro. Puoi andare oltre, avendo zone concave sovrapposte e permettendo ai civili di trovarsi in più di una zona in una sola volta da trovarne il maggior numero possibile nella stessa zona dell'altro civile in modo da evitare tutti gli altri controlli di visibilità.

Se il tuo terreno è irregolare e hai un gran numero di agenti, potresti essere interessato a questa scansione O (n) (dove N è la granularità di una griglia in cui hai diviso il terreno):inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.