Pergunta

Então, eu estou tentando trabalhar no meu próprio jogo 3d pequena. Agora estou mais ou menos fazendo isso para aprender C #. Fiquei me perguntando, qual é a melhor metodologia para a embalagem de ativos, como texturas / scripts?

Geralmente o que eu estava pensando em fazer foi o seguinte:

[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]
.
.

Agora eu só quero que ele loja, imagens simples e arquivos de texto. Eu tenho feito alguns olhando ao redor e a melhor coisa que eu realmente encontrei foi um velho exemplo de como Doom punhado são armazenados.

Alguém tem alguma experiência?

Foi útil?

Solução

Isso é bom. Se você pode carregar tudo na memória virtual e vamos trocar lidar com isso, então você pode usar qualquer formato, realmente. Se você quiser acesso aleatório a apenas um registro (assim, por exemplo, você pode carregar preguiçosamente, embora memmap descompactado também é preguiçoso), então você provavelmente vai querer manter o índice na memória.

A maioria das pessoas usam uma biblioteca que lhes dá acesso a um arquivo .zip, .jar, .pak (formato terremoto), ou outro semelhante (comprimido ou não) formato de arquivo, como se fosse parte do sistema de arquivos (isto é, registros são acessados ??por teclas de cordas). Eu definitivamente ir por esse caminho se você pode encontrar uma biblioteca já feito, por exemplo, truezip para Java. Apache Commons tem um, mas eu não sei como é fácil de integrar w / NET (que é uma grande base de código C Eu acredito). Zipfs parece que é um arquivo montador .NET zip real que detém apenas os cabeçalhos na memória.

Ou, provavelmente com apenas um pouco de conveniência menos, você poderia usar DotNetZip diretamente

Outras dicas

Não desperdice o seu tempo inventando o seu próprio formato de armazenamento.

Você pode usar SharpZipLib ou outra biblioteca de compressão livre para .net. Com ele, você também pode embalar vários arquivos em um arquivo e extrair os arquivos que deseja separadamente sob demanda.

Seu projeto parece ser bom para mim, embora eu suponho que você significou 32 pedaços para o tamanho, em vez de 32 bytes !

Eu acho que seu projeto seria melhor para situações em que você deseja carregar todos os seus ativos de uma só vez, porque é um tipo de projeto sequencial. Se você quiser carregar apenas alguns ativos por um tempo (talvez porque cada nível jogo usa apenas um subconjunto dos ativos), então seria um pouco menos eficiente, porque você teria que ler através de cada ativo em vez de encontrar os que você deseja.

Nesse caso, você pode querer tentar um design mais indexada, talvez algo como isto:

[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]
.
.

Isto permitirá melhor acesso aleatório de ativos, porque agora você só tem que procurar através de seu índice (que você carregar na memória) e não através de todo o seu arquivo (que pode não caber na memória). Se você quiser começar a fantasia, você poderia usar uma árvore ou hashtable para o índice.

A razão para colocar o índice no final do arquivo ao invés da frente é que ele torna mais fácil para adicionar mais um trunfo para o seu arquivo de pacote sem ter que reconstruir a coisa toda. Caso contrário, a entrada extra em seu índice seria jogar fora todos os seus deslocamentos.


EDIT: para responder aos comentários ...

O que eu tinha em mente era que você só poderia acessar os ativos através do índice, por isso espero que você nunca iria correr para fora da extremidade dos ativos quando lê-los. Talvez um exemplo de um caso de uso típico ajudaria.

Say você queria ler na textura chamada "TankTexture.png". Aqui está como eu acho que você vai fazer sobre isso:

  1. Abra o arquivo do pacote.
  2. Leia no cabeçalho de tamanho fixo.
  3. Extrai-se a compensar o índice e o número de entradas a partir do cabeçalho.
  4. Procure o início do índice.
  5. Ler o índice em uma matriz (índice fixo entrada vezes o tamanho número de entradas).
  6. Pesquisar o índice para o ativo chamado de "TankTexture.png".
  7. Extraia o deslocamento ativo e tamanho da entrada de índice.
  8. Procure o início do ativo.
  9. Leia no número de bytes dadas pelo volume de ativos.

Claro que, para ativos posteriores você precisa a poucos passos de 6-9.

Espero que ajuda a explicar o que eu estava pensando. Deixe-me saber se você tiver quaisquer outras perguntas.

Se você quiser fazer isso para fins de aprendizagem, em seguida, o formato de WAD é um bom lugar para começar. No entanto, eu proponho usando um formato de arquivo em partes.
Por isso, basicamente, seguir o seu formato proposto (ou seja cabeçalho, TOC etc), mas para cada entrada de dados você teria um ID pedaço que identifica o tipo de dados que é.
Isto tem muitos benefícios, principalmente, que você pode variar o seu formato de dados contra o seu formato de código, definindo o código para pular pedaços que não entendem - isto permite o seu desenvolvimento de ferramentas para continuar mantendo compatibilidade com versões anteriores de seus dados em seu jogo.

Eu também recomendo ter uma entrada extra de 32 bit 'bandeiras' em seu TOC que permitem que você use um campo de bits para permitir opções como tipo de compactação, criptografia etc

Espero que ajude

Eu digo o seu formato é uma boa escolha. Idealmente, você quer puxar em todos os seus ativos em uma leitura. Por exemplo, você iria querer todos os seus dados para o nível 3 no mesmo pacote, de que maneira você pode carregar todos os seus dados nível em uma leitura sem procurar. Sua realmente ok para ter um único ativo em mais de um pacote. Você só precisa lidar com o caso de que um ativo já está carregado e ignorá-lo.

Como você dividir seus dados deve ser dependente das dependências entre os seus dados (ou seja, se um script precisa de um determinado modelo, eles devem ser ao mesmo tempo no mesmo pacote) e como granular que você precisa para tornar a sua lê (ex. Pode você lê todos os seus dados de nível de uma só vez? Então você pode colocar seus inimigos no pacote de nível. Mas se o jogo flui no mundo, talvez você necessita de separar pacotes para os inimigos.)

Realmente, monitoramento você dependências de dados é a parte mais difícil. Em tempo de compilação que você quer saber as dependências de cada pedaço de dados que puxam em. Em tempo de execução que você só quer ler no seu pacote e têm os ativos aparecem na memória. Você também precisa controlar dependências em tempo de execução porque você precisa saber o que é seguro para o descarregamento, a qualquer momento dar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top