次の連休
五月のGWを過ぎると次の連休まで二ヶ月以上空いている事に軽い絶望を覚える五月病予備軍の皆さんこんにちは。ここから五連勤の週が10週続きます、なんだそれ。税金を増やす減らすとか賃金が上がる上がらないとか以前に休みを増やすことを考えても罰は当たらないと思う。
近況
制作中のリズムゲーム「Under A Groove」ですが、GW中はバグ修正とステージ選択画面の作成に勤しんでました。このゲームは特に発売日を決めず、Tokyo Inide Games Summit等の展示会イベントに合わせて新しいステージを披露していく開発スケジュールを取っており、展示会イベントで披露・試遊してもらうのはその新ステージのみ(既存のステージは見せない)という形にしていますが、今後のことも考えて既存のステージも遊んでもらえるようにステージ選択の画面(シーン)を作成しました。
作成したステージ選択画面
現状では上の動画でも分かるように未だ3ステージしか作ってませんが、今後ステージ数が増えていくことを考えると選択画面に表示するデータはソースに埋め込むのではなくマスタデータとして管理していきたい、それも出来ればロードが高速で検索も簡単にできる形で・・・といわけで、そういった用途には一番適しているデータ保存形式であろうMasterMemoryを導入することにしました。
MasterMemoryの導入
MasterMemoryはCysharp社が開発したアセットですがライセンスの範囲内であれば誰で無料で使用することができます。特徴としては高速かつ軽量なデータ管理ライブラリで、読み取り専用のデータ管理を得意とします。
このMasterMemoryの導入にはMasterMemoryが依存するMessagePack for C#の導入が先だって必要でそれに伴う設定変更も行うことになりますが、NuGetForUnityを使えばそういった事を省いて比較的簡単にUnityプロジェクト内に導入することができます。
よって先にPackageManagerからNuGetForUnityを導入します。PackageManagerウィンドウ左上の + ボタンを押下し、「Add package from git URL...」を選択して以下のURLを入力、Addボタンを押します。
https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity
NuGetForUnityを導入するとUnity上部のMenu内にNuGetForUnityの項目が増えるので、そこからManage NuGet Packages を選択します。
パッケージ検索ウィンドウが開くので、「MasterMemory」を検索してインストールします。
MasterMemoryの仕組み
MasterMemoryは、静的なバイナリ形式でデータを保存します。つまり、CSVやJsonなどに保存している原本データは一度そのデータをバイナリ形式に変換して保存しておく必要があります。そしてこのバイナリ形式に変換する際にインデックスを付加することで検索性能を最適化しています。
例えば以下のようなデータ構造のクラスをゲーム内でマスタデータとして取り扱い場合は
// クラスにMemoryTableアトリビュートをつける // クラスにMessagePackObjectアトリビュートをつける [MemoryTable("Music"), MessagePackObject(true)] public sealed class MusicData { // プライマリキーにはPrimaryKeyアトリビュートをつける [PrimaryKey] public string Id { get; set; } public string MusicName { get; set; } public int MusicBPM { get; set; } public string PlayTime { get; set; } }
マスタデータを格納したデータクラス(配列)を作成してDatabaseBuilderを使ってバイナリデータに変換してファイルに保存
var musicMasters = new MusicData[] { new("001", "Music1", 88, "02:35"), new("002", "Music2", 117, "01:30"), new("003", "Music3", 88, "02:30") }; // DatabaseBuilderを使ってバイナリデータを生成する var databaseBuilder = new DatabaseBuilder(); databaseBuilder.Append(musicMasters); var binary = databaseBuilder.Build(); // できたバイナリは永続化しておく var path = "Assets/Resources/Binary/MusicData.bytes"; var directory = Path.GetDirectoryName(path); if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); File.WriteAllBytes(path, binary);
そして参照側ではMemoryDatabaseに変換したバイナリデータを読み込み、そこから検索キーを指定した検索を行って目的のデータを取得
var path = "Assets/Resources/Binary/MusicData.bytes"; var asset = AssetDatabase.LoadAssetAtPath<TextAsset>(path); var binary = asset.bytes; var memoryDatabase = new MemoryDatabase(binary); var data = memoryDatabase.MusicDataTable.FindById("001");
という手順になります。
ちょっとややい越しいのでMasterMemoryを使ったデータの流れを図で表してみます。
ここまでのまとめ
MasterMemoryは高速な検索と任意のデータ構造に対応したマスタデータを管理するには大変便利なアセットです。
データはバイナリ形式で保持され、効率的にメモリを使用するためメモリ消費は少ないですし、インデックスが作られる為に大量データでも短時間でクエリ処理が可能となっています。
しかしデータには変換工程が必要で、準備に時間がかかるのがデメリットと言えます。
今回は例としてのマスタデータをソース内に定義して、それ以後の変換工程と取得手順を紹介しましたが、次回は実際にゲームで使用することを想定してマスタデータをJson形式で定義し、それをDatabaseBuilderを使ってバイナリデータに変換する手順を紹介したいと思います。