EventoObtenha 50% de desconto no seu ingresso para MongoDB.local Londres em outubro 2. Use o código WEB50Saiba mais >>
Desenvolvedor MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
C#chevron-right

Salvando dados no Unity3D usando arquivos

Dominic Frei11 min read • Published Feb 09, 2022 • Updated Aug 09, 2024
UnityRealmC#
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
(Parte 2 da série de comparação de persistência)
A persistência de dados é uma parte importante da maioria dos jogos. A Unity oferece apenas um conjunto limitado de soluções, o que significa que também precisamos procurar outras opções.
Na parte 1 desta série, exploramos a solução da própria Unity: PlayerPrefs. Desta vez, examinamos uma das maneiras de usar a estrutura .NET subjacente salvando arquivos. Aqui está uma visão geral da série completa:
  • Parte 1: PlayerPrefs
  • Parte 2: Arquivos (este tutorial)
  • Parte 3: BinaryReader e BinaryWriter (em breve)
  • Parte 4: SQL
  • Parte 5: Realm Unity SDK
  • Parte 6: Comparação de todas essas opções
Como a Parte 1, este tutorial também pode ser encontrado no https://github.com/realm/unity-examples repositório na comparação de persistência ramificação.
Cada parte é classificada em uma pasta. Os três scripts que veremos neste tutorial estão na subpasta File. Mas, primeiro, vamos dar uma olhada no jogo de exemplo em si e no que temos de preparar no Unity antes de começarmos a codificação propriamente dita.

Exemplo de jogo

Observe que, se já tiver trabalhado em qualquer um dos outros tutoriais desta série, você pode pular esta seção, pois estamos usando o mesmo exemplo em todas as partes da série, para que seja mais fácil ver as diferenças entre as abordagens.
O objetivo desta série de tutoriais é mostrar a você uma maneira rápida e fácil de dar os primeiros passos nas várias formas de persistir os dados em seu jogo.
Portanto, o exemplo que usaremos será o mais simples possível no próprio editor para que possamos nos concentrar totalmente no código real que precisamos escrever.
Uma cápsula simples na cena será usada para que possamos interagir com um objeto de jogo. Em seguida, registramos os cliques na cápsula e mantemos a contagem de ocorrências.
Quando você abre um modelo de 3D limpo, basta escolher GameObject -> 3D Object -> Capsule.
Em seguida, você pode adicionar scripts à cápsula ativando-a na hierarquia e usando Add Component no inspetor.
Os scripts que adicionaremos a esta cápsula, apresentando os diferentes métodos, terão a mesma estrutura básica que pode ser encontrada em HitCountExample.cs.
A primeira coisa que precisamos adicionar é um contador para os cliques na cápsula (1). Adicione um [SerilizeField] aqui para que você possa observá-lo ao clicar na cápsula no editor Unity.
Sempre que o jogo for iniciado (2), queremos ler a contagem atual de acertos da persistência e inicializar hitCount de acordo (3). Isso é feito no método Start() que é chamado sempre que uma cena é carregada para cada objeto de jogo ao qual esse script está anexado.
A segunda parte disso é salvar as alterações, o que queremos fazer sempre que registrarmos um clique do mouse. A mensagem do Unity para isso é OnMouseDown() (4). Esse método é chamado toda vez que o GameObject ao qual esse script está anexado é clicado (com um clique do botão esquerdo do mouse). Nesse caso, incrementamos o hitCount (5) que, por fim, será salvo pelas várias opções mostradas nesta série de tutoriais.

arquivo

(Consulte FileExampleSimple.cs no repositório para ver a versão finalizada).
Uma das maneiras que o framework .NET nos oferece para salvar dados é usando a classeFile:
Fornece métodos estáticos para a criação, cópia, exclusão, movimentação e abertura de um único arquivo e auxilia na criação de objetos FileStream.
Além disso, a classeFile também é utilizada para manipular o próprio arquivo, lendo e escrevendo dados. Além disso, oferece maneiras de ler metadados de um arquivo, como hora da criação.
Ao trabalhar com um arquivo, você também pode usar várias opções para alterar FileMode ou FileAccess.
O FileStream mencionado na documentação é outra abordagem para trabalhar com esses arquivos, fornecendo opções adicionais. Neste tutorial, usaremos apenas a classeFilesimples.
Vamos dar uma olhada no que temos que alterar no exemplo apresentado na seção anterior para salvar os dados usando File:
Primeiro definimos um nome para o arquivo que conterá os dados (1). Se nenhum caminho adicional for fornecido, o arquivo será salvo apenas na pasta do projeto ao executar o jogo no editor Unity ou na pasta do jogo ao executar uma compilação. Isso é bom para o exemplo.
Sempre que clicarmos na cápsula (2) e aumentarmos a contagem de acertos (3), precisaremos salvar essa alteração. Usando File.WriteAllText() (4), o arquivo será aberto, os dados serão salvos e ele será fechado imediatamente. Além do nome do arquivo, essa função espera o conteúdo como uma string. Portanto, temos que transformar hitCount chamando ToString() antes de passá-lo adiante.
Da próxima vez que iniciarmos o jogo (5), queremos carregar os dados salvos anteriormente. Primeiro, verificamos se o arquivo já existe (6). Se não existir, nunca salvamos antes e podemos apenas manter o valor padrão para hitCount. Se o arquivo existir, usaremos ReadAllText() para obter esses dados (7). Como isso é uma string novamente, precisamos converter aqui também usando Int32.Parse() (8). Observe que isso significa que precisamos ter certeza do que lemos. Se a estrutura do arquivo for alterada ou o reprodutor edita, isso poderá causar problemas durante a análise do arquivo.
Vamos tentar estender esse exemplo simples na próxima seção.

