En este post voy a mostrar un poco los ScriptableObject, algo que Unity agregó no hace mucho tiempo y que tiene un gran para contener y guardar mucha información, tal como lo haría un prefab normal, aunque este está más pensado para guardar datos de configuración e items que podrían querer persistir.
INTRODUCCIÓN:
Como lo define la documentación de Unity, los ScriptableObjects son unos “grandiosos” contenedores de datos. Podemos utilizarlos para guardar la configuración entera de un juego, e incluso editarla desde código. Los valores nuevos que le asignemos podrán persistir a lo largo del juego, e incluso aunque este se cierre. Es básicamente como si fuera una variable que nos da acceso a un archivo, en el cual podemos escribir información tratándo dicho archivo como si fuera una clase, y luego Unity se encarga de la serialización, salvado, y todas esas cosas que son tooooodo un tema a la hora de desarrollar, más que nada por una cuestión de que cada plataforma para la que exportamos el proyecto tiene su propia forma de guardar datos. Con esto no tendríamos que preocuparnos de ello.
CÓMO CREAR UN SCRIPTABLEOBJECT:
Algo que no me termina de cerrar aún del todo es el método de creación, ya que no es tan sencillo como hacer “Click Derecho” => “Crear…“. Lo que sí podemos crear con click derecho es el script que va a corresponder al ScriptableObject. Y… Por qué necesita un script sí sólo quiero que almacene datos? Bueno… Es porque en realidad es una clase normal de C#, sólo que la vamos a usar únicamente para guardar datos, aunque eso no quita que no pueda tener funcionalidad. De hecho, este script podría tener una funcionalidad que reinicie los datos a sus valores por predeterminados.
IMPORTANTE:
Los ScriptableObjects NO GUARDAN datos entre una sesión y la otra AL BUILDEAR el juego!! Sólo se guardan si estamos en el editor. Pero al buildear siempre tienen los valores buildeados originales.
El ScriptableObject en sí mismo es un archivo, de extensión “.asset“. La instancia de ese ScriptableObject sería justamente ESE archivo. Pero para crearlo, lo tenemos que hacer mediante un script. Así que empecemos creando uno, que con más o menos esta forma:
using UnityEngine; public class MyGameConfig : ScriptableObject { }
Este sería el formato básico del ScriptableObject
. Pueden crear un script de la manera que lo harían comúnmente con Unity y luego cambiarle la parte que diga MonoBehaviour
(y borrar los métodos como Start()
y Update()
que aparecen predeterminadamente), o simplemente crearlo desde cero.
En cualquier caso, de esta manera sólo creamos la parte del script, pero no el archivo “.asset” que les había dicho. A continuación les muestro 2 maneras de crearlo.
La primera:
using UnityEngine; using UnityEditor; //fileName => Ruta del archivo junto con el nombre del mismo. //menuName => Ruta del menú, junto con el nombre del mismo. //order => La posición de este menú, dentro de la estructura de menues. [CreateAssetMenu(fileName = "Assets/MyGameConfigFile", menuName = "Assets/Create/Game Config File", order = 0)] public class MyGameConfig : ScriptableObject { }
La segunda:
using UnityEngine; using UnityEditor; public class MyGameConfig : ScriptableObject { //Esto es un atributo que hace que esta función aparezca en el menú de creación de Unity. [MenuItem("Assets/Create/Game Config File")] public static void CreateMyAsset() { //Esta línea es la que hace la magia en sí: Crea una instancia del ScriptableObject. MyScriptableObjectClass asset = ScriptableObject.CreateInstance(); //Crea el archivo ".asset" y lo guarda en la ruta especificada. AssetDatabase.CreateAsset(asset, "Assets/MyGameConfigFile.asset"); AssetDatabase.SaveAssets(); //Esto es para mostrar la ventana "Project", por si no está abierta. EditorUtility.FocusProjectWindow(); //Esto es para seleccionar el archivo recientemente creado. Selection.activeObject = asset; } }
Parece como bastante código para sólo crear un archivo, no? Pero si lo leen detenidamente, van a ver que no hacer nada de otro mundo, y en su mayoría son métodos que aunque no los hayan usado nunca, los nombres explican bastante bien lo que hacen. Igualmente les dejé los comentarios como para que se guíen un poco más.
ACLARACIÓN:
Al igual que comenté en algunos posts, a veces trato de usar ejemplos de Unity o formas de escritura que van a encontrar por internet simplemente para que al buscarlo en Google también se topen con ellos. Es más fácil, a mi parecer, si uso esos ejemplos, porque después si leen documentación van a refrescar de alguna manera lo que vieron.
La segunda es como una manera más… Elegante… De hacerla. Es más por si quieren personalizar el proceso de creación como ustedes gusten.
A partir de acá pueden empezar a agregarle variables como se las agregarían a cualquier MonoBehaviour
y aparecerán en el editor de Unity, al seleccionar el archivo “.asset” creado. Esto sigue las mismas “normas” de Unity: Los tipos de datos que pongan deben ser serializables si quieren que se vean. Así que es muy probable que quieran personalizar algunos campos con clases serializables y/o algunos CustomInspector para que quede más “lindo” todo. Y con esto ya podemos empezar a agregar valores:
using UnityEngine; using UnityEditor; //fileName => Ruta del archivo junto con el nombre del mismo. //menuName => Ruta del menú, junto con el nombre del mismo. //order => La posición de este menú, dentro de la estructura de menues. [CreateAssetMenu(fileName = "Assets/MyGameConfigFile", menuName = "Assets/Create/Game Config File", order = 0)] public class MyGameConfig : ScriptableObject { public float gameTime; public float speed; public int enemyCount; public string gameName; }
USANDO NUESTRO SCRIPTABLEOBJECT:
Nuestro ScriptableObject, de más está decir, también es un tipo de dato. Por ende, podemos crear una variable de su tipo, y arrastrarle literalmente ese script. Siguiendo el mismo ejemplo, con el mismo ScriptableObject que ya creamos, quedaría algo así:
using UnityEngine; public class TestingConfig : MonoBehaviour { public MyGameConfig gameConfig; void Start() { Debug.Log(gameConfig.enemyCount); } }
CONCLUSIÓN:
Este es el funcionamiento básico de los ScriptableObjects. La realidad es que pueden extenderlo muchísimo más, armando algún custom inspector, y personalizandolo a medida que van desarrollando el juego. Por ejemplo, podrían hacer que sean observables, que disparen eventos al ser modificados, podrían combinarlos con algún sistema para guardar partidas. Las posibilidades son tan grandes como la creatividad de ustedes para usarlos. ;).