土屋つかさの技術ブログは今か無しか

土屋つかさが主にプログラミングについて語るブログです。

#unity (C#)でFlatBuffersを使い倒す(3) スキーマファイルからコードジェネレートする

FlatBuffersを使う流れ

 FlatBuffersを使用するには、以下の3つの手順を経る事になります。

  1. スキーマファイルを作り、flatc.exeでコードジェネレートする
  2. データをバイナリ配列にシリアライズしてファイルに保存する。
  3. ファイルからバイナリ配列を読み込みデシリアライズする。

 このうち1と2はゲーム開発時に行う処理、3はゲーム実行時に行う処理と言えます。
 今回はスキーマファイルについて解説します。

スキーマファイルの作成とコードジェネレート

 まずは扱うデータ構造の仕様(スキーマ)を定義するスキーマファイルを記述します。記述には専用の言語を使用します。ファイルの拡張子は*.fbs固定になります(FlatBufferSの略)。
 以下、今回使用するサンプルのスキーマファイル(test.fbs)になります。

namespace MyGame.Sample;

table Monster {
  mana:short = 150;
  hp:short = 100;
  cost:short = 150;
  name:string;
}

table MonsterList {
  items:[Monster];
}

root_type MonsterList;

 わかりやすさのため、一番下から順に解説していきます。

root_type MonsterList;

 "root_type"は構造化データツリーのrootのテーブル名を宣言します。FlatBuffersで管理するデータは、テーブルという要素でツリー形式に構造化されています(テーブル自体は構造体みたいな物です)。ここでは"MonsterList"をrootのテーブルに指定しています。
 なお、root_type宣言は、指定したテーブルの定義より後に記述しないとエラーになるようです(逆に、テーブル定義同士は依存しない模様)。

table MonsterList {
  items:[Monster];
}

 "table"はテーブルと、そのテーブルが持つフィールドを定義します。フィールドは"フィールド名:型;"という記法で宣言します。型にはint/short/float/stringなど一般的な物と、他のテーブルを指定できます。型名を中括弧で囲むと、そのフィールドがVector(参照配列)である事を示します。
 ここでは"MonsterList"テーブルを定義し、構成フィールド名に"items"を追加しています。itemsの型は"Monster"のVector型になります。

table Monster {
  mana:short = 150;
  hp:short = 100;
  cost:short = 150;
  name:string;
}

 テーブルMonsterを定義しています。フィールド宣言に"~= 値"で、フィールドの初期値を設定できます。FlatBuffersは、デフォルトでは全てのフィールドがオプション扱いであり、初期値を記述していないフィールドについても自動的に初期値が設定されるので注意してください。

namespace MyGame.Sample;

 "namespace"は名前空間を宣言します。ここで宣言した名前空間が、csファイル(と、出力コードのファイル構造)に直接反映されます。
 namespace宣言は、スキーマファイルのどこに配置してもいいのですが、宣言した以降のオブジェクトの名前空間を設定するので、先頭に書いた方が良いでしょう。

コードジェネレート

 作成したスキーマファイルをflatc.exeと同じフォルダに配置し、コマンドプロンプトで以下のように入力します。

>flatc.exe -n test.fbs

 "-n"オプションは.NET用のコード出力を指定しる物です。実行するとMyGame/Sampleフォルダが作られ、その下にMonster.cs/MonsterList.csの各ファイルが配置されます。このファイルをUnityのプロジェクトに追加します。今回はAssetsフォルダ直下に、MyGameフォルダを丸っとコピーしました。

続く

 無事コードジェネレートができたので、次回はシリアライズ/デシリアライズに挑戦します。