【Unity】Scriptable Objectで変更した値が参照先で変わらない問題の解決法
はじめに
お疲れ様です。柊 弥生です。
ゲーム制作をしていてScriptble Objectを使用する機会が多いのですが、動的に値を変更するときに使用した際、初期値からScriptable Objectの値を変更した後に値を適切に読み取ってくれないという問題があったので解決法をまとめます。
初歩的な話かもしれませんが、数時間悩んでしまったので戒めのつもりで記事にします。
Scriptable Objectの仕様については、公式のリファレンスや他の解説記事を見て下さい。
結論
結果から言うと使い方が違いました。参照先のスクリプトでは、何かしらの変数に置き換えてから使えということです。
だめな例
Scriptable Objectの例
public class TestScriptableObject : ScriptableObject
{
public int num;
}
参照先のオブジェクト
public class TestMonoBehaviour : MonoBehaviour
{
public TestScriptableObject _TestScriptableObject;
private void Update()
{
Debug.Log(_TestScriptableObject.num);
}
}
この方法では、参照先のオブジェクトでScriptable Objectのint型の値をインスタンス化せずにそのまま使用しています。この方法では、外部から値を変更しても変更後の値を読み取りません。
正しい例
public class TestMonoBehaviour : MonoBehaviour
{
public TestScriptableObject _TestScriptableObject;
private int num;
private void Update()
{
num = _TestScriptableObject.num;
Debug.Log(num);
}
}
この方法では、実行途中でScriptable Objectの値が変更しても読み取ってくれます。
インスタンス化必須ですねw
実際の使用箇所
このScriptable Objectはコントローラーからの入力(InputSystem)を各スクリプトに中継するために使用しています。
1.従来の方法
1の方法では、コントローラーからの入力をInputSystemの関数をまとめたScriptを経由して送信していました。このときコントローラー入力の値を使用する箇所を決めておき、InputSystemの関数をまとめたScript(以降は、IS Scriptとする)内で値を受け渡していました。IS Scirptは、コンポーネントとして配置することから、呼び出しタイミングの異なるコンポーネント間では、値の受け渡しができませんでした。
2.Scriptable Object使用後
2の方法にしたことにより事前にコントローラー入力の使用箇所を定めずに適宜Scriptable Objectを参照することでコントローラーの入力を受け取れるようにしました。Scriptable Objectは実行タイミングに依存せずに任意のタイミングで参照できるため、使用箇所を気にすることはありません。
注意事項
Scriptable Objectの仕様として、ビルド後は動的に値の変更をしたとしても途中で保存することはできません。したがって、コントローラーの入力結果を保存する場合には、Jsonなど任意のファイルに書き出すか、メモリ上に別途書き出す必要があります。
また、Scriptable Objectを経由してコントローラーの入力を受け取ることから、入力遅延が発生する可能性があります。私の環境では影響ありませんが、シュミュレーションゲームを作成される方でシビアな入力を必要とする場合には、注意して下さい。また、Scriptable ObjectのInspector上で入力結果を確認できるようにしていますが、実際に値が変化してから表示結果が変わるまで遅延します。(Inspectorの表示結果のすべては必ず遅延します)