¡Parece que estás buscando aprender sobre los árboles!
Y lo digo en serio, si actualmente estás recorriendo una matriz de todos tus cubos, entonces realmente deberías buscar en varias estructuras de datos espaciales. Para este caso, la mejor manera de volver a imaginar su mundo de cubos es como un árbol.
Antes de entrar en las razones de por qué, pensemos en nuestro problema. Estamos buscando una solución donde, por el menor costo posible, podamos recuperar una lista de cubos cercanos con los que el jugador podría estar chocando. Esta lista debe ser lo más pequeña y precisa posible.
Ahora para determinar esta zona, necesitamos asignar el espacio de coordenadas de nuestro jugador al espacio de coordenadas del mapa de cubos; es decir, necesitamos asignar la posición de coma flotante del jugador a un índice discreto de la matriz multidimensional de cubos (la notación de ejemplo podría ser world[31][31][31]
, es decir, el centro exacto para una matriz multidimensional 64 * 64 * 64).
Podríamos simplemente calcular los bloques circundantes usando esta misma indexación discreta, tal vez muestreando solo los cubos cercanos, pero esto aún requiere un recálculo constante y no permite ningún objeto que no sea discreto en su ubicación (es decir, puede que no se asigne al cubo mapa).
La situación ideal es un conjunto de cubos que contienen nuestros conjuntos de cubos para secciones particulares de nuestro mapa de cubos, divididos en partes iguales, por lo que en lugar de volver a calcular el área circundante, simplemente nos movemos dentro y fuera de estas zonas . Para cualquier cálculo no trivial, mantener nuestros datos de esta manera podría eliminar la iteración de todos los cubos, y solo estos conjuntos individuales que están cerca.
La pregunta es: ¿Cómo implementamos esto?
Para el mundo 64 * 64 * 64, imagínelo desglosado en 8 * 8 * 8 zonas . Esto significa que en su mundo, tendrá 8 zonas por eje (X, Y, Z). Cada una de estas zonas contendrá 8 cubos, fácilmente recuperables por este nuevo índice simplificado.
Si necesita realizar una operación en un conjunto de cubos cercanos, en lugar de iterar cada cubo en su mundo, simplemente puede iterar sobre estas zonas , desglosando el número máximo de iteraciones desde el 64 * 64 * 64 original (262144) hasta solo 520 (8 * 8 * 8 + 8).
Ahora aleja este mundo de zonas y coloca las zonas en superzonas más grandes ; en donde cada superzona contiene 2 * 2 * 2 zonas regulares . A medida que su mundo actualmente contiene 512 (8 * 8 * 8) zonas , podemos romper los 8 * 8 * 8 zonas en 64 (4 * 4 * 4) Grandes zonas dividiendo 8 zonas por 2 zonas por super-zona . Aplicando la misma lógica desde arriba, esto rompería las iteraciones máximas de 512 a 8 para encontrar la superzona ; y luego un máximo de 64 para encontrar la zona de procedimiento(total máximo 72)! Puede ver cómo esto ya le está ahorrando muchas iteraciones (262144: 72).
Estoy seguro de que ahora puedes ver lo útiles que son los árboles. Cada zona es una rama en el árbol, con cada superzona como una rama precedente. Simplemente estás atravesando el árbol para encontrar lo que necesitas; utilizando conjuntos de datos más pequeños para minimizar el costo general.
El siguiente diagrama debería ayudarlo a visualizar el concepto. (imagen de Wikipedia: Octrees ):
Descargo de responsabilidad:
En una configuración ideal como la anterior, donde su mundo de vóxel ya se presenta en una matriz multidimensional de tamaño fijo, simplemente puede consultar la posición del jugador, ¡luego indexar los bloques circundantes con un costo O (1)! (Ver explicación de Olhovsky) Pero esto se vuelve más difícil cuando comienzas a considerar que tu mundo rara vez tiene un tamaño fijo en un juego de vóxel; y es posible que necesite que su estructura de datos sea capaz de cargar súper zonas completas desde el disco duro a la memoria. A diferencia de una matriz multidimensional de tamaño fijo, los árboles lo permiten fácilmente sin dedicar demasiado tiempo a algoritmos combinatorios.