本ページにはプロモーションが含まれます
Unity

【Unity】Scriptable Objectsの罠

この記事は約5分で読めます。

はじめに

罠でも何でもなく、私がScriptable Objectsの仕様を理解していない、使い方も間違えていました。
シーン間の一時的なデータのやりとりや、一時的なデータ保管庫としての利用が適切な使い方であって、セーブデータストアとして使うものではないようです。
エディタ上で保存できたので、データ入れればメモリ経由で永続保存する、超優れたデータストア!くらいな認識でした。readオンリーでマスタデータとして使うのが仕様なようです。わかりづらいんだよ。

https://docs.unity3d.com/ja/2023.2/Manual/class-ScriptableObject.html

 

対処方法

今制作しているゲームとは別の推理ゲームモック制作時に何となく気がついていたのですが、EditorUtility.SetDirtyとAssetDatabase.SaveAssets()で保存できて、
実機でも正常に動いていたので(エディター上での変更がプロジェクトに反映されてただけでした)、まぁ、これでよいかと放置していました。分からないものを分からないまま放置したあげく、遊んでくれる方のデータを簡単に失う可能性があるような状態にはしたくないですね。
read json->Scriptable Objects->write jsonで対応させようと思います。

ScriptableObjectは、Unityでのデータ管理や再利用性を高めるために設計された特殊なデータオブジェクトです。主にデータの保存や共有を簡単に行うために使われ、MonoBehaviourとは異なり、ゲームオブジェクトにアタッチされる必要はありません。これにより、プロジェクト内で再利用可能なデータを効率的に管理できるようになります。


ScriptableObjectの目的

  1. データの管理と分離
    • ScriptableObjectは、ゲームの設定データやアイテム、キャラクターのステータスなどのデータを格納するために使います。これにより、コードとデータが分離され、コードの保守性が向上します。
  2. 複数のオブジェクト間でのデータ共有
    • ScriptableObjectは複数のシーンやオブジェクト間で簡単に共有することができます。たとえば、ゲーム内の設定データや共有するスコアなどのデータを保持するのに適しています。
  3. メモリの効率化
    • ScriptableObjectはメモリの管理に優れ、同じデータを使い回す場合に特に便利です。インスタンスごとにデータを複製するのではなく、データ自体を参照するため、パフォーマンスが向上します。
  4. インスペクターで編集可能
    • Unityのインスペクターを通して、ScriptableObjectのデータを簡単に編集できます。デザイナーや他の開発者がスクリプトを触らずに、データのみを調整できるようになります。

ScriptableObjectの利点

  1. 再利用性が高い
    • 一度作成したScriptableObjectは複数のプレハブやシーン、スクリプトで簡単に再利用可能です。
  2. データの一元管理
    • ゲーム内のアイテムやキャラクターのデータなどを1つのScriptableObjectにまとめて管理でき、変更を加えた場合、すべての参照先に反映されます。
  3. 軽量なオブジェクト
    • ScriptableObjectは軽量で、ゲームオブジェクトやコンポーネントのように大量のオーバーヘッドが発生しません。これにより、パフォーマンスの向上が期待できます。
  4. 状態を持たないデータの管理に最適
    • ScriptableObjectはゲームプレイ中の一時的なデータではなく、データ自体の定義や共有に向いています。例えば、アイテムやステータス、設定などのデータを保存するのに最適です。

ScriptableObjectを使うべき場合

  • アイテムやスキル、キャラクターデータの管理
    • RPGやアクションゲームにおけるアイテムやスキルのステータスをScriptableObjectで管理することで、複数のオブジェクトで共有しやすくなります。
  • ゲーム設定の管理
    • ゲームの設定(音量、難易度、グラフィック設定など)をScriptableObjectで管理し、メインメニューやゲーム中で共有・参照できます。
  • 複数のオブジェクトでデータを共有する必要がある場合
    • 例えば、複数のエネミーが同じデータ(攻撃力や体力など)を参照する場合、ScriptableObjectを使ってこれらのデータを共有することで、メンテナンスが楽になります。

ScriptableObjectは、データを効率的に管理し、再利用可能にする強力なツールです。特に、ゲームオブジェクトにアタッチする必要のないデータや、複数のオブジェクトで共有するデータを管理する際に便利です。データの分離と管理を行いたい場合に活用することで、プロジェクトのスケーラビリティと保守性が大幅に向上します。

おわりに

Playmakerにも対応しているEasySaveアセットを所有しているので、最終的にそれを使えばデータのロード、セーブ問題は解決するのですが、作る過程で理解したいことも多かったので、今回結果Scriptable Objects特徴に少しだけ触れられてよかったです。

以下動画解説が分かりやすかったです。

https://youtu.be/5a-ztc5gcFw

 

直近で制作していて、だんだんと趣旨からずれてきたなと思います。なのでまず、既存アセットも多様して、さくっと作りたいものを形にしてから、手法を考えていきたいと思います。あまり考えて、凝っていくと、それに囚われて、作るモチベーションがどんどん落ちています。週末に仕事みたいなことはしたくないですね。

うまくScriptable Objectsの構造体をシリアライズ、デシリアライズして呼び出し、保存ができるようになりました。
最初MonoBehaviourで実装してオブジェクトに貼り付けてPlaymakerからCall Methodしたのですが、処理タイミングのせいかうまく動かなくなってしまい、EasySaveにしようかな…と思い始めて、その前にカスタムアクションに移動したらWindows,Android共に想定どおりに動くようになりました。

これでマスタデータはScriptable Object、シーン間やオブジェクト間FSMの動的データの参照はScriptable Objectから、動的データはjsonで保存できるようになりました。

Scriptable Object, yaml, csv, xml マスタデータ、設定値、ReadOnly
PlayerPrefab 現在のプレイヤーデータ R/W
Json  マスタデータ、プレイヤーデータ R/W セーブスロット、バックアップ、テンポラリ 、PlayerPrefabとJsonのデータでチェックサム比較チート対策とか。