1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MySceneControllerを作ってみた(自分用データの受け渡し方法まとめ)

Last updated at Posted at 2024-02-24

前提

シーン遷移をするとデータが失われてしまう問題がある
データの受け渡し方法
シーン遷移をせずに1シーンで演出ができないか考えました

・static変数
C#

using UnityEngine;

public class Sample1 : MonoBehaviour
{
    public static int sharedData;
}

問題点
Sample1.cs - Staticな変数に保持しておく
依存関係の隠蔽が難しい: 静的な変数を利用すると、クラス間の依存関係が隠蔽されず、コードが複雑になりやすい。

・シングルトン
C#

using UnityEngine;

public class Sample2 : MonoBehaviour
{
    public static Sample2 Instance;

    public int sharedData;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

問題点
Sample2.cs - シングルトンを利用
グローバル状態への依存: シングルトンパターンはグローバルな状態を導入しやすく、コードの理解とテストが難しくなる可能性がある。
ライフサイクル管理の複雑さ: シングルトンはライフサイクルの管理が複雑になりがちで、適切な初期化や破棄が保証されない場合がある。

・(非推奨)DontDestroyOnLoad
C#

using UnityEngine;

public class Sample3 : MonoBehaviour
{
    public int sharedData;

    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}

問題点
Sample3.cs - (非推奨) DontDestroyOnLoadを利用
メモリリークの可能性: DontDestroyOnLoad を使用すると、不要なオブジェクトがメモリ内に残りやすくなり、メモリリークの原因となる可能性がある。
オブジェクトの管理が困難: DontDestroyOnLoad を使用すると、オブジェクトの管理が難しくなり、意図しない挙動が生じる可能性がある。

・マルチシーン
C#

using UnityEngine;

public class Sample4 : MonoBehaviour
{
    public static int sharedData;
}

問題点
Sample4.cs - マルチシーンを利用
複雑なデータ共有: マルチシーンを利用する場合、データの共有と同期が複雑になりがちで、コードの複雑性が増す可能性がある。

・ScriptableObject
C#

using UnityEngine;

[CreateAssetMenu(fileName = "NewData", menuName = "Data")]
public class Sample5 : ScriptableObject
{
    public int sharedData;
}

問題点
Sample5.cs - ScriptableObjectを利用
外部アセットへの依存: ScriptableObjectを使う場合、外部アセットに依存するため、プロジェクト内でコードと設定が分散しやすくなる。

・ストレージに値を保存
C#

using UnityEngine;

public class Sample6 : MonoBehaviour
{
    private const string Key = "SharedData";

    public void SaveData(int data)
    {
        PlayerPrefs.SetInt(Key, data);
        PlayerPrefs.Save();
    }

    public int LoadData()
    {
        return PlayerPrefs.GetInt(Key);
    }
}

問題点
Sample6.cs - ストレージに値を保存
データの永続化とセキュリティ: ストレージにデータを保存する場合、データの永続化とセキュリティ上の懸念があり、機密性の高いデータの場合は注意が必要です。また、プラットフォームによっては保存できる容量に制限があります。

最後に自分の解決方法?.(演出までは未完成)を載せておきます。
まず各シーンの分けて作ってある機能があることが前提です
次にCreateEmptyで空のGameObjectを各シーンに作ります
次に空のGameObjectの配下にシーン内のオブジェクトをすべて移動します
次にマルチシーンを利用して全てのシーンの管理シーンのヒエラルキーに全てのGameObjectを
Drag&Dropします
次にヒエラルキーの各シーンを右クリック>UnloadSceneを選択します(間違ってシーンを消さないように)
次に管理シーンに空のGameObjectを作成し以下のスクリプトをアタッチします
インスペクターでシーンの数に応じて配列を増やし、enumの値をDropDownから選びます
最後にSetActive(true);したいシーン部品オブジェクトをセットすれば完成です

サンプルではSpaceキーを押すとGameObjectが連番でSetActiveされていきます
実質シーン遷移が実装できました
最終的にはおしゃれなフェードを1シーンで実現したいのでまた更新します

C#

using UnityEngine;

public class SceneController : MonoBehaviour
{
    [System.Serializable]
    public class SceneCtrl
    {
        public enum SCENETYPE
        {
            TITLE,
            PROLOG,
            GAME,
            END_1,
            END_2,
            SAVE,
            SETTING,
        }

        public SCENETYPE sceneType = SCENETYPE.TITLE;
    }

    [SerializeField] SceneCtrl[] scenes;

    void Start()
    {
        // 初期のシーンを設定
        SwitchScene(SceneCtrl.SCENETYPE.TITLE);
    }

    void Update()
    {
        // シーンの切り替えなど、必要な処理をUpdate内に記述
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 例えばスペースキーを押したら次のシーンに切り替える
            SwitchToNextScene();
        }
    }

    void SwitchToNextScene()
    {
        // 現在のシーンを取得
        SceneCtrl currentScene = GetCurrentScene();

        // 現在のシーンの次のシーンを取得
        int currentIndex = System.Array.IndexOf(scenes, currentScene);
        int nextIndex = (currentIndex + 1) % scenes.Length;
        SceneCtrl nextScene = scenes[nextIndex];

        // 次のシーンに切り替え
        SwitchScene(nextScene.sceneType);
    }

    void SwitchScene(SceneCtrl.SCENETYPE sceneType)
    {
        // すべてのシーンを非アクティブにする
        foreach (SceneCtrl scene in scenes)
        {
            SetSceneActive(scene.sceneType, false);
        }

        // 指定されたシーンをアクティブにする
        SetSceneActive(sceneType, true);
    }

    void SetSceneActive(SceneCtrl.SCENETYPE sceneType, bool isActive)
    {
        switch (sceneType)
        {
            case SceneCtrl.SCENETYPE.TITLE:
                title_Object.SetActive(isActive);
                break;
            case SceneCtrl.SCENETYPE.PROLOG:
                prolog_Object.SetActive(isActive);
                break;
            case SceneCtrl.SCENETYPE.GAME:
                game_Object.SetActive(isActive);
                break;
            case SceneCtrl.SCENETYPE.END_1:
                end_1_Object.SetActive(isActive);
                break;
            case SceneCtrl.SCENETYPE.END_2:
                end_2_Object.SetActive(isActive);
                break;
            case SceneCtrl.SCENETYPE.SAVE:
                save_Object.SetActive(isActive);
                break;
            case SceneCtrl.SCENETYPE.SETTING:
                settingObject.SetActive(isActive);
                break;
        }
    }

    SceneCtrl GetCurrentScene()
    {
        // アクティブなシーンを検索して返す
        foreach (SceneCtrl scene in scenes)
        {
            GameObject sceneObject = GetSceneObject(scene.sceneType);
            if (sceneObject.activeSelf)
            {
                return scene;
            }
        }
        return null;
    }

    GameObject GetSceneObject(SceneCtrl.SCENETYPE sceneType)
    {
        switch (sceneType)
        {
            case SceneCtrl.SCENETYPE.TITLE:
                return title_Object;
            case SceneCtrl.SCENETYPE.PROLOG:
                return prolog_Object;
            case SceneCtrl.SCENETYPE.GAME:
                return game_Object;
            case SceneCtrl.SCENETYPE.END_1:
                return end_1_Object;
            case SceneCtrl.SCENETYPE.END_2:
                return end_2_Object;
            case SceneCtrl.SCENETYPE.SAVE:
                return save_Object;
            case SceneCtrl.SCENETYPE.SETTING:
                return settingObject;
            default:
                return null;
        }
    }
}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?