Cómo manejar un mundo de bloques como Minecraft

9

Quiero escribir un juego simple con un mundo de bloques como en Minecraft. Mi pregunta teórica es cuál es la mejor manera de manejar esta información de bloque durante la reproducción. Mi primera idea fue una gran variedad, pero creo que esto hará que se quede sin memoria. Tal vez solo tenga que cargar los bloques cerca del jugador.

¿Cómo puedo manejar la carga de la información de bloque necesaria de un archivo y la retención de la información necesaria en la memoria?

danijar
fuente
2
Minecraft carga el mundo en cubos bastante grandes llamados Chunks, no todos a la vez. No estoy seguro de los detalles exactos. La fuente de Minecraft es bastante fácil de conseguir si quieres ver cómo ha ido.
ratbum
Echa un vistazo a la wiki de minecraft: minecraftwiki.net/wiki/Chunk
tom van green
Ya sabía sobre trozos en Minecraft, pero de todos modos gracias.
danijar
Esta es una pregunta compleja que no es apropiada para el alcance de este blog.

Respuestas:

9

Hay un par de formas diferentes de almacenar los datos de un juego con bloques como Minecraft.

La forma en que creo que Minecraft lo hace es romper el mundo en 16x16x256 Chunks. Los fragmentos alrededor del jugador se cargan en la memoria cuando el jugador inicia el juego, luego un hilo de fondo carga más a medida que camina. Aquí hay un video que lo muestra: http://www.youtube.com/watch?v=oR_ZdJH9eho .

Otra forma de hacerlo es dividir el mundo en un Octree. Michael Goodfellow escribió un blog sobre la implementación de un mundo de cubos con esta estructura de datos: http://www.sea-of-memes.com/LetsCode1/LetsCode1.html . El Octree es bueno porque le da un poco de compresión incorporada, pero probablemente será un poco más difícil trabajar con un Array.

¿Acerca de mantener los "únicos necesarios en la memoria"? Esto es un poco más difícil ya que tienes que preguntar qué es "necesario". Si tienes NPC que viven en otra parte del mundo con IA que interactúa con el entorno, entonces "necesitas" mucho más del mundo para estar en la memoria. Los datos mundiales de Voxel pueden ser muy grandes muy rápido, por lo que es mejor tratar de mantener la menor cantidad posible en la memoria. (IE, solo tiene NPCs cerca del jugador).

El motor de gráficos "necesitará" cada bloque que no esté completamente rodeado por otros bloques no transparentes. La forma habitual de representar el mundo es construir una malla única que contenga los vértices de cada bloque visible. Esto es mucho más rápido de dibujar ya que solo está haciendo 1 llamada a los métodos de dibujo para 65,536 bloques (en trozos de tamaño de Minecraft). Dado que el motor de gráficos necesitará construir esta malla, generalmente necesita conocer todos los cubos en un fragmento. Tenga en cuenta que es por eso que cuando ve a través del piso en Minecraft, gran parte del mundo es invisible. Esto se debe a que se omite cada bloque que está rodeado por los seis lados. Creo que Minecraft también reduce la cantidad de vértices al combinar lados horizontales del mismo tipo de textura en una caja con la repetición de la textura.

Mi consejo sería ir con los trozos de 16x16x256. Almacénelos en una matriz, ya que necesitará una iteración y edición rápidas debido a la construcción de la malla y la lógica del juego (detección de colisión, agregar / eliminar bloques, etc.). Luego carga tantos trozos en un círculo alrededor del jugador como puedas. Escale el número de fragmentos hacia arriba o hacia abajo para computadoras mejores o peores.

La carga de Chunks será un gran éxito en el rendimiento, así que póngalo en un hilo que lo ejecute con el tiempo. Hazlo para que puedas cargar por completo 3 nuevos fragmentos durante el tiempo que le toma a un jugador caminar de un extremo a otro.

