ScriptableObject(すくりぷたぶるおぶじぇくと)はとても便利な機能です。マスターデータとして作成したり、シーン間に依存しない参照先のオブジェクトとしても利用できます。
ScriptableObject(すくりぷたぶるおぶじぇくと)とは
まずはScriptableObjectがどんなものなのかをざっくりと把握しましょう。
シーンに依存しないオブジェクト・コンポーネント
Unityでは通常シーン内のオブジェクトにスクリプト(コンポーネント)をアタッチしてゲーム制作を行います。ところがこのScriptableObjectはシーン内のオブジェクトに対してインスペクターで数値を設定するようにメンバ変数のパラメータを変更することができます。
ScriptableObjectはこの特性を使って、シーンをまたいだ設計や、プレファブからの参照を受け付けることが可能です。
主な使われ方・用途
スクリプタブルオブジェクトは主に次のような場面で用いられます
- マスターデータとしての利用
- 唯一の設定ファイル(シングルトン的な扱い)
- イベントの中継地点
ゲームの重要なデータをマスターテーブルのような使い方が一番使われている方法だと思います。サーバークライアント型のゲームだと、サーバー側の普遍的なマスターデータテーブルがスクリプタブルオブジェクトと言えるでしょう。
また、ゲームはユーザーごとにコンフィグ設定を行うことがあると思います。設定したシーンと実際に使われるシーンが離れている場合に、なんらかの方法でその設定値を参照する必要がありますが、スクリプタブルオブジェクトを利用することでこの問題は簡単に解決します。
イベントの中継地点というのはイベントのリスナー・センダーをつなぐためのオブジェクトをスクリプタブルオブジェクトに行わせる方法です。イベントを発信する相手がシーン内にいない状態からイベントの受信処理を作ることが出来るため、設計が非常に楽になります。(やや難しいので今回は省略します)
スクリプタブルオブジェクトの作り方
じゃあ早速スクリプタブルオブジェクトを使って見ましょう。以下の工程で進めたいと思います。
- ScriptableObject用のスクリプトを作成
- アセット作成(スクリプタブルオブジェクト本体)
- 外部スクリプトから確認
スクリプタブルオブジェクトのスクリプト
ここでは設定ファイルになりえるようなスクリプタブルオブジェクトConfigを作りたいと思います。通常のスクリプトと違って注意する点は以下を踏まえて作成します。
- 継承するクラスをScriptableObjectに変更
- クラス定義の上の行にCreateAssetMenuに関する設定を追加
- menuName:コンテキストメニューの項目
- fileName:新規作成されるときのファイル名(オプション)
- order:コンテキストメニューの順番(オプション)
- メンバ変数の追加
- なくても一応大丈夫ですが、いるよね
下記サンプルスクリプトではメジャーな変数を突っ込んでます。実際に利用する場合は適した変数名などに変えてください。
using UnityEngine;
[CreateAssetMenu(menuName = "ゲーム名/Config", fileName = "初期ファイル名", order = 1)]
public class Config : ScriptableObject
{
public int intValue;
public float floatValue;
public string stringValue;
public bool boolValue;
public Vector3 vector3Value;
public Color colorValue;
}
アセット作成
スクリプトが作成できたら、以下の手順でスクリプタブルオブジェクトを作成しましょう。
- プロジェクトビューで右クリックコンテキストメニューを開く
- Create>ゲーム名>Configを選択
- アセットが生成される
- 名前を変えたりインスペクターでパラメータを変更してみてください
- テスト確認用として以下の様に設定
- intValue : 123
- floatValue : 456.789
- stringValue : testConfig
- 他は何でもいいです
コンテキストメニューはスラッシュ( / )を挟むことで階層を加えることができます。
出来上がったアセットはこんな感じ。実際にはスクリプタブルオブジェクトを管理するフォルダにいれるのが良いですね。
確認用のスクリプト
実際にアセットが作れたので、確認をしましょう。このスクリプト自体はスクリプタブルオブジェクト固有という感じではありません。スクリプト名は「TestScriptableObject」とかにしましょう。
using UnityEngine;
using UnityEngine.SceneManagement;
public class TestingScriptableObject : MonoBehaviour
{
public Config config;
private void Start()
{
Debug.Log(config.intValue);
Debug.Log(config.floatValue);
Debug.Log(config.stringValue);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
SceneManager.LoadScene("SampleScene");
}
}
}
作成できたら下記手順でコンソール画面を利用しながらチェック!
- 空のGameObjectを作成
- TestingScriptableObjectをアタッチ
- インスペクターに作成済みのスクリプタブルオブジェクトをセット
- ゲームを動かしてConsoleで設定済みのパラメータが表示されるか確認
- スクリプタブルオブジェクトのパラメータを更新
- ゲームを動かしたままインスペクターのパラメーターを異なる値に変更してください
- (本当は止めても構わないんですが、連続性を感じやすいのでそのままやろう)
- スペースキーを押してシーンのリロード
- 再びConsoleビューを確認して、変更後のパラメータが表示されていればOK
ちなみに作業中のシーンがSampleSceneで、SampleSceneがBuildSettingsに設定されている前提です!
ScriptableObjectを扱う上での注意点
ここからは利用する際の注意点。取り扱いは慎重に。
Editorではパラメータが更新されたままになる
先程の確認を行ったときに気づいたかも知れませんが、シーン内のインスペクターと異なり、ゲームを停止してもパラメータが更新されたままになります。
ところがスマートフォンなどのアプリでは、アプリが再起動された場合などで最初の状態に戻ります。Editor上でもちょっと特殊なので以下の内容を覚えておいてください。
- 再生中のスクリプタブルオブジェクトの更新された値は、停止してもその値を一時的に保持する
- これは再度プレイしたときに以前のパラメータを利用します
- 再生中に更新したパラメータをスクリプタブルオブジェクトの正式な値にしたい場合、エディタ機能を利用する必要がありますが、これはアプリには含められません。
- 参考キーワード:SetDirty , SaveAssets , Refresh
- 再生をしていない状態で更新した場合、スクリプタブルオブジェクトの正式な値として扱われます
- これはアプリ動作中に更新された値を無視して設定されます。
- この値はUnityエディタを再起動すると反映されます。
上記を正しく理解しておいてください。でないと、ScriptableObjectでそのままセーブ機能が使えると勘違いしてしまう可能性があります。スクリプタブルオブジェクトはデータ保存の目的では使えません。一時的なテンポラリ、他シーンなどでの共有を得意としています。
コメント