🎮 UnityDocs

Sistema de guardado con JSON

Receta para guardar y cargar partidas en un archivo JSON: una clase de datos serializable, JsonUtility y la ruta segura persistentDataPath. Con las trampas de JsonUtility que debes conocer.

🍳 RecetaIntermedio✅ RevisadoUnity 6.0 LTSActualizado 2026-07-15
DificultadConceptual Código Matemáticas
Tiempo📖 Lectura 7 min · ⌨️ Práctica 25 min

El objetivo#

Guardar el estado de la partida (nivel, vida, posición, ítems) en un archivo y volver a cargarlo. El enfoque estándar: convertir los datos a JSON (texto) y escribirlos en un archivo.

Paso 1 — Una clase de datos serializable#

Mete lo que quieras guardar en una clase marcada con [System.Serializable]:

C#
[System.Serializable]
public class DatosPartida
{
    public int nivel;
    public float vida;
    public Vector3 posicion;
    public int monedas;
    public string[] itemsRecogidos;
}

Paso 2 — Guardar y cargar#

C#
using System.IO;
using UnityEngine;

public class SistemaGuardado : MonoBehaviour
{
    // Ruta segura y válida en cualquier plataforma
    private string Ruta => Path.Combine(Application.persistentDataPath, "partida.json");

    public void Guardar(DatosPartida datos)
    {
        string json = JsonUtility.ToJson(datos, true);   // true = con formato legible
        File.WriteAllText(Ruta, json);
        Debug.Log("Guardado en: " + Ruta);
    }

    public DatosPartida Cargar()
    {
        if (!File.Exists(Ruta))
        {
            Debug.Log("No hay partida guardada");
            return null;
        }
        string json = File.ReadAllText(Ruta);
        return JsonUtility.FromJson<DatosPartida>(json);
    }

    public bool HayPartida() => File.Exists(Ruta);
    public void Borrar() { if (File.Exists(Ruta)) File.Delete(Ruta); }
}

Paso 3 — Usarlo#

C#
var sistema = GetComponent<SistemaGuardado>();

// Guardar
var datos = new DatosPartida {
    nivel = 3, vida = 80f,
    posicion = transform.position,
    monedas = 150,
    itemsRecogidos = new[] { "llave", "espada" }
};
sistema.Guardar(datos);

// Cargar
DatosPartida cargado = sistema.Cargar();
if (cargado != null)
    transform.position = cargado.posicion;

Por qué persistentDataPath#

Nunca guardes dentro de la carpeta del juego

Application.persistentDataPath apunta a una carpeta con permisos de escritura en cada plataforma (Windows, macOS, Android, iOS). Si intentas escribir dentro de la carpeta de la build o en Application.dataPath, en móvil o en una build instalada no tienes permiso y falla. persistentDataPath es la respuesta correcta siempre.

Las trampas de JsonUtility#

JsonUtility es rápido pero limitado

JsonUtility viene de serie y es eficiente, pero tiene límites que sorprenden:

  • No serializa Dictionary (ni tipos genéricos sueltos): envuélvelos en listas o usa listas de pares.
  • Solo serializa lo que Unity serializa: campos públicos o [SerializeField], no propiedades.
  • No maneja polimorfismo (guardar una lista de una clase base con objetos de derivadas).

Para casos complejos (diccionarios, polimorfismo), usa una librería como Newtonsoft Json.NET (disponible como paquete de Unity).

Buenas prácticas#

  • Versiona tus datos: añade un campo version para poder migrar guardados antiguos cuando cambies la estructura.
  • Guarda en momentos concretos (checkpoints, salir del nivel), no cada frame.
  • Para varias ranuras de guardado, usa nombres de archivo distintos (partida1.json, partida2.json).
  • Si te preocupa la manipulación, puedes cifrar el contenido, aunque para single-player rara vez merece la pena.

Errores frecuentes#

  • Guardar en dataPath en vez de persistentDataPath (falla en build/móvil).
  • Esperar que JsonUtility serialice un Dictionary (no lo hace).
  • Olvidar [System.Serializable] en la clase de datos (sale vacío).
  • No comprobar File.Exists antes de cargar (excepción si no hay guardado).
  • Guardar componentes de Unity directamente (guarda datos simples: números, strings, Vector3, no GameObjects).

Resumen#

Mete los datos en una clase [System.Serializable], conviértela con JsonUtility.ToJson y escríbela con File.WriteAllText en Application.persistentDataPath. Carga con File.ReadAllText + JsonUtility.FromJson. Recuerda las limitaciones de JsonUtility (nada de Dictionary ni polimorfismo; para eso, Json.NET), versiona tus datos y no uses PlayerPrefs para esto.

Fuentes y para profundizar