Exemplo estendido

(Consulte FileExampleExtended.cs no repositório para ver a versão finalizada).
A seção anterior mostrou o exemplo mais simples, usando apenas uma variável que precisa ser salva. E se quisermos economizar mais do que isso?
Dependendo do que precisa ser salvo, há várias abordagens diferentes. Você pode usar vários arquivos ou escrever várias linhas dentro do mesmo arquivo. Este último deve ser mostrado nesta seção, estendendo o jogo para reconhecer as teclas modificadoras. Queremos detectar cliques normais, Shift+Clique e Control+Clique.
Primeiro, atualize as contagens de acertos para que possamos salvar três deles:
Também queremos usar um nome de arquivo diferente para que possamos ver as duas versões uma ao lado da outra:
O último campo que precisamos definir é a tecla pressionada:
A primeira coisa que precisamos fazer é verificar se uma tecla foi pressionada e qual chave era.O Unity oferece uma maneira fácil de fazer isso usando a funçãoInput da turma GetKey. Ele verifica se a chave fornecida foi pressionada ou não. Você pode passar a string para a chave ou, para ter um pouco mais de segurança, é só usar o enum KeyCode . No entanto , não podemos usar isso noOnMouseClick() ao detectar o clique do mouse:
Nota: os sinalizadores de entrada não são redefinidos até a atualização. Você deve fazer todas as chamadas de entrada no loop de atualização.
Adicione um novo método chamado Update() (1) que é chamado em cada quadro. Aqui precisamos verificar se a teclaShift ou Control foi pressionada (2) e, em caso afirmativo, salvar a tecla correspondente em modifier (3). Caso nenhuma dessas teclas tenha sido pressionada (4), nós a consideramos não modificada e redefinimos modifier ao seu default (5).
Agora, para salvar os dados quando um clique acontece:
Sempre que um clique do mouse é detectado na capsula (6), podemos realizar uma verificação semelhante ao que aconteceu em Update(), exceto que usamos modifier em vez de Input.GetKey() aqui.
Verifique se modifier foi definido como KeyCode.LeftShift ou KeyCode.LeftControl (7) e, em caso afirmativo, aumente a contagem de ocorrências correspondente (8). Se nenhum modificador foi usado (9), aumente o hitCountUnmodified.
Como visto na última seção, precisamos criar uma string que possa ser salva no arquivo. Há uma segunda função em File que aceita uma array de string e então salva cada entrada em uma linha: WriteAllLines().
Sabendo disso, criamos um array contendo as três contagens de acertos (11) e passamos este para File.WriteAllLines().
Inicie o jogo e clique na cápsula usando Shift e Control. Você deve ver os três contadores no Inspetor.
Depois de interromper o jogo e, portanto, salvar os dados, um novo arquivo hitCountFileExtended.txt deve existir na pasta do seu projeto. Dê uma olhada nele. Deve parecer algo assim:
Por último, mas não menos importante, vamos ver como carregar o arquivo novamente ao iniciar o jogo:
Primeiro, verificamos se o arquivo existe (12). Se já salvamos dados antes, esse deve ser o caso. Se existir, lemos os dados. Semelhante a escrever com WriteAllLines(), usamos ReadAllLines (13) para criar uma array de string onde cada entrada representa uma linha no arquivo.
Esperamos que haja três linhas, então devemos esperar que a matriz de string tenha três entradas (14).
Usando esse conhecimento, podemos então atribuir as três entradas da matriz às contagens de acertos correspondentes (15).
Desde que todos os dados salvos nessas linhas estejam juntos, o arquivo pode ser uma opção. Se você tiver várias propriedades diferentes, poderá criar vários arquivos. Como alternativa, você pode salvar todos os dados no mesmo arquivo usando um pouco de estrutura. Observe, no entanto, que os números não serão associados às propriedades. Se a estrutura do objeto mudar, precisaremos migrar o arquivo também e levar isso em consideração na próxima vez que abrirmos e lermos o arquivo.
Outra abordagem possível para estruturar seus dados será mostrada na próxima seção usando JSON.

