Pregunta

Así que estoy tratando de trabajar en mi propio pequeño juego en 3D. Ahora estoy más o menos haciendo esto para aprender C #. Me preguntaba, ¿cuál es la mejor metodología para empaquetar activos como texturas / scripts?

Generalmente, lo que estaba pensando hacer era esto:

[header]
[number of records]
[Offset to Record 1 from End of header]
[Offset to Record 2 from end of Record 1]
.
.
[Offset to record N from Record N-1]
[record 1]
[256 bytes represent the filename]
[32 byte size]
[binary data]
[record 2]
.
.

En este momento solo quiero que almacene imágenes simples y archivos de texto. He echado un vistazo y lo mejor que encontré fue un viejo ejemplo de cómo se almacenan los tacos de Doom.

¿Alguien tiene alguna experiencia?

¿Fue útil?

Solución

Eso está bien. Si puede cargar todo en la memoria virtual y dejar que el intercambio lo maneje, entonces puede usar cualquier formato, realmente. Si desea acceso aleatorio a un solo registro (por ejemplo, puede cargar de manera diferida, aunque el mapa de memoria sin comprimir también es diferido), entonces probablemente desee mantener el índice en la memoria.

La mayoría de las personas usan una biblioteca que les da acceso a un .zip, .jar, .pak (formato de terremoto) u otro formato de archivo similar (comprimido o no), como si fuera parte del sistema de archivos (es decir, Se accede a los registros mediante teclas de cadena). Definitivamente iría por ese camino si puedes encontrar una biblioteca ya hecha, p. truezip para Java. Apache Commons tiene uno, pero no sé lo fácil que es integrar w / .NET (creo que es una gran base de código C). ZipFS parece que es un montador de archivos zip .NET real que solo contiene los encabezados en la memoria.

O, probablemente con un poco menos de conveniencia, puede usar DotNetZip directamente

Otros consejos

No pierda su tiempo inventando su propio formato de almacenamiento.

Puede usar SharpZipLib u otra biblioteca de compresión gratuita para .net. Con él también puede empaquetar varios archivos en un solo archivo y extraer los archivos que desee por separado a pedido.

¡Su diseño se ve bien para mí, aunque supongo que usted quiso decir 32 bits para el tamaño en lugar de 32 bytes !

Creo que su diseño sería el mejor para situaciones en las que desea cargar todos sus activos de una sola vez, porque es una especie de diseño secuencial. Si desea cargar solo unos pocos activos a la vez (tal vez porque cada nivel de juego usa solo un subconjunto de los activos), sería algo menos eficiente, ya que tendría que leer cada activo por turnos para encontrarlos. que quieras

En ese caso, es posible que desee probar un diseño más indexado, tal vez algo como esto:

[HEADER]
[Miscellaneous header stuff]
[Offset to index from start of file]
[Number of entries in index]
[RECORD 1]
[Asset data]
[RECORD 2]
[Asset data]
.
.
[RECORD N]
[Asset data]
[INDEX]
[ID or filename of asset 1]
[Size of asset 1]
[Offset to asset 1 from start of file]
[Other asset 1 flags or whatever]
[ID or filename of asset 2]
[Size of asset 2]
[Offset to asset 2 from start of file]
[Other asset 2 flags or whatever]
.
.

Esto permitiría un mejor acceso aleatorio de los activos, porque ahora solo tiene que buscar a través de su índice (que cargaría en la memoria) en lugar de a través de todo su archivo (que podría no encajar en la memoria). Si quieres ponerte elegante, puedes usar un árbol o una tabla hash para el índice.

La razón para colocar el índice al final del archivo en lugar del frente es que hace que sea más fácil agregar otro activo a su archivo de paquete sin tener que reconstruir todo. De lo contrario, la entrada adicional en su índice eliminaría todas sus compensaciones.


EDITAR: para responder a los comentarios ...

Lo que tenía en mente era que solo accedería a los activos a través del índice, por lo que espero que nunca se salga del final de los activos al leerlos. Quizás un ejemplo de un caso de uso típico sería útil.

Digamos que desea leer en la textura llamada " TankTexture.png " ;. Así es como creo que lo harías:

  1. Abra el archivo del paquete.
  2. Leer en el encabezado de tamaño fijo.
  3. Extraiga el desplazamiento del índice y el número de entradas del encabezado.
  4. Busque el inicio del índice.
  5. Lea el índice en una matriz (tamaño de entrada de índice fijo multiplicado por el número de entradas).
  6. Busque en el índice el activo denominado " TankTexture.png " ;.
  7. Extraiga el desplazamiento y el tamaño del activo de la entrada de índice.
  8. Busque el inicio del activo.
  9. Lea la cantidad de bytes dada por el tamaño del activo.

Por supuesto, para activos posteriores solo necesitaría los pasos 6-9.

Espero que eso ayude a explicar lo que estaba pensando. Avíseme si tiene alguna otra pregunta.

Si desea hacer esto con fines de aprendizaje, entonces el formato WAD es un buen lugar para comenzar. Sin embargo, propondría usar un formato de archivo fragmentado.
Por lo tanto, básicamente seguiría su formato propuesto (es decir, encabezado, tabla de contenido, etc.) pero para cada entrada de datos tendría una ID de fragmento que identifica qué tipo de datos es.
Esto tiene muchos beneficios, principalmente porque puede variar su formato de datos contra el formato de su código configurando su código para omitir fragmentos que no entienda; esto permite que el desarrollo de sus herramientas continúe mientras mantiene la compatibilidad con sus datos en su juego.

También recomendaría tener una entrada adicional de 'banderas' de 32 bits en su TOC que le permitiría usar un campo de bits para habilitar opciones como tipo de compresión, cifrado, etc.

Espero que ayude

Digo que su formato es una buena opción. Idealmente, desea obtener todos sus activos en una sola lectura. Por ejemplo, querría todos sus datos para el nivel 3 en el mismo paquete, de esa manera puede cargar todos sus datos de nivel en una lectura sin buscar. Está realmente bien tener un solo activo en más de un paquete. Solo necesita manejar el caso de que un activo ya esté cargado y omitirlo.

La forma en que divide sus datos debe depender de las dependencias entre sus datos (es decir, si una secuencia de comandos necesita un determinado modelo, ambos deben estar en el mismo paquete) y la granularidad que necesita para realizar sus lecturas (ej. si lees todos los datos de tu nivel de una vez? Luego puedes poner a tus enemigos en el paquete de niveles. Pero si tu juego se transmite en el mundo, tal vez necesites paquetes separados para los enemigos).

Realmente, el seguimiento de sus dependencias de datos es la parte difícil. En el momento de la compilación, desea conocer las dependencias de cada dato que ingresa. En el tiempo de ejecución, solo desea leer en su paquete y hacer que los activos se muestren en la memoria. También debe realizar un seguimiento de las dependencias en tiempo de ejecución porque necesitará saber qué es seguro DESCARGAR en cualquier momento dado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top