LoginSignup
0
0

インディーズゲームを作った時に便利だったUnity拡張の紹介② SQLiteを用いたセーブデータ編

Posted at

概要

別名義で活動しているのでタイトルは伏せさせていただきますが、個人でインディーズゲームを作成しておりました
その際に作って便利だったUnityの拡張などの機能や仕組みの紹介をします
今回はSQLiteを用いたセーブデータ編となります
基本的には生成物や生成前のデータ、最低限のロジックなどは説明しますがコードは記載しません
自身で作成する際のヒントになればと思います

生成前のXML

image.png

生成されるC#コード

///Don't write
///This is Generated Code

using System;
using System.Collections.Generic;
using System.Linq;
using Cysharp.Threading.Tasks;
using SQLite;
using UniRx;

[Table("GameData")]
public class GameDataEntity : EntityBase
{
    /// <summary>
    /// ユーザーID
    /// <summary>
    [PrimaryKey]
    [Column("user_id")]
    public int user_id { get; set; }
    /// <summary>
    /// 所持金
    /// <summary>
    [Column("money")]
    public int money { get; set; }

}

public class GameDataModel
{
    private static List<GameDataModel> items = null;

    public static IList<GameDataModel> Items
    {
        get
        {
            if(items == null)
            {
                GetAll();
            }
            return items;
        }
    }

    private GameDataEntity entity = new GameDataEntity();
    private CompositeDisposable disposable = new CompositeDisposable();
    
    public int UserId => entity.user_id;
    private ReactiveProperty<int> money = new ReactiveProperty<int>();
    public IReadOnlyReactiveProperty<int> Money => money;

    


    public static async UniTask<GameDataModel> Get()
    {  
        if(items == null)
        {
            await GetAll();
        }
        
        if(items.Exists(i => i.UserId == 0))
        {
            return items.First(i => i.UserId == 0);
        }

        var entity = new GameDataEntity();
        entity.user_id = 0;
        entity.money = default;

        await SaveDataCore.InsertData(entity);
        var model = new GameDataModel(entity);
        items.Add(model);
        return model;
    }

    private static async UniTask GetAll()
    {
        if (items == null)
        {
            var datas = await SaveDataCore.GetAllData<GameDataEntity>();
            var models = new List<GameDataModel>();
            foreach (var data in datas)
            {
                models.Add(new GameDataModel(data));
            }
            items = models;
        }
    }

    private GameDataModel(GameDataEntity _entity)
    {
        entity = _entity;
        money.Value = entity.money;
        money.Do(v => entity.money = v).Subscribe(_ => UpdateData()).AddTo(disposable);

    }

    private async UniTask UpdateData()
    {
        await SaveDataCore.UpdateData(entity);
    }
     
    public void UpdateMoney(int _money)
    {
        money.Value = _money;
    }

    
    ~GameDataModel()
    {
        disposable.Dispose();
    }
}

使用技術

  • XML
  • C#
  • System.Xml.Linq
  • SQLite-net
  • UniRX
    • いずれR3に置き換える
      となっております

こちらはC#のロジックにより作られているため、UniRX以外の部分はgodotエンジンに移植しても動作しました

↑のコード上ではSQLite-netがかなりラップされた状態のコードになってます
基本的にはTemprate用のTextファイルを用意して、文字を置き換えるような形で対応してます

自動生成の流れはこんな感じです

コンセプト

基本的にはXMLでセーブデータに関する機能が全部自動生成されるようにしたい
セーブデータを書き換えた場合は即保存したい
セーブデータの実データはDBのように扱いたい(デバックしやすくするため
これらの理由からSQLiteを採用しつつ↑のようなコードを自動生成する形となりました。

その他

↑の仕組みでは
マイグレーションについて触れてませんが、SQLite-netがかなりいい感じにやってくれます

SQLite-netが実際便利なので、SQLite側の機能はかなり甘えた仕組みになってます

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0