シーン間のデータ受け渡し

2022年2月7日

Unityでは、シーンをLoadSceneで切り替えるとデータが破棄され引き継げません
引き継ぐ方法は様々ありますが、Unityでの推奨をご紹介したいと思います

スクリプタブルオブジェクトを使ったデータの受け渡し

スクリタプルオブジェクトは、シーン間のデータの受け渡しのみならず、パラメータの保存等に活用することができます

データの保存が目的の場合・・・

ハイスコアなど、結果シーンでもデータを利用したい場合、スクリプタブルオブジェクトを検討してみましょう

準備

スクリプタブルオブジェクト作成用のコード

このコードを作成後、下のスクリプタブルオブジェクトを作成を実行します

このコードでは、保存したいデータの他にCreateメニューにスクリプタブルオブジェクトの作成も行うコードが属性として追加されています

using UnityEngine;

[CreateAssetMenu(menuName = "Data")]
public class DataKeep : ScriptableObject
{
    public int score;
}

スクリプタブルオブジェクトを作成

プロジェクトウィンドウで、右クリック → Create → Dataを選択
ファイル名入力になりますので、Dataとします

作成されたファイルをクリックすると、インスペクタに情報が表示されます

シーン構成

シーン切り替え時にデータがうまく渡せたか確認するため、2つのシーンを作成します

シーン1

最初のシーンです。
スペースキーを押すと、scoreに100を代入後、シーンを2に切り替えるスクリプトがアタッチされています

インスペクターのDataには、プロジェクトウィンドウからDataファイルをアウトレット接続します

using UnityEngine;
using UnityEngine.SceneManagement;

public class DataWrite : MonoBehaviour
{
    [SerializeField]
    DataKeep data;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            data.score = 100;

            SceneManager.LoadScene("Scene2");
        }
    }
}

シーン2

シーンが切り替わり、Startメソッドが呼び出させるとコンソールにscoreの値が表示されます

インスペクターのDataには、プロジェクトウィンドウからDataファイルをアウトレット接続します

using UnityEngine;

public class DataRead : MonoBehaviour
{
    [SerializeField]
    DataKeep data;

    void Start()
    {
        Debug.Log(data.score);
    }
}

実行結果

コードで変更(コードで代入)しても保存されません(一見保存されているように見えても再起動で戻っています)

コードで変更しても保存したい場合

この方法は、Unityエディター限定です。PCやスマホでビルドして機能させることはできません
ビルドした時は、最後に書き出したデータが使われます

ハイスコアなどのデータ保持の場合はこれを使いましょう

ただしインスペクターで値を変更する場合は、すぐ保存されます

次のコードを追加します

EditorUtility.SetDirty(data);
AssetDatabase.SaveAssets();

今回のサンプルでは次のようになります

using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;

public class DataWrite : MonoBehaviour
{
    [SerializeField]
    DataKeep data;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            data.score = 100;

            EditorUtility.SetDirty(data);
            AssetDatabase.SaveAssets();

            SceneManager.LoadScene("Scene2");
        }
    }
}

スクリプタブルオブジェクトは、最後に更新された値がエディター上では残っています。呼び出し元のコードで初期化してもいいですが、スクリプタブルオブジェクト自身で初期化してほしい場合、次のようにすれば可能です

スクリプタブルオブジェクトを起動都度初期化

今回のサンプルでは次のようになります

using UnityEngine;

[CreateAssetMenu(menuName = "Data")]
public class DataKeep : ScriptableObject
{
    [SerializeField]
    int initScore;

    public int Score;

    // インスペクターに表示したくなければ・・・こちら
    //public int Score { get; set; }

    private void OnEnable()
    {
        Score = initScore;
    }
}

参考

スクリプタブルオブジェクトの内容

テキストファイルになっています。最終行がscoreになってますね

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 0}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 88881a02bc6a14eb08bbc76d3d3ae587, type: 3}
  m_Name: Data
  m_EditorClassIdentifier: 
  score: 100

Unity

Posted by hidepon