Thomas Marnell
fuente
¡Gracias! No hay nada sobre IA porque estoy escribiendo un cliente para un MMO. El servidor calcula los NPC. Una adición: el motor de gráficos no necesita "todos los bloques que no estén completamente rodeados por otros bloques no transparentes". Si hay cuevas que el jugador no puede ver, no son importantes. ;-)
danijar
2
Acerca de las cuevas que el jugador no puede ver ... Creo que usa menos rendimiento para dibujar las cuevas que para determinar si la cueva estaba completamente bloqueada. Y si no dibujas cuevas, entonces si eliminaste un bloque, potencialmente tendrías que volver a generar la malla para múltiples fragmentos en lugar de solo uno. Sería genial encontrar una manera de excluir cuevas, simplemente no puedo pensar en una manera de hacerlo de manera eficiente: D.
Thomas Marnell
3

Puede que no tenga la mejor manera de explicarlo, pero lo intentaré.

Creo que la mejor manera de entender cómo hacerlo más eficiente es entender Voxels. Minecraft está basado en vóxel, solo usa cubos en lugar de esferas, etc., etc.

Básicamente, un vóxel es una forma 3D que puede tener un volumen cambiado dinámicamente y cuando el volumen cambia, también lo hace la forma. Un trozo es un conjunto de vóxeles X por X por X. Entonces, por ejemplo, puede tener un fragmento que tiene 16x16x16 vóxeles y luego puede tener un número X de fragmentos. Tendrás una distancia establecida, que si el jugador está más lejos que N de cualquier fragmento, no los incluyas en tus cálculos. Esto es similar a las distancias de recorte, pero también debería aplicarse a cada fragmento. De esta manera, puedes tenerlo para que siempre puedas tener a tu jugador en el Chunk central de, por ejemplo, un conjunto de Chunks 3x3.

Entonces, lo que tendrías es una clase para manejar los Voxels individuales. Lo llamaremos Voxel_cl. Y luego tendrías una clase para manejar la porción de vóxeles, llamada Chunk_cl. Y luego tendrías una clase mundial que genera todos los fragmentos que generarían los vóxeles, llamados World_cl.

Entonces, en lugar de una gran variedad de todo, tendrías una matriz de 9 Chunks en cualquier momento y en la clase de trozos, tendrías una matriz de 4096 voxels.

Tenga en cuenta que esta es una explicación bastante simple. Actualmente estoy trabajando en algo usando voxels, así que pensé que incluiría mi entrada = -)

Para obtener más información sobre voxels, consulte http://en.wikipedia.org/wiki/Marching_cubes

Mungoid
fuente
3
Marching Cubes se trata de visualizar vóxeles. Y Minecraft ni siquiera lo usa; simplemente dibuja cubos, que es exactamente lo que Marching Cubes trata de no hacer.
Nicol Bolas
¡Gracias por tu explicación! Nunca antes había oído hablar de Voxels y parece muy importante para mi proyecto. Pero me queda una pregunta ahora.
danijar
Entiendo crear una matriz de fragmentos cercanos donde cada elemento contiene una matriz de los vóxeles de este fragmento. Pero luego necesito manejar el cambio del conjunto de fragmentos cuando el jugador se mueve por el mundo. ¿Tengo que leer los fragmentos necesarios del archivo de guardar? ¿O hay una buena manera de mantenerlos en la memoria?
danijar
2
@danijar Solo algunas curiosidades, pixel es la abreviatura de "elemento de imagen", voxel se forma de la misma manera a partir de "elemento de volumen". No es que importe para nada, pero como no había escuchado el término voxel antes, pensé que podría ser de algún interés para usted.
Daniel Carlsson
1

Podría intentar hacer que las superficies visibles se procesen, la computadora maneja los datos de bloque en segundo plano, mientras que el renderizador solo funciona con lo que ve. Los trozos de 8x8 serían más fáciles de manejar.

Gandalf
fuente