Dados mais complexos

(Consulte FileExampleJson.cs no repositório para ver a versão finalizada).
JSON é uma abordagem muito comum ao salvar dados estruturados. É fácil de usar e existem frameworks para quase todas as linguagens. O framework .NET fornece um JsonSerializer. O Unity tem sua própria versão dele: JsonUtility.
Como você pode ver na documentação, a funcionalidade se resume a esses três métodos:
  • FromJson: Crie um objeto a partir de sua representação JSON.
  • FromJsonOverwrite: Substitui dados em um objeto lendo a partir de sua representação JSON.
  • ToJson: Gere uma representação JSON dos campos públicos de um objeto.
O JsonUtility transforma JSON em objetos e de volta. Portanto, nossa primeira alteração na seção anterior é definir tal objeto com campos públicos:
A classe em si pode ser private e apenas ser adicionada dentro da classeFileExampleJson, mas seus campos precisam ser públicos.
Como antes, usamos um arquivo diferente para salvar esses dados. Atualizar o nome do arquivo para:
Ao salvar os dados, usaremos o mesmo métodoUpdate() de antes para detectar qual tecla foi pressionada.
A primeira parte de OnMouseDown() (1) também pode permanecer a mesma, pois essa parte só aumenta a contagem de acertos dependendo do modificador usado.
No entanto, precisamos atualizar a segunda parte. Em vez de uma array de string, criamos um novo objetoHitCount e definimos os três campos públicos para os valores dos contadores de acessos (2).
Usando JsonUtility.ToJson(), podemos transformar este objeto em uma string (3). Se você passar em true para o segundo parâmetro opcional, prettyPrint, a string será formatada de forma legível.
Finalmente, como em FileExampleSimple.cs, acabamos de usar WriteAllText() porque estamos salvando apenas uma string, não uma array (4).
Então, quando o jogo começar, precisamos ler os dados novamente na contagem de acertos:
Verificamos se o arquivo existe primeiro (5). Caso isso aconteça, salvamos os dados antes e podemos continuar lendo-os.
Usando ReadAllText, lemos a string do arquivo e a transformamos, por meio de JsonUtility.FromJson<>(), em um objeto do tipo HitCount (6).
Se isso aconteceu com sucesso (7), podemos atribuir as três propriedades à contagem de ocorrências correspondente (8).
Ao executar o jogo, você verá que, no editor, ele parece idêntico à seção anterior, pois estamos usando os mesmos três contadores. Se você abrir o arquivo hitCountFileJson.txt, verá os três contadores em um JSON bem formatado.
Observe que os dados são salvos em texto simples. Em um tutorial futuro, veremos a criptografia e como melhorar a segurança de seus dados.

Conclusão

Neste tutorial, aprendemos a utilizar File para salvar dados. JsonUtility ajuda a estruturar esses dados. Eles são simples e fáceis de usar, e não é necessário muito código.
Quais são as desvantagens, embora?
Em primeiro lugar, abrimos, gravamos e salvamos o arquivo toda vez que a cápsula é clicada. Embora não seja um problema neste caso e certamente seja aplicável a alguns jogos, isso não funcionará muito bem quando muitas operações de salvamento forem feitas.
Além disso, os dados são salvos em texto simples e podem ser facilmente editados pelo jogador.
Quanto mais complexos forem seus dados, mais complexa será a manutenção dessa abordagem. E se a estrutura do objetoHitCountmudar? Você terá que alterar a conta para isso ao carregar uma versão mais antiga do JSON. As migrações são necessárias.
Nos tutoriais a seguir, veremos (entre outras coisas) como os bancos de dados podem facilitar muito esse trabalho e resolver os problemas que enfrentamos aqui.
Forneça feedback e faça qualquer pergunta no fórum da comunidade do Realm.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Adicionando o MongoDB Atlas Vector Search a um aplicativo .NET Blazor C#


Feb 29, 2024 | 10 min read
Tutorial

Criando um jogo de captura de espaço no Unity que sincroniza com o Realm e o MongoDB Atlas


Jun 26, 2024 | 24 min read
Tutorial

Como fazer pesquisa de texto completo em um aplicativo móvel com o MongoDB Realm


Jul 14, 2023 | 3 min read
Tutorial

Crie um jogo Infinite Runner com o Unity e o Realm Unity SDK


Feb 03, 2023 | 12 min read
Sumário
  • Exemplo de jogo