Parece que você está procurando aprender sobre Árvores!
E estou falando sério, se atualmente você está fazendo um loop sobre uma matriz de todos os seus cubos, então deve realmente analisar várias estruturas de dados espaciais. Nesse caso, a melhor maneira de repensar o mundo do seu cubo é como uma árvore.
Antes de abordarmos as razões, vamos pensar sobre o nosso problema. Estamos procurando uma solução em que, pelo menor custo possível, possamos recuperar uma lista de cubos próximos com os quais o jogador esteja colidindo. Essa lista deve ser tão pequena, mas precisa quanto possível.
Agora, para determinar esta zona, precisamos mapear o espaço de coordenadas do nosso jogador para o espaço de coordenadas do mapa do cubo; isto é, precisamos mapear a posição do ponto flutuante do player para um índice discreto da matriz multidimensional de cubos (pode ser uma notação de exemplo world[31][31][31]
, ou seja, o meio exato para uma matriz multidimensional 64 * 64 * 64).
Poderíamos simplesmente calcular os blocos adjacentes usando essa mesma indexação discreta, talvez amostrando apenas os cubos próximos, mas isso ainda exige um recálculo constante e não permite objetos que não sejam discretos no posicionamento (ou seja, não podem ser mapeados para o cubo mapa).
A situação ideal é um conjunto de baldes que contêm nossos conjuntos de cubos para seções específicas do nosso mapa de cubos, divididos igualmente para que, em vez de recalcular a área circundante, simplesmente nos movemos para dentro e para fora deles. zonas . Para qualquer cálculo não trivial, manter nossos dados assim poderia eliminar a iteração de todos os cubos e apenas desses conjuntos individuais que estão próximos.
A questão é: como implementamos isso?
Para o mundo 64 * 64 * 64, imagine-o dividido em 8 * 8 * 8 zonas . Isso significa que, no seu mundo, você terá 8 zonas por eixo (X, Y, Z). Cada um desses zonas conterá 8 cubos, facilmente recuperáveis por esse novo índice simplificado.
Se você precisar executar uma operação em um conjunto de cubos próximos, em vez de iterar todos os cubos do seu mundo, basta iterar sobre esses zonas , dividindo o número máximo de iterações do original 64 * 64 * 64 (262144) para apenas 520 (8 * 8 * 8 + 8).
Agora zoom deste mundo de zonas, e colocar as zonas em maiores super-zonas ; em que cada superzona contém 2 * 2 * 2 zonas regulares . Como seu mundo atualmente contém 512 (8 * 8 * 8) zonas , podemos quebrar as 8 * 8 * 8 zonas em 64 (4 * 4 * 4) super-zonas dividindo 8 zonas por 2 zonas por super-zone . Aplicando a mesma lógica de cima, isso quebraria as iterações máximas de 512 a 8 para encontrar a superzona ; e, no máximo, 64 para encontrar a zona de prosseguimento(total máximo de 72)! Você pode ver como isso já está poupando muitas iterações (262144: 72).
Tenho certeza que você pode ver agora como as árvores são úteis. Cada zona é um ramo da árvore, com cada superzona como um ramo anterior. Você está simplesmente atravessando a árvore para encontrar o que precisa; usando conjuntos menores de dados para minimizar o custo geral.
O diagrama abaixo deve ajudá-lo a visualizar o conceito. (imagem da Wikipedia: Octrees ):
Aviso Legal:
Em uma configuração ideal como acima, onde seu mundo voxel já está disposto em uma matriz multidimensional de tamanho fixo, você pode simplesmente consultar a posição do jogador e indexar os blocos ao redor com um custo de O (1)! (Veja a explicação de Olhovskys). Mas isso se torna mais difícil quando você começa a considerar que seu mundo raramente tem tamanho fixo em um jogo de voxel; e você pode precisar a sua estrutura de dados para ser capaz de carregar todo super-zonas do disco rígido para a memória. Ao contrário de uma matriz multidimensional de tamanho fixo, as árvores prontamente permitem isso sem muito tempo gasto em algoritmos combinatórios.