🎮 UnityDocs

ScriptableObject: datos como assets

Qué es un ScriptableObject, qué problema resuelve frente a MonoBehaviour, cómo usarlo para configurar armas o enemigos sin duplicar datos, y por qué es la base de arquitecturas dirigidas por datos.

📄 ArtículoAvanzado✅ RevisadoUnity 6.0 LTSActualizado 2026-07-14
DificultadConceptual Código Matemáticas
Tiempo📖 Lectura 9 min · ⌨️ Práctica 25 min

Qué es#

Un ScriptableObject es un contenedor de datos que vive como asset en tu proyecto, no pegado a un GameObject ni a una escena. Piensa en él como una "ficha de datos" reutilizable: la defines una vez y la referencias desde donde quieras.

El problema que resuelve#

Imagina 100 enemigos "Goblin" en pantalla. Si guardas sus stats (vida, daño, velocidad) en un MonoBehaviour, cada uno de los 100 lleva su propia copia de esos números en memoria, aunque sean idénticos. Y si quieres cambiar el daño del goblin, ¿editas los 100?

Con un ScriptableObject, los 100 goblins apuntan al mismo asset de datos. Un solo sitio que editar, una sola copia en memoria.

⚖️ Comparativa · MonoBehaviour vs ScriptableObject
MonoBehaviourScriptableObject
Vive enUn GameObject, en una escenaUn asset en el proyecto
Tiene ciclo de vida (Update…)No (no se adjunta a objetos)
Copias en memoriaUna por instanciaUna compartida
Ideal paraComportamiento en escenaDatos y configuración

Crear uno#

C#
using UnityEngine;

// Añade la opción al menú Assets > Create
[CreateAssetMenu(fileName = "NuevaArma", menuName = "Juego/Arma")]
public class ArmaData : ScriptableObject
{
    public string nombre;
    public int daño = 10;
    public float cadencia = 0.5f;
    public Sprite icono;
    public GameObject prefabProyectil;
}

Ahora, clic derecho en el Project → Create → Juego → Arma, y creas "Pistola", "Escopeta", "Rifle" como assets independientes que un diseñador puede balancear sin tocar código.

Usarlo#

C#
public class Arma : MonoBehaviour
{
    [SerializeField] private ArmaData datos;   // arrastras "Escopeta" aquí

    void Disparar()
    {
        Debug.Log($"Disparando {datos.nombre}, daño {datos.daño}");
        Instantiate(datos.prefabProyectil, transform.position, transform.rotation);
    }
}
Diseñadores felices

Este patrón separa datos de comportamiento. El programador escribe la lógica del arma una vez; el diseñador crea y ajusta decenas de armas como assets. Es el corazón del diseño data-driven.

Más allá de los datos: SO como sistema#

Los ScriptableObjects no solo guardan datos estáticos; pueden ser piezas de arquitectura:

  • Variables compartidas: un FloatVariable como asset al que varios sistemas acceden, en vez de un Singleton.
  • Canales de eventos: un GameEvent como asset; unos lo lanzan y otros lo escuchan, sin referencias directas entre escenas. Combina genial con eventos.
  • Estados y configuraciones: dificultad, tablas de loot, definiciones de niveles.
🎬 Por dentro · ¿Se guardan los cambios en runtime?

Cuidado: en el editor, modificar un ScriptableObject en Play persiste tras salir de Play (estás editando el asset real). En una build, los cambios en runtime no se guardan al cerrar. Por eso un SO no sirve como sistema de guardado de partidas: úsalo para datos de diseño, no para el progreso del jugador. Para eso, serializa a JSON.

Cuándo NO usarlo#

  • Para el estado que cambia durante la partida y debe persistir (vida actual, inventario del jugador): eso va en runtime + guardado, no en el asset.
  • Para lógica con ciclo de vida (necesitas Update): eso es un MonoBehaviour.

Errores frecuentes#

  • Modificar un SO en runtime esperando que en la build se guarde (no pasa).
  • Meter estado mutable de partida en un SO compartido (todos comparten el mismo dato sin querer).
  • Olvidar [CreateAssetMenu] y no poder crear el asset desde el editor.

Ponte a prueba#

📝 Pon a prueba lo aprendido

Resumen#

El ScriptableObject guarda datos como asset, independientes de escenas y GameObjects: una sola copia compartida, un solo sitio que editar. Perfecto para configurar armas, enemigos e ítems, y como base de arquitecturas data-driven y de eventos. No lo uses para el estado de partida que deba persistir en una build.

Fuentes y para profundizar