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?
c++
voxels
minecraft-modding
data
danijar
fuente
fuente
Respuestas:
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.
fuente
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
fuente
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.
fuente