いんでぃーづ

ゲームいろいろ、いろいろ自由

Unity : ScriptableObject解体新書(?)

共有データ保存になんとなく使っていた ScriptableObject について、いろいろ研究してみました。
そして、今までいろいろ間違った使い方をしていたことに気づきました。

目次

ScriptableObject インスタンスを参照(生成)する方法

インスペクタでシリアライズ

シーン内の MonoBehaviour オブジェクトに設定して置く方法。

f:id:sugar_affordance:20170429132940j:plain

注意したいのは、シーン内に間接的にリンクされたオブジェクトが存在する場合、メモリが確保されてしまうということです。

たとえば下のような、ScriptableObjectを持ったプレハブを

f:id:sugar_affordance:20170429094610j:plain

シーン内のオブジェクトにリンクしてしまうと

f:id:sugar_affordance:20170429094634j:plain

ScriptableObjectのメモリが確保され、さらにScriptableObject#Awakeなどのライフサイクル関数も呼ばれます

あらゆるテーブルをScriptableObjectにして、一つのオブジェクトにリンクするようなことはやめておきませう。

Resource.Load

Resourcesフォルダの下に ScriptableObject のアセットを置くことで、動的にロードすることができます。

例えばプロジェクト内に以下のように配置しておけば

f:id:sugar_affordance:20170429095150j:plain

下のソースで動的に ScriptableObject を読み込むことができます。

// EnemyDataTable はScriptableObjectを継承したクラス

EnemyDataTable table = Resources.Load("EnemyDataTable") as EnemyDataTable;

ライフサイクル関数は Load 関数実行時に呼ばれます。
たぶん、必要なタイミングでのみScriptableObjectを参照したい(メモリをなるべく確保したくない)と思ったときに、最終的に行き着くところがコレ。

嬉しいのは、Awake, OnEnableなどのライフサイクル系の関数は、初回にLoadしたときのみ呼ばれるところ。
つまりメモリも初回Load時のみ確保されていると思われる。

ScriptableObject.CreateInstance

新しくインスタンスが確保されます。
インスタンスが別なので、メモリ領域は別々に確保されます。

EnemyDataTable EnemyDataTable = ScriptableObject.CreateInstance<EnemyDataTable>();

プログラムから生成しているので、データのシリアライズなどはできませんので値を初期化する必要があります。
違う数値を持つScriptableObjectをスクリプトから作成したいときに使うかも?

ただ、値をコピーして別インスタンスにしたい場合は ↓

ScriptableObject.Instantiate

この関数を使えば、インスタンスを新しく確保できます。

EnemyDataTable = ScriptableObject.Instantiate(Resources.Load("EnemyDataTable")) as EnemyDataTable;

これで確保したインスタンスScriptableObject.Destroy で開放すると、OnDisable, OnDestroy メソッド が呼ばれます。
上記ライフサイクル関数を使いたい場合は有用かもしれません。

ライフサイクル関数

ScriptableObjectには、MonoBehaviourのStartなどにあたる関数として、AwakeやOnEnableなどがあります。

注意しなければならないのは、エディタ上で実行するのと、ビルドしたプログラムを実行するのとでは、呼ばれるタイミングが全く違うということ!

Awake, OnEnable

この二つの使い分けがよくわからないので一緒に書いておく。

  • エディタ
    Unity起動後、はじめてプロジェクト内でScriptableObjectを選択してインスペクタに表示したときに呼ばれます。

  • ビルド後
    ScriptableObjectの参照が発生したときに呼ばれます。
    シーン内に間接的にリンクされたオブジェクトが Instantiate された、Resources.Load した、など。

呼ばれる順番は

コンストラクタ > Awake > OnEnable

です。

OnDisable, OnDestroy

この二つの使い分けもよくわからないので一緒に書いておく。

ScriptableObject.Instantiate したインスタンスを ScriptableObject.Destroy で開放すると呼ばれます。
呼ばれる順番は OnDisable > OnDestroy

上記の関数を使わない限り、エディタ上では基本的に呼ばれないと思ったほうがいいかも?


参考
ScriptableObject - Unity スクリプトリファレンス


“Unity” and Unity logos are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere, and are used under license.


免責事項

当サイトの広告バナー、リンクによって提供される情報、サービス内容について、当サイトは一切の責任を負いません。

また、当サイトの情報を元にユーザ様が不利益を被った場合にも、当サイトは一切の責任を負いません。

すべて自己責任でお願いします。