Como verifico se um canto do bloco está visível no espaço 2D?

7

Estou tentando implementar a névoa da guerra e estou com problemas. Quero verificar se o jogador é capaz de ver os cantos de cada peça dentro de um determinado raio, no entanto, não tenho certeza de como verificar se a visão dos cantos deve ser obstruída ou não. Existe uma maneira rápida de fazer isso? Usei um sistema para desenhar uma linha e verificar se os blocos em que a linha está são blocos sólidos em uma linha de arraste, mas não tenho certeza se esse método seria adequado, pois é possível ver partes de uma peça, ao contrário de uma peça de rolamento onde é uma coisa do tipo sim ou não.

Por exemplo, o bloco preto está obstruindo parcialmente a vista do bloco branco. Rudeza no seu melhor

As linhas vermelhas significam que o jogador é capaz de ver o canto, enquanto o azul significa que não podem (como o preto o impede).

user15498
fonte
Um desenho da situação de que você está falando ajudaria a tornar essa pergunta sólida.
MichaelHouse

Respostas:

3

Para detalhar um pouco a resposta de Nick: o conceito principal por trás do algoritmo DDA (que funciona tão bem em três dimensões) é que, para cada eixo da sua grade, você acompanha o próximo 'ponto de cruzamento' desse eixo em termos de parâmetro de linha; cada etapa do algoritmo consiste em descobrir qual eixo tem o próximo ponto de cruzamento (que é uma comparação simples em duas dimensões), executar o passo apropriado e atualizar os valores da próxima travessia para cada eixo. Ilustração DDA

A linha aqui pode ser escrita como '(x, y) = (x0, y0) + t * (m, n)', onde m = x1-x0 e n = y1-y0. Se as dimensões de uma célula de grade são gx e gy, então dx - a distância (em termos do parâmetro t) necessária para cruzar uma célula de grade - pode ser encontrada com um pouco de álgebra rápida: a partir do par de equações x = x0 + m t, (x + gx) = x0 + m (t + dx) obtemos gx = m * dx, ou seja, dx = gx / m. Da mesma forma, dy = gy / n. O algoritmo controla next_x (a distância até o próximo ponto vermelho ao longo da linha) e next_y (a distância até o próximo ponto azul ao longo da linha) e os atualiza toda vez que atinge outro cruzamento, para que o loop central se pareça com este :

while ( cur_t < t_max) {
  if ( next_x < next_y ) {
    cell_x++;
    cur_t += next_x;
    next_y -= next_x;
    next_x = dx;
  } else {
    cell_y++;
    cur_t += next_y;
    next_x -= next_y;
    next_y = dy;
  }
  // Process the cell (cell_x, cell_y)
}

Observe que esse código está faltando muitos detalhes - ele não informa como inicializar next_x e next_y, por exemplo. Existem maneiras de eliminar a maioria das divisões, facilitando o tratamento de casos especiais, como linhas verticais e horizontais. Se você incrementa ou diminui cell_x e cell_y, depende do quadrante em que sua linha está - observe que, na minha linha de exemplo, você estaria diminuindo cell_x a cada marca, pois m (x1-x0) é negativo. Você também precisa decidir como vai lidar com os casos em que sua linha passa exatamente pelo canto entre as células, em vez de fazer a transição em uma aresta; existem muitos pequenos detalhes que podem dar errado e precisam de muitos testes. Ainda assim, espero que isso lhe dê uma imagem de qual é a idéia principal do algoritmo.

Steven Stadnicki
fonte
1

O algoritmo DDA (Digital Differential Analyzer) de John Amanatides e Andrew Woo fornece o que você precisa. Estou no celular tão entediante para pegar o link sem fechar esta página. DDA é O (n * m) em que n é o número de ladrilhos a serem percorridos ao longo de um raio / ângulo e m o número de ângulos.

Se você precisar verificar se partes menores do bloco ainda estão visíveis (detalhes mais finos), poderá dividir cada bloco em uma grade separada e executar verificações de DDA nesse nível também.

A única alternativa substancialmente diferente que eu vejo é a varredura raycast (verificações de interseção linha-linha) que é O (n * m), com n sendo o número de arestas de ladrilhos dentro da área de interesse e m sendo o número de ângulos discretos testados pois em cada varredura circular (o que implica que, mesmo com essa abordagem, ainda existem problemas de resolução). Como existem várias arestas em cada bloco, o DDA pode ser visto como mais eficiente.

Uma abordagem final que vem à mente é adaptar a varredura raycasrt configurando um ângulo de raio individual para cada interseção de grade individual dentro de sua área de interesse limitada. Dessa forma, você pode determinar exatamente onde a oclusão ocorre dentro de sua grade (já que as linhas de oclusão sempre passam pelos cantos), embora seja necessário restringir substancialmente sua área de interesse, para que o número de pontos intersticiais que definem seus ângulos de raio fique fora de controle.

Nick Wiggill
fonte