マスタデータを作る(1)(Unityメモ)
Unityのエディタ拡張に手を出した
マスタデータとシステム本体を分ける
マスタデータはシステムを実際に使う上で必要なデータを指します。ゲームの場合、ユニットの能力値やマップ情報、キャラ画像などを指します。
マスタデータはユーザデータと違ってユーザの使用中に変更することはありません。それでも大抵の場合、マスタデータはシステムの外部に別建てで用意します。システムの実装部分に直書きするとアップデート時に変更しづらいのと、マスタデータをシステム本体と分けておいた方が分業しやすいためです。
それと制作中のゲームは周回ゲームのため、新キャラやイベントマップなど、コンテンツをシステム運用中に追加しやすいほうがよいです。実際にそうするかはともかく。
マスタデータの保存方法とフォルダ構成
マスタデータはゲームシステム本体と分けて保存するので、マスタデータの保存方法によって、プロジェクトのフォルダ構成が変わってきます。
プロジェクトのフォルダ構成については以下の記事が参考になりました。
https://gentome.com/gentomeblog/2435/unityfolder/ ※最も参考にした記事だが、2023-08-29現在アクセス不能(SSL証明書の期限切れ)
一括で保存
小さなゲームでしか採用できない方法ですが、フォルダ一個にマスタデータのファイルをすべて放り込みます。ファイル名でデータを区別します。データの管理方法を特に設計しなくても良い、というのは利点です。
一括で保存・DBライブラリを使用
マスタデータをデータベース化する方法です。画像等のデータもバイナリデータとしてDBに登録します。
DBライブラリにデータ管理やリモート処理を任せられるのが最大の利点です。オンラインゲームを作る場合はこの方法になります。データベースの設計がコスト高です。
フォルダに分ける・ファイル種別ごと
マスタデータを、スクリプトや画像ファイルなどのファイル種別ごとにフォルダに整理して保存します。
分かりやすい方法ですが、ゲームコンテンツの追加が意外とやりづらいことが知られていない、という点が弱点です。(開発時に気づかれず運用し始めて初めて気づかれるため)
なおユニットデータを一個のアセットにまとめる方法もこちらに相当します。(後述)
フォルダに分ける・用途ごと
マスタデータを、キャラクタやマップといったデータの用途ごとにフォルダに分けて保存します。
ゲームコンテンツをまとめて追加しやすいのが利点です。半面、同種のデータが散らばるため読み込み処理を実装する手間がかかるのが欠点です。
制作中のゲームのフォルダ構成は、コンテンツの追加のしやすさを採用し、用途ごとにマスタデータのフォルダを分けることにしました。現状は以下のように作っています。
なお、「ヤード」については以前の記事を見てください。大まかには保守責任の分掌という意味合いです。
※Assets/ 以下のフォルダ。自動生成されるもの、アセットストア、Editorは省略
※アルファベット順ではなく、意味が分かりやすいよう並び替えている
Content/ マスタデータ(画像、音声、.assetファイルなど。一部はソースコードも)
Character/ キャラクタデータ(能力値・画像など)
(キャラクタごとにサブフォルダを切る)
Ability/ スキル・装備・アイテム
(項目ごとにサブフォルダを切る)
Effect/ Abilityのエフェクト演出
(エフェクト演出ごとにサブフォルダを切る)
Decision/ 行動決定ルーチン
Map/ マップデータ
(マップごとにサブフォルダを切る)
BackgroundImage/ 背景画像
GUI/ GUI用のアセット。アイコン画像等
Font/ フォントデータ
BGM/ BGM用音声ファイル
SE/ SE用音声ファイル
Source/ ソースコード
Core/ 共通のライブラリ
Domain/ Domainヤード(能力値定義、戦闘などゲームルールの定義)
Hub/ Hubヤード(ヤード間の情報伝達)
Repository/ Repositoryヤード(永続化データ処理。外部ライブラリ依存)
View/ Viewヤード(ゲーム内GUIの共通処理。Unity依存)
Widget/ GUIウィジェットの実装(Prefabデータ。Viewヤードの一部)
Service/ サービスの実装(ヤードをまたぐ処理。ユニット一覧表示機能、セーブ処理など)
UseCase/ ユースケースの実装(サービスの連携。セーブ処理~ダイアログ表示など)
Scene/ 各シーンの実装(ホーム、戦闘、マップなど)
マスタデータを用途ごとにフォルダ分けした場合、運用中に限らず開発中でもマップなどを追加しやすいのは便利だと思います。読み込み処理の実装の手間は呑むことにしました。
実際の所、マスタデータの保存方法とプロジェクトのフォルダ構成は鶏と卵の関係になっていることに気づきました。つまりマスタデータの保存方法を決めようとするとプロジェクトのフォルダ構成に制約され、逆にプロジェクトのフォルダ構成はマスタデータの保存方法によって制約を受けます。どこかで許容するデメリットを決断する必要がありました。
Unityの場合
Unityの場合、マスタデータのデータベースシステムがあります。そう、AssetDatabaseとAddressablesです。Assetが広い意味でのマスタデータに相当します。
UnityではAssetsフォルダの下にプロジェクトで使用するすべてのファイルを置くのですが、その際にソースコードとマスタデータ類をフォルダに分けても問題なくゲームをビルドできます。さらにAddressablesの機能として、アセットにラベルを複数種つけることができ、かつラベル名でプロジェクト内のアセットを絞り込んで一括ロードが出来ます。
マスタデータのフォルダ構成に関して、個々のキャラクタや個々のマップ単位でサブフォルダを切ると、同種のアセットがサブフォルダに分散することになります。そこで"UnitParameter", "Map" のようにファイル種別をラベルとしてアセットにつけておくと、サブフォルダを横断してアセットをファイル種別で一括ロードできる、というわけです。アセットに"Preload"のラベルをつけてプリロードすることもできます("UnitParameter" "Preload" のように複数ラベル可)。
というわけで、Unityの場合はデータの用途ごとに細かくフォルダに分けてマスタデータを保存しても、Addressablesの機能を使ってデータの種別ごとのロードができます。
実のところ、マスタデータを用途ごとにフォルダ分けするよう決めたのも、このAddressablesの機能を利用できると分かったためです。
思ったより記事が長くなったので、続きを次の記事に分割しました。