PlayerPrefs na Unity: Salvar Recorde e Opções
PlayerPrefs na Unity é um armazenamento simples de chave e valor para guardar preferências entre sessões: o recorde, o volume da música, a qualidade gráfica escolhida. Com PlayerPrefs.SetInt("HighScore", 1200) você grava, com PlayerPrefs.GetInt("HighScore", 0) você lê na próxima vez que o jogo abrir. Este tutorial de Unity PlayerPrefs monta o recorde e a tela de opções, mostra onde os dados ficam em cada plataforma e traça a linha de quando parar de usar PlayerPrefs e partir para um save de verdade.
As informações de armazenamento seguem a referência oficial do Unity 6.3 LTS, conferida em outubro de 2026.
O que é PlayerPrefs na Unity
PlayerPrefs é uma classe estática que guarda três tipos de valor: int, float e string. Cada valor tem uma chave em texto. Os métodos são poucos:
SetInt,SetFloat,SetString: gravam um valor numa chave.GetInt,GetFloat,GetString: leem, com um valor padrão opcional para quando a chave não existe.HasKey: diz se a chave existe.DeleteKeyeDeleteAll: apagam uma chave ou todas.Save: força a gravação no disco.
O nome entrega a intenção: player preferences. Foi pensado para configurações do jogador, não para o progresso do jogo. Essa distinção é o fio do post inteiro.
Não existe SetBool. Para booleanos, a convenção é gravar 1 ou 0 com SetInt.
Salvando e lendo recorde
O recorde é o caso de uso perfeito: um número, que muda pouco, e que precisa sobreviver ao jogo fechar. Arquivo HighScore.cs:
using UnityEngine;
public class HighScore : MonoBehaviour
{
private const string HighScoreKey = "HighScore";
[SerializeField] private int currentScore;
public int Best { get; private set; }
private void Awake()
{
Best = PlayerPrefs.GetInt(HighScoreKey, 0);
}
public void AddPoints(int amount)
{
currentScore += amount;
}
public bool SubmitFinalScore()
{
if (currentScore <= Best)
{
return false;
}
Best = currentScore;
PlayerPrefs.SetInt(HighScoreKey, Best);
PlayerPrefs.Save();
return true;
}
}
Decisões que importam:
- A chave numa constante. Digitar
"HighScore"em dois lugares e errar uma letra em um deles gera um bug silencioso: o jogo grava numa chave e lê de outra. Comconst, o compilador cuida disso. - Valor padrão no
GetInt. Na primeira vez que o jogo abre, a chave não existe e oGetIntdevolve o padrão (0). Sem precisar deHasKey. Savesó no fim da partida. O manual avisa que gravar pode causar engasgos e recomenda não chamarSavedurante o gameplay. A tela de fim de partida é o momento natural. A Unity também grava sozinha noOnApplicationQuit, mas um fechamento forçado (o celular matando o app, um travamento) pode pular essa etapa, por isso oSaveexplícito no momento certo.
Se você já fez isso no Godot, o raciocínio é o mesmo do post sobre pontuação e recorde no Godot, com a diferença de que lá o recorde costuma ir para um arquivo.
Salvando opções de volume e qualidade
Opções são o outro uso clássico. Arquivo GameSettings.cs:
using UnityEngine;
public class GameSettings : MonoBehaviour
{
private const string MasterVolumeKey = "Settings.MasterVolume";
private const string QualityKey = "Settings.Quality";
private const string FullscreenKey = "Settings.Fullscreen";
public float MasterVolume { get; private set; }
public int QualityLevel { get; private set; }
public bool Fullscreen { get; private set; }
private void Awake()
{
MasterVolume = PlayerPrefs.GetFloat(MasterVolumeKey, 0.8f);
QualityLevel = PlayerPrefs.GetInt(QualityKey, QualitySettings.GetQualityLevel());
Fullscreen = PlayerPrefs.GetInt(FullscreenKey, 1) == 1;
Apply();
}
public void SetMasterVolume(float value)
{
MasterVolume = Mathf.Clamp01(value);
AudioListener.volume = MasterVolume;
PlayerPrefs.SetFloat(MasterVolumeKey, MasterVolume);
}
public void SetQuality(int level)
{
int maxLevel = QualitySettings.names.Length - 1;
QualityLevel = Mathf.Clamp(level, 0, maxLevel);
QualitySettings.SetQualityLevel(QualityLevel, true);
PlayerPrefs.SetInt(QualityKey, QualityLevel);
}
public void SetFullscreen(bool value)
{
Fullscreen = value;
Screen.fullScreen = value;
PlayerPrefs.SetInt(FullscreenKey, value ? 1 : 0);
}
public void ConfirmAndSave()
{
PlayerPrefs.Save();
}
private void Apply()
{
AudioListener.volume = MasterVolume;
QualitySettings.SetQualityLevel(Mathf.Clamp(QualityLevel, 0, QualitySettings.names.Length - 1), true);
Screen.fullScreen = Fullscreen;
}
}
Ligue os métodos aos controles da UI: um Slider (de 0 a 1) chama SetMasterVolume no evento On Value Changed, um Dropdown chama SetQuality e um Toggle chama SetFullscreen. O botão "Voltar" do menu chama ConfirmAndSave.
Repare no prefixo Settings. nas chaves. Com dezenas de chaves, um prefixo por área evita colisão e facilita achar tudo no registro. E o Mathf.Clamp na qualidade protege contra um valor salvo numa versão anterior do jogo que tinha mais níveis de qualidade do que a atual.
Para volume por categoria (música, efeitos, voz), o caminho é um Audio Mixer com parâmetros expostos; o PlayerPrefs só guarda o número de cada um.
HasKey, DeleteKey e Save
HasKey serve quando o valor padrão não basta para decidir. O caso típico é "primeira vez que o jogador abre o jogo":
if (!PlayerPrefs.HasKey("Tutorial.Done"))
{
// mostra o tutorial
PlayerPrefs.SetInt("Tutorial.Done", 1);
PlayerPrefs.Save();
}
DeleteKey apaga uma chave: útil para um botão "Zerar recorde". DeleteAll apaga tudo do jogo, o que você quer num botão "Restaurar padrões" ou durante o desenvolvimento.
No editor, há um atalho para limpar tudo: Edit > Clear All PlayerPrefs. Use antes de testar o fluxo de primeira execução. E lembre que o editor e a build guardam em lugares diferentes (próxima seção), então limpar no editor não limpa a build instalada.
Onde o PlayerPrefs fica no Windows, Mac, Android e WebGL
Segundo a referência do Unity 6.3:
| Plataforma | Onde fica |
|---|---|
| Windows (build) | Registro: HKEY_CURRENT_USER\Software\NomeDaEmpresa\NomeDoProduto |
| Windows (editor) | Registro: HKEY_CURRENT_USER\Software\Unity\UnityEditor\NomeDaEmpresa\NomeDoProduto |
| macOS (build) | ~/Library/Preferences/ num arquivo .plist com o identificador do app |
| Linux | ~/.config/unity3d/NomeDaEmpresa/NomeDoProduto |
| Android | /data/data/nome-do-pacote/shared_prefs/nome-do-pacote.v2.playerprefs.xml (API SharedPreferences) |
| iOS | API NSUserDefaults do sistema |
| Web | IndexedDB do navegador, até 1 MB |
NomeDaEmpresa e NomeDoProduto são os campos Company Name e Product Name em Edit > Project Settings > Player. Consequência prática: trocar o nome da empresa ou do produto depois de publicar faz o jogo procurar as preferências em outro lugar, e o jogador "perde" o recorde. Defina esses nomes no começo e não mexa mais.
Outro detalhe do Windows: no registro, a Unity acrescenta um hash ao nome da chave no registro (algo como HighScore_h1234567), para permitir chaves com diferença de maiúsculas e evitar conflito. Se for procurar no regedit, procure pelo começo do nome.
No Web, o limite de 1 MB e o fato de os dados ficarem no navegador significam que limpar os dados do site apaga tudo, e que abrir o jogo em outro navegador começa do zero.
Recorde e opções são a parte fácil do save. O resto (inventário, fases liberadas, posição, missões) é onde o projeto começa a exigir arquitetura de verdade, e é o ponto em que muita gente desiste do jogo por não saber estruturar dados que crescem junto com ele.
Erros comuns com PlayerPrefs
Ler com o tipo errado. Gravou com SetFloat e leu com GetInt? A chave existe, mas com outro tipo, e o GetInt não devolve o número que você gravou (em geral volta o valor padrão). O recorde parece "zerado" sem nenhum erro no Console. Mantenha cada chave sempre com o mesmo tipo, e as constantes com o nome do tipo ajudam (VolumeFloat, por exemplo, se o projeto for grande).
Testar no editor e achar que a build vai lembrar. Editor e build gravam em chaves diferentes do registro. O recorde que você bateu testando no editor não aparece na build, e vice-versa. Não é bug, é o comportamento esperado.
Mudar Company Name ou Product Name depois de publicar. O jogo passa a ler outro caminho, e para o jogador parece que tudo foi apagado. Se for inevitável, leia as chaves antigas uma vez e copie para as novas numa atualização de transição.
Chamar Save a cada frame ou a cada moeda coletada. Funciona no seu PC rápido e engasga em celular mais simples. Grave nos momentos naturais: fim de fase, saída do menu de opções, pausa.
Esquecer o OnApplicationPause no mobile. No Android e no iOS o sistema pode matar o app em segundo plano sem passar pelo OnApplicationQuit. Um PlayerPrefs.Save() no OnApplicationPause(bool paused) quando paused for verdadeiro garante que as opções sobrevivam.
Chaves espalhadas pelo código. Com o projeto crescendo, juntar todas as chaves numa classe estática (PrefsKeys.HighScore, PrefsKeys.MasterVolume) evita duplicata e deixa fácil ver tudo que o jogo guarda.
Quando NÃO usar PlayerPrefs
PlayerPrefs é ótimo dentro do nome dele. Fora disso, atrapalha:
- Progresso do jogo. Fases liberadas, inventário, moedas, posição. São dados estruturados (listas, objetos dentro de objetos), e PlayerPrefs só tem
int,floatestring. Você acaba inventando chaves comoItem_0_Id,Item_0_Qtd,Item_1_Id... e qualquer mudança vira migração manual. - Dados que o jogador não deve editar. O manual diz que os dados ficam sem criptografia e pede para não guardar informação sensível ali. No Windows, qualquer um abre o
regedite muda o número de moedas. - Vários slots de save. Dá para simular com prefixos, mas um arquivo por slot é muito mais simples de listar, copiar e apagar.
- Muito volume de dados. No Web, o teto é 1 MB. Em qualquer plataforma, guardar um JSON gigante numa string do registro é pedir problema.
A regra que uso: se o dado é uma escolha do jogador sobre como o jogo funciona (volume, idioma, controles, qualidade) ou um número solto (recorde), PlayerPrefs. Se é o estado do mundo do jogo, arquivo de save. No Godot a separação é a mesma, como mostra o post sobre sistema de save e load no Godot.
Próximo passo: save com JSON
Implemente o HighScore e o GameSettings deste post, feche e abra o jogo para confirmar que tudo volta como estava, e depois use Edit > Clear All PlayerPrefs para testar a primeira execução. Quando o seu jogo precisar guardar inventário, fases ou qualquer lista, siga para o sistema de save com JSON na Unity, que grava uma classe inteira num arquivo com versionamento.
Perguntas frequentes
Onde o PlayerPrefs fica salvo no Windows?
Numa build, no registro do Windows, em HKEY_CURRENT_USER\Software\NomeDaEmpresa\NomeDoProduto. Quando você testa no editor, a chave é outra: HKEY_CURRENT_USER\Software\Unity\UnityEditor\NomeDaEmpresa\NomeDoProduto. Os nomes vêm de Edit > Project Settings > Player.
PlayerPrefs é seguro para salvar moedas e progresso?
Não. O manual da Unity diz que o PlayerPrefs é guardado sem criptografia e recomenda não usá-lo para dados sensíveis. Qualquer jogador consegue editar o registro ou o arquivo de preferências. Para progresso, use um arquivo de save próprio.
Preciso chamar PlayerPrefs.Save?
A Unity grava automaticamente quando o jogo fecha normalmente (OnApplicationQuit). Chamar Save garante a gravação antes disso, o que protege contra fechamento forçado ou queda do aplicativo. O manual recomenda não chamar durante o gameplay, porque a gravação pode causar engasgos.
Qual a alternativa ao PlayerPrefs na Unity?
Para qualquer coisa além de preferências simples, a alternativa padrão é serializar uma classe de save para JSON com JsonUtility e gravar num arquivo em Application.persistentDataPath. Isso suporta listas, estruturas aninhadas e versionamento do save.



