Enum string 기반 -> AssetReference 기반으로 Scene 관리
This commit is contained in:
parent
4b24122c3d
commit
8ae8fc0242
@ -75,16 +75,16 @@ public static async Task<List<T>> LoadAssetsByLabel<T>(string label) where T : U
|
|||||||
Debug.LogError($"[AssetManager] Failed to load assets with label: {label}");
|
Debug.LogError($"[AssetManager] Failed to load assets with label: {label}");
|
||||||
return new List<T>();
|
return new List<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<SceneInstance> LoadScene(string key, LoadSceneMode mode = LoadSceneMode.Additive)
|
public static async Task<SceneInstance> LoadScene(AssetReference assetReference, LoadSceneMode mode = LoadSceneMode.Additive)
|
||||||
{
|
{
|
||||||
var handle = Addressables.LoadSceneAsync(key, mode);
|
var handle = Addressables.LoadSceneAsync(assetReference, mode);
|
||||||
await handle.Task;
|
await handle.Task;
|
||||||
|
|
||||||
if (handle.Status == AsyncOperationStatus.Succeeded)
|
if (handle.Status == AsyncOperationStatus.Succeeded)
|
||||||
return handle.Result;
|
return handle.Result;
|
||||||
|
|
||||||
Debug.LogError($"Scene load failed: {key}");
|
Debug.LogError($"Scene load failed: {assetReference}");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Sirenix.OdinInspector;
|
using Sirenix.OdinInspector;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.AddressableAssets;
|
||||||
|
|
||||||
namespace DDD
|
namespace DDD
|
||||||
{
|
{
|
||||||
@ -9,5 +10,6 @@ namespace DDD
|
|||||||
public class GameFlowSceneMappingSo : SerializedScriptableObject
|
public class GameFlowSceneMappingSo : SerializedScriptableObject
|
||||||
{
|
{
|
||||||
public Dictionary<GameFlowState, SceneType> FlowToSceneMapping = new();
|
public Dictionary<GameFlowState, SceneType> FlowToSceneMapping = new();
|
||||||
|
public Dictionary<SceneType, AssetReference> AssetMapping = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,54 +2,80 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
#endif
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
namespace DDD
|
namespace DDD
|
||||||
{
|
{
|
||||||
public enum SceneType
|
public enum SceneType
|
||||||
{
|
{
|
||||||
Entry = 0,
|
None = 0,
|
||||||
Restaurant = 1,
|
Entry = 1,
|
||||||
Voyage = 2
|
Restaurant = 2,
|
||||||
|
Voyage = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SceneData
|
||||||
|
{
|
||||||
|
public Scene Scene { get; }
|
||||||
|
public SceneInstance? SceneInstance { get; } // 처음에 실행되는 씬은 SceneInstance를 가질 수 없음 Unload용 데이터
|
||||||
|
|
||||||
|
public SceneData(Scene scene, SceneInstance? sceneInstance)
|
||||||
|
{
|
||||||
|
Scene = scene;
|
||||||
|
SceneInstance = sceneInstance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SceneManager : Singleton<SceneManager>, IManager
|
public class SceneManager : Singleton<SceneManager>, IManager
|
||||||
{
|
{
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private SceneTransitionHandlerSo _sceneTransitionHandlerSo;
|
private SceneTransitionHandlerSo _sceneTransitionHandlerSo;
|
||||||
|
|
||||||
private Dictionary<SceneType, SceneInstance> _loadedScenes;
|
|
||||||
|
|
||||||
private SceneInstance _currentSceneInstance;
|
|
||||||
public Action<SceneInstance> OnSceneChanged;
|
|
||||||
|
|
||||||
|
private Dictionary<SceneType, SceneData> _loadedSceneDatas;
|
||||||
|
private SceneType _currentSceneType = SceneType.None;
|
||||||
|
|
||||||
public void PreInit()
|
public void PreInit()
|
||||||
{
|
{
|
||||||
Array sceneTypeArray = Enum.GetValues(typeof(SceneType));
|
Array sceneTypeArray = Enum.GetValues(typeof(SceneType));
|
||||||
_loadedScenes = new Dictionary<SceneType, SceneInstance>(sceneTypeArray.Length);
|
_loadedSceneDatas = new Dictionary<SceneType, SceneData>(sceneTypeArray.Length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
try
|
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
||||||
|
var activeScenePath = activeScene.path;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
foreach (var kvp in GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping)
|
||||||
{
|
{
|
||||||
foreach (SceneType sceneType in Enum.GetValues(typeof(SceneType)))
|
var asset = kvp.Value.editorAsset;
|
||||||
|
if (asset == null) continue;
|
||||||
|
|
||||||
|
string assetPath = AssetDatabase.GetAssetPath(asset);
|
||||||
|
if (string.IsNullOrWhiteSpace(assetPath)) continue;
|
||||||
|
|
||||||
|
if (assetPath == activeScenePath)
|
||||||
{
|
{
|
||||||
if (sceneType == SceneType.Entry) continue;
|
_currentSceneType = kvp.Key;
|
||||||
var currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
_loadedSceneDatas.Add(_currentSceneType, new SceneData(activeScene, null));
|
||||||
if (sceneType.ToString() == currentScene.name)
|
break;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await PreloadSceneAsync(sceneType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
if (_currentSceneType == SceneType.None)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"Scene preload failed\n{e}");
|
Debug.LogWarning($"[SceneManager] 활성 씬이 AssetMapping에 존재하지 않습니다: {activeScenePath}");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
_currentSceneType = SceneType.Entry;
|
||||||
|
_loadedSceneDatas.Add(_currentSceneType, new SceneData(activeScene, null));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
await PreloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostInit()
|
public void PostInit()
|
||||||
@ -57,47 +83,70 @@ public void PostInit()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SceneInstance GetSceneInstance(SceneType sceneType) => _loadedScenes[sceneType];
|
public async Task PreloadSceneBySceneType(SceneType sceneType)
|
||||||
|
|
||||||
public async Task PreloadSceneAsync(SceneType sceneType)
|
|
||||||
{
|
{
|
||||||
if (_loadedScenes.ContainsKey(sceneType))
|
if (_loadedSceneDatas.ContainsKey(sceneType)) return;
|
||||||
return;
|
|
||||||
|
|
||||||
string key = sceneType.ToString();
|
var kvp = GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping.FirstOrDefault(kvp => kvp.Key == sceneType);
|
||||||
SceneInstance sceneInstance = await AssetManager.LoadScene(key);
|
var preloadedSceneInstance = await AssetManager.LoadScene(kvp.Value);
|
||||||
|
|
||||||
if (sceneInstance.Scene.IsValid())
|
if (preloadedSceneInstance.Scene.IsValid())
|
||||||
{
|
{
|
||||||
_loadedScenes[sceneType] = sceneInstance;
|
DeactivateScene(preloadedSceneInstance.Scene);
|
||||||
|
_loadedSceneDatas.Add(kvp.Key, new SceneData(preloadedSceneInstance.Scene, preloadedSceneInstance));
|
||||||
foreach (var root in sceneInstance.Scene.GetRootGameObjects())
|
|
||||||
{
|
|
||||||
root.SetActive(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError($"[SceneManager] Failed to preload scene: {sceneType}");
|
Debug.LogError($"[SceneManager] {sceneType}의 씬이 존재하지 않습니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PreloadAll()
|
||||||
|
{
|
||||||
|
var assetMapping = GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping;
|
||||||
|
foreach (var kvp in assetMapping)
|
||||||
|
{
|
||||||
|
if (_loadedSceneDatas.ContainsKey(kvp.Key)) continue;
|
||||||
|
|
||||||
|
var preloadedSceneInstance = await AssetManager.LoadScene(kvp.Value);
|
||||||
|
|
||||||
|
if (preloadedSceneInstance.Scene.IsValid())
|
||||||
|
{
|
||||||
|
DeactivateScene(preloadedSceneInstance.Scene);
|
||||||
|
_loadedSceneDatas.Add(kvp.Key, new SceneData(preloadedSceneInstance.Scene, preloadedSceneInstance));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"[SceneManager] {kvp.Key}의 씬이 존재하지 않습니다.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ActivateScene(SceneType sceneType)
|
public async Task ActivateScene(SceneType sceneType)
|
||||||
{
|
{
|
||||||
|
if (_currentSceneType == sceneType) return;
|
||||||
|
|
||||||
foreach (var handler in _sceneTransitionHandlerSo.Handlers.Where(handler => handler != null))
|
foreach (var handler in _sceneTransitionHandlerSo.Handlers.Where(handler => handler != null))
|
||||||
{
|
{
|
||||||
await handler.OnBeforeSceneActivate(sceneType);
|
await handler.OnBeforeSceneActivate(sceneType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_loadedScenes.TryGetValue(sceneType, out var sceneInstance))
|
if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData))
|
||||||
{
|
{
|
||||||
foreach (var root in sceneInstance.Scene.GetRootGameObjects())
|
foreach (var root in sceneData.Scene.GetRootGameObjects())
|
||||||
{
|
{
|
||||||
root.SetActive(true);
|
root.SetActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnityEngine.SceneManagement.SceneManager.SetActiveScene(sceneInstance.Scene);
|
if (sceneData.Scene.IsValid())
|
||||||
_currentSceneInstance = sceneInstance;
|
{
|
||||||
|
UnityEngine.SceneManagement.SceneManager.SetActiveScene(sceneData.Scene);
|
||||||
|
_currentSceneType = sceneType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"[SceneManager] {sceneType}의 Scene이 유효하지 않습니다.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -112,20 +161,33 @@ public async Task ActivateScene(SceneType sceneType)
|
|||||||
|
|
||||||
public void DeactivateScene(SceneType sceneType)
|
public void DeactivateScene(SceneType sceneType)
|
||||||
{
|
{
|
||||||
if (_loadedScenes.TryGetValue(sceneType, out var sceneInstance))
|
if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData))
|
||||||
{
|
{
|
||||||
foreach (var root in sceneInstance.Scene.GetRootGameObjects())
|
foreach (var root in sceneData.Scene.GetRootGameObjects())
|
||||||
{
|
{
|
||||||
root.SetActive(false);
|
root.SetActive(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UnloadSceneAsync(SceneType sceneType)
|
private void DeactivateScene(Scene scene)
|
||||||
{
|
{
|
||||||
if (_loadedScenes.TryGetValue(sceneType, out var sceneInstance))
|
foreach (var root in scene.GetRootGameObjects())
|
||||||
{
|
{
|
||||||
await AssetManager.UnloadScene(GetSceneInstance(sceneType));
|
root.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UnloadSceneBySceneType(SceneType sceneType)
|
||||||
|
{
|
||||||
|
if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData))
|
||||||
|
{
|
||||||
|
if (sceneData.SceneInstance == null) return;
|
||||||
|
|
||||||
|
if (GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping.ContainsKey(sceneType))
|
||||||
|
{
|
||||||
|
await AssetManager.UnloadScene((SceneInstance)sceneData.SceneInstance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user