⛳
【Unity】ScriptableObjectの使い方と落とし穴【コピペ可】
使い方と落とし穴シリーズ一覧
さっさと試したい人向け コピペ可コード
PlayerStatus.cs
(ScriptableObject
側 エディタ上で生成する側)
using UnityEngine;
[CreateAssetMenu(menuName = "Status/PlayerStatus")]
public class PlayerStatus : ScriptableObject
{
[SerializeField] private float hp = 100f;
public float HP => hp;
}
Player.cs
(ScriptableObject
を利用する側)
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField] private PlayerStatus status;
private void Start()
{
Debug.Log($"初期HP: {status.HP}");
}
}
使い方
1:Assetsフォルダ内で PlayerStatus.cs
を作成
2:Player.cs
をシーン上のオブジェクトにアタッチ
3:プロジェクトビュー → Create → Status → PlayerStatus でアセット作成
4:作成アセットを Player
の status
にドラッグ
一言
-
ScriptableObject
の習得で Unity への抵抗感がグッとなくなる (経験談) - 開発に必須…ではないが、Unity のディープな機能を色々扱っていく上で
最初の良いステップと考えています
ScriptableObject
を使用するケース
- 定数の管理
- キャラクタークラスごとの初期ステータス
- シーン間で共通する設定情報
ScriptableObject
の使い方
全体の流れ
ScriptableObject
継承
[CreateAssetMenu(menuName = "Status/PlayerStatus")]
public class PlayerStatus : ScriptableObject
{
[SerializeField] private float hp;
public float HP => hp;
//他なんかデータ色々
}
-
[CreateAssetMenu(menuName = "任意の名前")]
を追加 -
MonoBehaviour
をScriptableObject
に変更 - クラス内には後々エディタ上で操作したいデータを記述(例:
hp
)
エディタ上で生成
- エディタ上で右クリック → Create → Status → PlayerStatus を選択するとプロジェクトビューに
PlayerStatus
ファイルが作成される -
[SerializeField]
,public
な変数はインスペクターから操作できる
他スクリプトで使用
public class Player : MonoBehaviour
{
[SerializeField] private PlayerStatus status;
private void Start()
{
Debug.Log($"初期HP:{status.HP}");
}
}
-
ScriptableObject(PlayerStatus)
を参照して使うことができる
ScriptableObject
のメリット
- エディタ上で操作できるデータ群を作りやすい
- 複数シーンやゲーム全体にまたがったデータ群を作りやすい
-
静的で共用のデータに向いている(例:敵のHPや移動速度等の固定パラメータ)
- 全インスタンスが値を持つより、
ScriptableObject
参照の方がメモリ使用量が抑えられる - Flyweightパターン実装に活用することもできる
- 全インスタンスが値を持つより、
オイラはこんな落とし穴に出会った
データ書き換えで想定外のやつも変わる
- 複数スクリプトで使用する場合に注意(そう珍しくない状況)
- スクリプトは
ScriptableObject
を参照する - そのため、「スクリプトA調整するか…」とうっかり参照元を変え、他にも影響が出てしまうケースがある
new()
で生成
-
ScriptableObject
継承クラスをnew()
すると警告がでる(UNT0011) - この場合 Unity message methods(
OnEnable()
とか)が正しく動作しない可能性がある - そのため、
CreateInstance()
を代わりに用いる
var status = new PlayerStatus(); //UNT0011
var status = ScriptableObject.CreateInstance<PlayerStatus>(); //OK
- なお、これで作成した
ScriptableObject
はメモリ上にのみ存在するため、アセットとして保存したい場合は別途AssetDatabase.CreateAsset()
が必要
実行中に書き換え → そのまま
- エディタで実行中、
ScriptableObject
のデータを書き換えても終了後そのまま - これはむしろ便利だが、
Monobehaviour
との挙動とは異なるので注意(終了後、元に戻る) - 筆者はその辺を勘違いしてパラメータで遊んでたら盛大にバグった経験アリ(99%筆者が悪い)
Discussion