Linha de visão 2d Java eficiente para muitas entidades?

7

Meu problema hoje é este:

Imagem de uma tonelada de pessoas em um mapa

Eu tenho muitos civis por aí, são classes armazenadas por um arraylist.

A idéia é que, quando virem outro pânico civil, começarão a entrar em pânico e isso se espalhará.

Primeiro, chamo a Step()função de cada classe fazendo um loop através de um iterador. Então, na Step()função, ele passa por outro iterador civil Enquanto ele tenta, tenta detectar se ele pode ver o outro civil no iterador, é aqui que o tempo de desempenho varia de 0 a 50 milissegundos por ter 100 civilianos.

Esse é o problema que eu preciso resolver, tentei facilitar o modo de detectar se algum objeto está no caminho do ponto a ao ponto b.

Aqui está o código para a linha de visão:

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 você está com dor de cabeça, os fundamentos são:

Ele mostra 10 pontos no meio e detecta se está 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;
   }
}

Minha pergunta é: Existe uma maneira mais fácil de detectar essa linha de visão que não afeta severamente meu desempenho em grandes números? Algum feedback?

user940982
fonte
2
1. 404 em LOS.txt2. Não queremos ver todo o seu código. Forneça um SSCCE .
Matt Bola
Obrigado pela ajuda de edição Matt, eu consertei o 404 :) Eu só mostrei o código que importava.

Respostas:

5

Um pensamento seria manter as pessoas que não estavam em pânico e em pânico em listas separadas N e P e, em seguida, limitar suas verificações de LOS a <n, p> ∈ N × P. Dessa forma, você nunca verifica pessoas do mesmo estado, o que acelerará as coisas acima.

Outra coisa (o que você já deve estar fazendo - não tenho certeza) seria garantir que, depois de determinar que um não violador tenha se tornado um violador, pare imediatamente as verificações restantes do ex-violador. Isso ajudará seu algoritmo a escalar com o aumento do tamanho da população para um mapa fixo. Quando a população fica muito grande, você deve convergir rapidamente para o pânico a 100%, o que significa que não são necessárias mais verificações, conforme observado nos comentários abaixo.


fonte
Bom conselho, eu acabei de adicionar esse filtro, em 0% em pânico está em 1 milissegundo, em 100% atinge 50, mas isso definitivamente está tornando prático, obrigado.
Algo não parece certo - o número de verificações deve ser (tp) * p, onde t = total, p = pânico. Portanto, quando p = t, o número de verificações deve ser 0. Intuitivamente, quando todo mundo está em pânico, não há razão para fazer mais verificações. Tem certeza de que sua lista N contém os não- violadores, em vez de conter toda a população? Suponho que, a 100%, você esteja comparando todos os pânico com toda a população, e é por isso que é mais lento.
2

Pela sua descrição, parece que seu código está repetindo todos os pares possíveis de dois civis. O desenho sugere que isso é desnecessário. Você pode usar algum tipo de indexação geométrica para rastrear civis próximos. Em seguida, teste-os primeiro. Se eles estiverem no LOS, entre em pânico. Caso contrário, teste os civis mais distantes.

emory
fonte
Obrigado, eu já fiz isso, antes das otimizações era de 100 milissegundos.
0

Você tem várias opções:

A) Suponha que as pessoas possam entrar em pânico também ouvindo outras pessoas gritando, então o código da linha de visão não é tão importante para o XD.

B) Caso A não seja uma opção, você deve fazer isso para cada civil:

  1. Calcule se o segmento entre dois civis tem um comprimento menor ou igual a algum valor constante.
  2. Calcule se esse segmento cruza com um polígono (retângulo, no seu caso).

Você precisa executar 1 antes de 2 porque isso reduz bastante a quantidade de trabalho, já que 2 é o cálculo mais caro. Além disso, você deve considerar algum tipo de "memória" sobre os cálculos que já fez, por exemplo: Se você acabou de processar o segmento C1-C2, não faça novamente C2-C1.

Além disso, você precisa otimizar 2. Testar se um segmento se cruza com um retângulo é equivalente a testar se um determinado segmento se cruza com 4 segmentos. Quando você cruza com um deles, temos certeza de que os civis não se vêem, então não faz sentido processar os segmentos restantes no retângulo.

Como esse é um problema geométrico típico, conhecido como problema de interseção do segmento de linha , você pode encontrar bastante código-fonte aberto na Internet. A maioria das pessoas usa um algoritmo de linha de varredura junto com alguma estrutura de dados.

Mister Smith
fonte
Obrigado pelo amplo conhecimento, estou fazendo algumas pesquisas wiki sobre esses algoritmos agora.
User940982
0

Se você tratar as salas como zonas, unidas por portais , você só precisará fazer verificações de visibilidade em cada sala e nas partes das salas adjacentes que são visíveis através dos portais pré-determinados.

Sua linha de visão provavelmente não é responsável pela direção que o civil está enfrentando? Nesse caso, se você dividir quartos que contenham obstáculos, como pilares, ou contornem esquinas em zonas convexas separadas, e supondo que todos os civis na mesma zona sejam todos visíveis um ao outro. Você pode levar isso adiante ao ter zonas côncavas sobrepostas e permitir que os civis estejam em mais de uma zona ao mesmo tempo, a fim de encontrar o maior número possível na mesma zona que o outro civil, para evitar todas as outras verificações de visibilidade.

Se o seu terreno for irregular e você tiver um grande número de agentes, poderá estar interessado nessa varredura de O (n) (onde N é a granularidade de uma grade na qual você dividiu o terreno):insira a descrição da imagem aqui

Vai
fonte