はじめに
こんにちは、株式会社ルーデル 25卒の栗原です。
本記事では、レアゾンホールディングスの新卒エンジニア研修で行われたゲーム研修の中のマスターデータの講義の内容をご紹介します。
ゲーム研修って?
2週間の期間で下記内容の講義を受けました。
- 環境構築
- Unity基礎
- インゲーム
- ビルド
- マスターデータ
- アウトゲーム
- ゲームの改造
本記事はマスターデータに関する内容です。
マスターデータって?
マスターデータ=ゲーム実行中に変更しないデータ
ゲームのキャラクターのHPや攻撃力などのステータスのようなデータを格納する先のことをマスターデータと呼びます。
マスターデータの講義では、キャラクターのステータスをソースコードに直接書き込まずに、マスターデータから読み取るということを学びました。
なぜマスターデータを使うのか
コンパイル時間の短縮
Unityでゲームを作成している方ならお分かりかもしれませんが、ソースコードに少しでも修正が入った場合、コンパイルの時間が必要になります。
Unityのコンパイルの時間は意外と長く、PCのスペックにもよりますが10秒以上かかることもあります。
キャラクターのステータスの微調整のたびに待つ時間があるのはストレスです。
そこで、マスターデータを使うことによって、コンパイルの時間が不要になることでストレスフリーな開発を行うことができます。
データの調整が容易
プログラミングに慣れていない人がゲームのキャラクターのステータスの変更をする時にも、CSVファイルやJsonなどに変更を加えるだけなので容易に検証を行うことができます。
マスターデータを使ってみよう!
ここからは、実際に研修で作成したコードを交えながら、マスターデータの使い方を解説していきます。今回は、プレイヤーのステータスをJSONファイル、またはCSVファイルから読み込んで反映させる実装を見ていきましょう。
1. マスターデータの準備
まず、マスターデータとなるファイルを用意します。
今回マスターデータのデータ形式として使ったのはJSONとCSVです。
JSONの場合 (playerDataJsonVersion.json
)
JSON
{
"_id" : 1,
"_jumpPower" : 100,
"_speed" : 10,
"_mass" : 2,
"_color" : "#0000ff"
}
CSVの場合 (playerDataCsvVersion.csv
)
id,jumpPower,speed,mass,color
1,100,10,2,#0000ff
これらのファイルを、Unityプロジェクト内のResources
フォルダに配置します。Resources
フォルダに入れることで、後述するResources.Load
というメソッドで簡単にファイルにアクセスできるようになります。
2. マスターデータを格納するモデルクラスの作成
次に、読み込んだデータをプログラム上で扱うための「型」となるクラスを作成します。このPlayerMasterModel
は、JSONでもCSVでも共通で使います。
Player.cs (抜粋)
// Playerのマスターデータのモデルを定義する
public class PlayerMasterModel
{
[SerializeField] private int _id;
[SerializeField] private float _jumpPower;
[SerializeField] private float _speed;
[SerializeField] private float _mass;
[SerializeField] private Color _color;
public int Id => _id;
public float JumpPower => _jumpPower;
public float Speed => _speed;
public float Mass => _mass;
public Color Color => _color;
public PlayerMasterModel(int id, float jumpPower, float speed, float mass, Color color)
{
this._id = id;
this._jumpPower = jumpPower;
this._speed = speed;
this._mass = mass;
this._color = color;
}
}
マスターデータの各項目(カラム)と対応するフィールドを定義しているのがポイントです。
3. マスターデータを読み込む管理クラスの実装
マスターデータの読み込みや管理を専門に行うSimpleMasterManager.cs
を作成します。この中で、JSONを読み込む処理とCSVを読み込む処理を両方実装しました。
Load()
メソッドで、どちらの読み込み処理を呼ぶか切り替えます。(使わない方のメソッドをコメントアウトします)
SimpleMasterManager.cs(抜粋)
public void Load()
{
// ここでCSVを読み込むかJSONを読み込むかを選択する
LoadCsv();
//LoadJson();
}
JSONファイルで読み込む場合
LoadJson
メソッドでは、JsonUtility
を使ってJSONテキストをクラスオブジェクトに変換します。
今回の場合は先ほど作成したモデルクラス(PlayerMasterModel
)に変換することができます。
SimpleMasterManager.cs(抜粋)
private void LoadJson()
{
_playerData.Clear();
var jsonTextAsset = Resources.Load<TextAsset>("playerDataJsonVersion");
if (jsonTextAsset != null)
{
var tempData = JsonUtility.FromJson<PlayerMasterDataTemp>(jsonTextAsset.text);
ColorUtility.TryParseHtmlString(tempData._color, out Color color);
var loadedData = new PlayerMasterModel(
tempData._id, tempData._jumpPower, tempData._speed, tempData._mass, color
);
_playerData.Add(loadedData);
}
}
JsonUtility
は便利ですが、Color
型など一部の型を直接変換できないため、一度string
で受け取ってから変換する工夫を入れています。
CSVファイルで読み込む場合
LoadCsv
メソッドでは、ファイルを1行ずつ読み込み、カンマで分割してデータをパースしていきます。
SimpleMasterManager.cs(抜粋)
private void LoadCsv()
{
_playerData.Clear();
var csvTextAsset = Resources.Load<TextAsset>("playerDataCsvVersion");
if (csvTextAsset == null) return;
// テキストデータをStringReaderに変換
StringReader reader = new StringReader(csvTextAsset.text);
// 最初の行(ヘッダー)を読み飛ばす
reader.ReadLine();
// ファイルの終わりまで1行ずつ読み込む
while (reader.Peek() != -1)
{
// 1行をカンマで分割して配列に格納
string[] values = reader.ReadLine().Split(',');
// 各データを適切な型に変換
int id = int.Parse(values[0]);
float jumpPower = float.Parse(values[1]);
float speed = float.Parse(values[2]);
float mass = float.Parse(values[3]);
ColorUtility.TryParseHtmlString(values[4], out Color color);
// PlayerMasterModelを生成してリストに追加
var loadedData = new PlayerMasterModel(id, jumpPower, speed, mass, color);
_playerData.Add(loadedData);
}
}
こちらはJsonUtility
のような自動変換はないため、int.Parse
やfloat.Parse
を使って手動で型変換を行っています。
4. プレイヤーにデータを適用する
読み込み部分の実装は異なりますが、読み込んだ後のデータをプレイヤーに適用する部分は完全に共通です。
今回GetPlayerMasterDataの引数には1が入っていますが、これはマスターデータに格納されているIDです。
Player.cs (抜粋)
public void SetStatus()
{
int MasterDataId = 1;
PlayerMasterModel masterData = SimpleMasterManager.Instance.GetPlayerMasterData(MasterDataId);
if (masterData != null)
{
// 取得したデータで各プロパティを更新
this.jumpPower = masterData.JumpPower;
this.speed = masterData.Speed;
this.rigidBody.mass = masterData.Mass;
this.spriteRenderer.color = masterData.Color;
}
}
SimpleMasterManager.csでは、GetPlayerMasterDataメソッドを実装しています。
このメソッドは、引数と一致するIDのデータがあった場合データを返してくれます。
SimpleMasterManager.cs (抜粋)
public PlayerMasterModel GetPlayerMasterData(int id)
{
for(int i = 0; i < _playerData.Count; i++){
if(_playerData[i].Id == id){
return _playerData[i];
}
}
return null;
}
5.ゲームマネージャーで呼び出す
最後に、今まで用意したメソッドを呼び出すGameManagerを実装します。
GameManagerのStartメソッドでは、マスターデータを読み込んで、プレイヤーに適用します。
GameManager.cs (抜粋)
private void Start()
{
// 1. 最初にマスターデータをメモリに読み込む
SimpleMasterManager.Instance.Load();
// 2. 次に、そのデータをプレイヤーに適用(初期化)する
player.SetStatus();
}
ゲーム内のボタンのメソッドに下記を用意しておくと、ゲームプレイ中でもPlayerのステータスを変更することができます。
GameManager.cs (抜粋)
public void OnClickLoadMasterButton()
{
// 同様に、まずデータを再読み込みしてから...
SimpleMasterManager.Instance.Load();
// プレイヤーのステータスを更新する
player.SetStatus();
}
6.概略図
まとめ
今回の研修を通して、マスターデータを導入するメリットを身をもって体験することができました。
- コンパイル不要でパラメータを調整できる
- エンジニア以外の人でも簡単にバランス調整ができる
本記事が、これからUnityでゲーム開発を始める方や、マスターデータについて学んでいる方の参考になれば幸いです。 最後までお読みいただきありがとうございました。
▼採用情報
レアゾン・ホールディングスは、「世界一の企業へ」というビジョンを掲げ、「新しい"当たり前"を作り続ける」というミッションを推進しています。
現在、エンジニア採用を積極的に行っておりますので、ご興味をお持ちいただけましたら、ぜひ下記リンクからご応募ください。