La idea#
Partimos del guardado con JSON. Para tener varias partidas, la clave es sencilla: un archivo por ranura (slot_0.json, slot_1.json...) y unos metadatos para que el menú de "Cargar partida" muestre información sin cargar la partida entera.
Paso 1 — Datos con metadatos#
Incluye en tus datos lo que el menú necesita mostrar de un vistazo:
[System.Serializable]
public class DatosPartida
{
public int version = 1; // para migrar guardados antiguos
public string nombre;
public int nivel;
public float vida;
public int monedas;
public float tiempoJugado; // segundos
public string fechaGuardado; // para ordenar/mostrar
}Paso 2 — El gestor de ranuras#
using System.IO;
using UnityEngine;
public static class GestorGuardado
{
static string Ruta(int slot) =>
Path.Combine(Application.persistentDataPath, $"slot_{slot}.json");
public static void Guardar(int slot, DatosPartida datos)
{
datos.fechaGuardado = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm");
File.WriteAllText(Ruta(slot), JsonUtility.ToJson(datos, true));
}
public static DatosPartida Cargar(int slot)
{
string ruta = Ruta(slot);
if (!File.Exists(ruta)) return null; // ranura vacía
return JsonUtility.FromJson<DatosPartida>(File.ReadAllText(ruta));
}
public static bool Existe(int slot) => File.Exists(Ruta(slot));
public static void Borrar(int slot)
{
if (File.Exists(Ruta(slot))) File.Delete(Ruta(slot));
}
}Aquí el gestor es una clase static: son utilidades puras (leer/escribir archivos) sin estado propio, así que no necesitas ponerla en un GameObject ni un Singleton. GestorGuardado.Guardar(0, datos) y listo.
Paso 3 — El menú de cargar#
Para cada ranura (0, 1, 2...), muestra un botón. Si Existe(slot), carga solo los metadatos para pintar "Nivel 3 · 2h 15m · 2026-07-15"; si no, muestra "Ranura vacía".
void PintarRanura(int slot, TextMeshProUGUI etiqueta)
{
DatosPartida d = GestorGuardado.Cargar(slot);
etiqueta.text = d == null
? "— Ranura vacía —"
: $"{d.nombre} · Nivel {d.nivel} · {d.fechaGuardado}";
}Al pulsar una ranura con partida, cargas sus datos y vas a la escena correspondiente (SceneManager); al pulsar una vacía, empiezas una partida nueva en ese slot.
Paso 4 — Autoguardado y ranura rápida#
Muchos juegos reservan una ranura especial para el autoguardado (por ejemplo slot_auto.json) que se sobrescribe en los checkpoints, además de las ranuras manuales del jugador.
Versionado: pensar en el futuro#
Cuando publiques una actualización que cambie la estructura de DatosPartida, los guardados viejos pueden romperse. El campo version te permite detectar un guardado antiguo y migrarlo (rellenar los campos nuevos con valores por defecto) en vez de fallar. Un save system serio siempre versiona.
Errores frecuentes#
- Un solo archivo para todo (no puedes tener varias partidas).
- Cargar la partida completa solo para mostrar el menú (carga solo metadatos).
- Guardar fuera de
persistentDataPath(falla en build/móvil). - No versionar y romper los guardados al actualizar el juego.
- No contemplar la ranura vacía (
Cargardevuelvenull).
Resumen#
Un archivo por ranura (slot_N.json) en persistentDataPath, con metadatos (nivel, tiempo, fecha) para pintar el menú sin cargar la partida entera. Un gestor static con Guardar/Cargar/Existe/Borrar, una ranura de autoguardado aparte, y un campo version para migrar guardados antiguos. Todo construido sobre el guardado JSON básico.