Salvando o Progresso: Um Sistema de Save e Load Simples com JSON na Unity

Você criou um personagem, coletou itens, passou de nível e derrotou o primeiro chefe. O jogador está investido na jornada. Mas se ele fechar o jogo, todo esse progresso se perde. A capacidade de salvar e carregar o estado do jogo é o que transforma uma sessão de jogo em uma experiência contínua e recompensadora.

Em um post anterior, discutimos as diferentes formas de armazenar dados. Hoje, vamos focar na abordagem mais comum, flexível e poderosa para jogos single-player: usar o formato JSON.

JSON (JavaScript Object Notation) é um formato de texto leve, legível para humanos e, ao mesmo tempo, fácil para as máquinas interpretarem, tornando-o perfeito para guardar os dados do nosso jogo. Neste guia, criaremos um sistema de Save e Load do zero.

1. A Estrutura dos Dados: O que Vamos Salvar?

Antes de salvar qualquer coisa, precisamos definir quais dados são importantes. Faremos isso criando uma classe C# simples que servirá como um “contêiner” para todas as informações do nosso save.

  1. Crie um novo script C# chamado GameData, mas não o anexe a nenhum objeto. Este script não será um MonoBehaviour.
  2. Abra o script e substitua seu conteúdo por este:
// Remova ": MonoBehaviour" se ele foi adicionado automaticamente.
// Adicione a tag [System.Serializable] para que a Unity possa converter esta classe.

[System.Serializable]
public class GameData {

    // Variáveis que queremos salvar.
    public int nivelDoJogador;
    public float saudeDoJogador;
    public Vector3 posicaoDoJogador;

    // Valores iniciais para um novo jogo.
    public GameData() {
        this.nivelDoJogador = 1;
        this.saudeDoJogador = 100f;
        this.posicaoDoJogador = Vector3.zero; // Posição inicial padrão
    }3
}

A “tag” [System.Serializable] é essencial. Ela sinaliza para a Unity que esta classe e suas variáveis públicas podem ser serializadas, ou seja, convertidas para um formato como o JSON. O construtor public GameData() define os valores padrão para quando um jogador começa um novo jogo.

2. O Gerenciador de Save/Load (SaveManager.cs)

Agora, vamos criar o cérebro do nosso sistema. Este será um Singleton, garantindo que tenhamos um ponto de acesso central para salvar e carregar o jogo de qualquer lugar do nosso código.

  1. Crie um novo script chamado SaveManager e anexe-o a um objeto vazio na cena (ex: SaveManagerObject).
  2. Implemente o padrão Singleton e as funções de Salvar e Carregar:
using UnityEngine;
using System.IO; // Essencial para lidar com arquivos!

public class SaveManager : MonoBehaviour {

    public static SaveManager instance;
    private string saveFilePath;

    void Awake() {

        // Configuração do Singleton
        if (instance == null) {
            instance = this;
            DontDestroyOnLoad(gameObject);
        } else {
            Destroy(gameObject);
        }

        // Define o caminho do arquivo de save
        saveFilePath = Path.Combine(Application.persistentDataPath, "savegame.json");

    }


    public void SalvarJogo(GameData data) {

        // Converte o objeto de dados para uma string JSON
        string json = JsonUtility.ToJson(data, true); // O 'true' formata o JSON para ser legível

        // Escreve a string JSON no arquivo
        File.WriteAllText(saveFilePath, json);

        Debug.Log("Jogo salvo com sucesso em: " + saveFilePath);

    }


    public GameData CarregarJogo() {

        // Verifica se o arquivo de save existe
        if (File.Exists(saveFilePath)) {
            // Lê o conteúdo do arquivo
            string json = File.ReadAllText(saveFilePath);

            // Converte a string JSON de volta para o objeto de dados
            GameData data = JsonUtility.FromJson<GameData>(json);

            Debug.Log("Jogo carregado com sucesso!");
            return data;
        } else {
            Debug.LogWarning("Nenhum arquivo de save encontrado! Criando um novo jogo.");
            // Retorna um novo GameData com valores padrão se não houver save
            return new GameData();
        }

    }

}

Ponto importante: Usamos Application.persistentDataPath. Este é o local mais seguro para salvar arquivos em qualquer plataforma (PC, Mac, mobile), pois é uma pasta onde seu jogo sempre terá permissão para escrever.

3. Colocando em Prática

Agora, como usamos isso? Você precisará de um script para coletar os dados do jogo e passá-los para o SaveManager. Por exemplo, em um Player.cs:

// Exemplo dentro do seu script do Jogador
public void SalvarEstado() {
    GameData data = new GameData();
    data.nivelDoJogador = this.nivel; // 'this.nivel' seria a variável de nível do seu jogador
    data.saudeDoJogador = this.saudeAtual; // 'this.saudeAtual' seria a vida atual
    data.posicaoDoJogador = transform.position;

    SaveManager.instance.SalvarJogo(data);
}


public void CarregarEstado() {
    GameData data = SaveManager.instance.CarregarJogo();

    this.nivel = data.nivelDoJogador;
    this.saudeAtual = data.saudeDoJogador;
    transform.position = data.posicaoDoJogador;
}

Você pode então chamar essas funções a partir de botões no seu menu: SalvarEstado() em um menu de pausa, e CarregarEstado() no botão “Continuar” do menu principal.

4. Segurança e Próximos Passos

É importante notar que, por padrão, o arquivo JSON é um texto simples e pode ser facilmente editado pelo jogador.

Para jogos onde a trapaça é uma preocupação, o próximo passo seria criptografar a string JSON antes de salvá-la e descriptografá-la depois de carregá-la. Embora isso adicione complexidade, é uma camada de segurança essencial para proteger os dados do seu save.

Outras ideias para evoluir o sistema incluem a criação de múltiplos “slots” de save (salvando arquivos com nomes diferentes, como savegame_1.json, savegame_2.json, etc.).

Conclusão

Com este sistema, você deu ao seu jogo uma memória. O progresso do jogador agora tem valor e persistência, transformando sua criação em uma experiência muito mais envolvente.

Saber como estruturar e salvar dados é uma habilidade que separa protótipos rápidos de projetos de longo prazo. Foi um dos passos que me ajudou a pensar em meus jogos não como “mais um projeto”, mas como uma experiência contínua e completa para o jogador.

Quer ver um sistema de save sendo implementado em um projeto real? Em nosso canal no YouTube, a PERAI DEV, construímos mecânicas como esta do zero. Inscreva-se para não perder nenhum passo!

Compartilhe !