프로젝트를 하다보면 하나의 Scene에 모든것을 관리하려니 리소스 관리가 힘들어지는 경우가 종종 생깁니다.
이럴 때 하나의 Scene을 여러개의 Scene으로 나누어서 관리한다면 좀 더 관리하기가 수월해집니다.
예를 들어, 하나의 Scene에서는 핵심 Core System만 다루고, 다른 Scene에서는 비쥬얼을 담당하는 Design System만 다룬다면 개발자와 디자이너가 작업하기에도 편하고, 협업 과정에서 충돌가능성이 적어질 수 있습니다.
저는 com.unity.multiplayer.samples.coop의 Boss Room에 있는 코드를 가져와서 사용하고 있으며, 코드를 공유드리고자 합니다.
GitHub - Unity-Technologies/com.unity.multiplayer.samples.coop: A small-scale cooperative game sample built on the new, Unity ne
A small-scale cooperative game sample built on the new, Unity networking framework to teach developers about creating a similar multiplayer game. - GitHub - Unity-Technologies/com.unity.multiplayer...
github.com
예시
왼쪽 사진처럼 현재 사용하고자 하는 Scene들을 배치해둔 다음 Save Scene Setup to Config버튼을 누르면 자동으로 Child Scene에 등록이 됩니다.
반대로 Reset 버튼을 누르면 저장되지 않은 추가 된 Scene들이 사라지게 됩니다.
코드
using System;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// Allows setting a scene as a root scene and setting its child scenes. To use this, drag this component on any object in a scene to make that scene a root scene. In the background, ChildSceneLoader will automatically manage this.
/// </summary>
public class EditorChildSceneLoader : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField]
public List<SceneAsset> ChildScenesToLoadConfig;
void Update()
{
// DO NOT DELETE keep this so we can enable/disable this script... (used in ChildSceneLoader)
}
public void SaveSceneSetup()
{
if (ChildScenesToLoadConfig == null)
{
ChildScenesToLoadConfig = new List<SceneAsset>();
}
else
{
ChildScenesToLoadConfig.Clear();
}
foreach (var sceneSetup in EditorSceneManager.GetSceneManagerSetup())
{
ChildScenesToLoadConfig.Add(AssetDatabase.LoadAssetAtPath<SceneAsset>(sceneSetup.path));
}
}
public void ResetSceneSetupToConfig()
{
var sceneAssetsToLoad = ChildScenesToLoadConfig;
List<SceneSetup> sceneSetupToLoad = new List<SceneSetup>();
foreach (var sceneAsset in sceneAssetsToLoad)
{
sceneSetupToLoad.Add(new SceneSetup() { path = AssetDatabase.GetAssetPath(sceneAsset), isActive = false, isLoaded = true });
}
sceneSetupToLoad[0].isActive = true;
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
EditorSceneManager.RestoreSceneManagerSetup(sceneSetupToLoad.ToArray());
}
#endif
}
#if UNITY_EDITOR
[InitializeOnLoad]
public class ChildSceneLoader
{
static ChildSceneLoader()
{
EditorSceneManager.sceneOpened += OnSceneLoaded;
}
static void OnSceneLoaded(Scene _, OpenSceneMode mode)
{
if (mode != OpenSceneMode.Single || BuildPipeline.isBuildingPlayer) return; // try to load child scenes only for root scenes or if not building
var scenesToLoadObjects = GameObject.FindObjectsOfType<EditorChildSceneLoader>();
if (scenesToLoadObjects.Length > 1)
{
throw new Exception("Should only have one root scene at once loaded");
}
if (scenesToLoadObjects.Length == 0 || !scenesToLoadObjects[0].enabled) // only when we have a config and when that config is enabled
{
return;
}
scenesToLoadObjects[0].ResetSceneSetupToConfig();
Debug.Log("Setup done for root scene and child scenes");
}
}
#endif
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(EditorChildSceneLoader))]
public class ChildSceneLoaderInspectorGUI : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var currentInspectorObject = (EditorChildSceneLoader)target;
if (GUILayout.Button("Save scene setup to config"))
{
currentInspectorObject.SaveSceneSetup();
}
if (GUILayout.Button("Reset scene setup from config..."))
{
currentInspectorObject.ResetSceneSetupToConfig();
}
}
}
#endif
Editor 스크립트는 Editor 폴더에 생성하셔야 합니다!