Base de datos en ScriptableObject con sistema de guardar / cargar

Introducción



Cada juego tiene datos con los que trabajan los diseñadores de juegos. En RPG, esta es una base de datos de elementos, en match-3 - el costo en cristales de herramientas de la tienda, en juegos de acción - la cantidad de HP que cura el botiquín de primeros auxilios.



Hay muchas formas de almacenar dichos datos: alguien los almacena en tablas, en archivos xml o json, que edita con sus propias herramientas. Unity ofrece su propio camino: Objetos programables (SO), que me gustan porque no es necesario que escriba su propio editor para su representación visual, es fácil vincular los activos del juego y entre sí, y con la llegada de Addressables, estos datos se pueden almacenar de manera fácil y conveniente fuera juegos y actualizar por separado.



En este artículo, me gustaría hablar sobre mi biblioteca SODatabase, con la que puede crear, editar y usar convenientemente en el juego (editar y serializar) objetos programables.



Crear y editar SO



Creo y edito SO en una ventana separada, que es algo similar a las ventanas del proyecto con un inspector: a la izquierda hay un árbol de carpetas (la carpeta en la que se encuentran todos los SO, un grupo en direccionables), y a la derecha está el inspector del SO seleccionado.



Interfaz



Para dibujar un WindowEditor de este tipo, utilizo la biblioteca Odin Inspector . Además, utilizo la serialización para SO de esta biblioteca: amplía en gran medida la serialización de unitium estándar al permitir que se almacenen clases polimórficas, anidación profunda y referencias de clase.



Creando SO



Los nuevos SO se crean haciendo clic en un botón en esta ventana; allí debe seleccionar el tipo de bípode deseado y se crea en la carpeta. Para que el tipo SO aparezca en esta ventana como una opción, SO debe heredar de DataNode, que tiene solo un campo adicional para ScriptableObject



public string FullPath { get; }


SO, .



SO



- , , SO - , — , , SO.

static SODatabase , , .



public static T GetModel<T>(string path) where T : DataNode   

public static List<T> GetModels<T>(string path, bool includeSubFolders = false) where T : DataNode


, SODatabase , Addressables.





ScriptableObject , . ScriptableObject . , SO .



— , , - , . , SO . , unity, xml .



, ScriptableObject JSON.



DataNode — SO, SODatabase,



[JsonObject(MemberSerialization.OptIn, IsReference = true)]


JsonProperty save.txt . SODatabase addressables JsonConvert.PopulateObject SODatabase, .



, , SO ( , JsonProperty) -, SO . — . , , , .





-



async void Awake()
{
    await SODatabase.InitAsync(null, null);
    await SODatabase.LoadAsync();
}




private void OnApplicationPause(bool pauseStatus)
{
    if (pauseStatus)
        SODatabase.Save();
}

private void OnApplicationQuit()
{
    SODatabase.Save();
}        


PlayerSO, — , , . - , SODatabase, .



public class PlayerSO : DataNode
{
    public static string Path => "PlayerInfo/Player";

    [JsonProperty]
    public string Title = string.Empty;

    [JsonProperty]
    public int Experience;
}


PlayerInventorySO, ( SO SODatabase).



 public class PlayerInventorySO : DataNode
 {
     public static string Path => "PlayerInfo/PlayerInventory";

     [JsonProperty]
     public List<ItemSO> Items = new List<ItemSO>();
 }


, — , . , , QuestSO (, , ..) . - .



public class QuestNode : BaseNode
{
    public static string Path = "QuestNodes";

    //Editor
    public virtual string Title { get; } = string.Empty;

    public virtual string Description { get; } = string.Empty;

    public int TargetCount;

    //Runtime
    [JsonProperty]
    private bool finished;
    public bool Finished
    {
        get => finished;
        set => finished = value;
    }
}


, JsonProperty , SO .



var playerSO = SODatabase.GetModel<PlayerSO>(PlayerSO.Path);
var playerInventorySO = SODatabase.GetModel<PlayerInventorySO>(PlayerInventorySO.Path);
var questNodes = SODatabase.GetModels<QuestNode>(QuestNode.Path, true);




— - / , , SO, json. - , ( ..) . SO , SODatabase , Addressables.



addressables ( ). .



La biblioteca está disponible públicamente en github . Escrito con Nullable de c # 8, por lo tanto, requiere Unity 2020.1.4 como versión mínima.




All Articles