Banco de dados em ScriptableObject com sistema de salvar / carregar

Introdução



Cada jogo possui dados com os quais os designers de jogos trabalham. No RPG, esse é um banco de dados de itens, em match-3 - o custo em cristais de ferramentas da loja, em jogos de ação - a quantidade de HP que o kit de primeiros socorros cura.



Existem muitas maneiras de armazenar esses dados - alguém os armazena em tabelas, em arquivos xml ou json, que edita com suas próprias ferramentas. O Unity oferece seu próprio caminho - Scriptable Objects (SO), do qual gosto porque você não precisa escrever seu próprio editor para sua apresentação visual, é fácil vincular os recursos do jogo e uns aos outros e, com o advento dos endereçáveis, esses dados podem ser fácil e convenientemente armazenados fora jogos e atualização separadamente.



Neste artigo, gostaria de falar sobre minha biblioteca SODatabase, com a qual você pode criar, editar e usar convenientemente no jogo (editar e serializar) objetos de script.



Criação e edição de SO



Eu crio e edito SOs em uma janela separada, que é um pouco semelhante às janelas do projeto com um inspetor - à esquerda há uma árvore de pastas (a pasta na qual todos os SOs estão localizados - um grupo em endereçáveis) e à direita está o inspetor do SO selecionado.



Interface



Para desenhar esse WindowEditor, uso a biblioteca Odin Inspector . Além disso, eu uso a serialização para SO desta biblioteca - ela estende muito a serialização unitium padrão, permitindo que classes polimórficas, aninhamento profundo e referências de classe sejam armazenados.



Criando SO



Novos SOs são criados clicando em um botão nesta janela - lá você precisa selecionar o tipo de bipé desejado, e ele é criado na pasta. Para que o tipo de SO apareça nesta janela como uma opção, o SO deve herdar de DataNode, que tem apenas um 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 ( ). .



A biblioteca está disponível publicamente no github . Escrito usando Nullable de c # 8, portanto, requer Unity 2020.1.4 como uma versão mínima.




All Articles