前提
シーン遷移をするとデータが失われてしまう問題がある
データの受け渡し方法
シーン遷移をせずに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;
}
}
}