ScriptableObjectの実行時変更が保存されてしまう問題と安全な対策方法
目次
1. 問題の概要
ScriptableObjectはUnityのアセットとして保存されるデータオブジェクトですが、
実行中にこのアセットを直接変更すると、変更内容がプロジェクトに永続化されてしまうことがあります。
これは、一時的なデバッグやテストのつもりで変更した値が、次回以降も保持されてしまうという不具合につながります。
2. 典型的な問題例
[SerializeField] private MyData configData;
void Start()
{
configData.hp = 9999; // ← アセット自体を書き換えてしまう危険なコード
}
このクラスは、例で使用した hp プロパティを持ち、Unityエディタからインスペクター上で編集できるシンプルな構成です。
MyData.cs
using UnityEngine;
[CreateAssetMenu(fileName = "NewMyData", menuName = "ScriptableObjects/MyData")]
public class MyData : ScriptableObject
{
[Header("基本ステータス")]
public int hp = 100;
public int attack = 10;
public int defense = 5;
}
作成手順(Unityエディタでの操作)
- 上記スクリプトを Assets/Scripts/ フォルダなどに保存する。
- Unityエディタの Projectビューで右クリック →Create > ScriptableObjects > MyData を選択。
- 任意の名前(例:PlayerData, EnemyData など)でアセットを作成。
- 作成したアセットをインスペクターで開き、hp, attack, defense を編集。
- 実行時には Instantiate() でこのアセットを複製して使用する。
メモ
- [CreateAssetMenu] 属性を使うことで、Unityエディタから簡単にインスタンスを作成できます。
- この MyData はプレイヤーや敵キャラ、スキル、アイテムなど幅広く応用可能です。
このようなコードでは、アセットに保存されている値 hp が、実行後も9999のまま残ってしまう場合があります。
3. 安全な対策:
Instantiate()によるクローンの作成
✅ 推奨される実装方法
[SerializeField] private MyData originalData;
private MyData runtimeData;
void Start()
{
// アセットの複製(実行時限定のクローン)
runtimeData = Instantiate(originalData);
// runtimeDataを操作しても、元のアセットには影響しない
runtimeData.hp = 9999;
}
✅ こうすることで:
- 元の originalData アセットは安全に保たれる
- runtimeData は実行中だけ使われ、変更は保存されない
- デバッグ時も安心して操作・変更ができる
4. まとめ
- ScriptableObjectを直接編集すると、変更がUnityエディタに保存される危険がある
- 実行時のデバッグには、必ず Instantiate() で複製して操作することが安全
- これにより、元のアセットを汚染せずに安心してテスト・変更が行える
補足:ScriptableObjectの用途
- ゲームの設定情報(例:敵キャラのステータス、ゲームバランス値など)
- スキルやアイテム定義など、共通データのテンプレートとして非常に有効
→ だからこそ、アセットを誤って汚すと全体に影響するため注意が必要です。
ディスカッション
コメント一覧
まだ、コメントがありません