Skip to content

Commit 95a9f52

Browse files
committed
Added a new additive scene manager to manage additive scenes. Yet to be tested in real application, but conceptually should work
1 parent ed768e9 commit 95a9f52

File tree

3 files changed

+130
-14
lines changed

3 files changed

+130
-14
lines changed

AdditiveSceneManager/AdditiveSceneManager.cs

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,93 @@
22
using System.Collections.Generic;
33
using UnityEngine;
44
using UnityEngine.SceneManagement;
5-
6-
[System.Serializable]
7-
public class AdditiveSceneRef {
8-
public string scene_name;
9-
public Object scene_ref;
10-
}
5+
using UnityEngine.Events;
116

127
public class AdditiveSceneManager : MonoBehaviour
138
{
149

1510
// Global instance
1611
public static AdditiveSceneManager Instance;
12+
13+
[Header("=== Scene Lists ===")]
14+
[Tooltip("List of additive scenes. These scenes must be added to \"Build Settings\" too.")]
15+
public Object[] scenes;
16+
public Dictionary<string, Object> sceneDict;
17+
private List<string> activeScenes = new List<string>();
1718

18-
// List of scenes
19-
public AdditiveSceneRef[] scenes;
20-
21-
// Adictionary of scenes based on `scenes`; generated
22-
19+
[Header("=== Callbacks ===")]
20+
public UnityEvent onSceneLoadedCallback;
21+
public UnityEvent onSceneUnloadedCallback;
2322

2423
// Awake
2524
private void Awake() {
2625
Instance = this;
26+
InitializeScenes();
27+
}
28+
29+
private void InitializeScenes() {
30+
// Load listeners
31+
SceneManager.sceneLoaded += OnSceneLoaded;
32+
SceneManager.sceneUnloaded += OnSceneUnloaded;
33+
34+
// Initialize arrays and dictionary
35+
activeScenes = new List<string>();
36+
sceneDict = new Dictionary<string, Object>();
37+
foreach(Object s in scenes) {
38+
sceneDict.Add(s.name, s);
39+
}
2740
}
2841

2942
// Add Scene from `scenes` to scene
30-
public void AddScene(string quuery) {
43+
public void LoadScene(string query, LoadSceneMode mode = LoadSceneMode.Additive) {
44+
if(!sceneDict.ContainsKey(query)) {
45+
Debug.LogError($"Query scene \"{query}\" doesn't exist in this scene manager!");
46+
return;
47+
}
48+
if (activeScenes.Contains(query)) {
49+
Debug.LogError($"Query scene \"{query}\" is already loaded additively. Will not add scene again.");
50+
return;
51+
}
52+
SceneManager.LoadScene(sceneDict[query].name, mode);
53+
}
54+
55+
public void UnloadScene(string query) {
56+
if (!sceneDict.ContainsKey(query)) {
57+
Debug.LogError($"Query scene \"{query}\" doesn't exist in this scene manager!");
58+
return;
59+
}
60+
if (!activeScenes.Contains(query)) {
61+
Debug.LogError($"Query scene \"{query}\" is not loaded.");
62+
return;
63+
}
64+
SceneManager.UnloadSceneAsync(sceneDict[query].name);
65+
}
66+
67+
public void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
68+
SceneManager.SetActiveScene(scene);
69+
if (!activeScenes.Contains(scene.name)) activeScenes.Add(scene.name);
70+
Debug.Log($"Scene \"{scene.name}\" loaded!");
71+
onSceneLoadedCallback?.Invoke();
72+
}
73+
74+
public void OnSceneUnloaded(Scene scene) {
75+
if (activeScenes.Contains(scene.name)) activeScenes.Remove(scene.name);
76+
Debug.Log($"Scene \"scene.name\" unloaded!");
77+
onSceneUnloadedCallback?.Invoke();
78+
}
79+
80+
public bool QuerySceneLoaded(string query) {
81+
return activeScenes.Contains(query);
82+
}
83+
84+
void OnDestroy() {
85+
SceneManager.sceneLoaded -= OnSceneLoaded;
86+
SceneManager.sceneUnloaded -= OnSceneUnloaded;
87+
}
88+
89+
90+
3191

32-
}
3392

3493

3594
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using UnityEngine;
2+
using UnityEditor;
3+
4+
[CustomEditor(typeof(AdditiveSceneManager))]
5+
public class AdditiveSceneManagerEditor : Editor
6+
{
7+
AdditiveSceneManager manager;
8+
9+
public void OnEnable() {
10+
manager = (AdditiveSceneManager)target;
11+
}
12+
13+
public override void OnInspectorGUI() {
14+
DrawDefaultInspector();
15+
16+
// Don't do anything if not playing
17+
if (!Application.isPlaying) return;
18+
19+
// Render controls for each scene
20+
EditorGUILayout.LabelField("=== Scene Controls ===", EditorStyles.boldLabel);
21+
foreach(Object s in manager.scenes) SceneButtons(s);
22+
}
23+
24+
public void SceneButtons(Object s) {
25+
26+
// Query if scene is active
27+
bool sceneActive = manager.QuerySceneLoaded(s.name);
28+
29+
// Start a horizontal group for the buttons
30+
GUILayout.BeginHorizontal();
31+
32+
GUI.enabled = !sceneActive;
33+
if (GUILayout.Button($"Load \"{s.name}\"")) manager.LoadScene(s.name);
34+
GUI.enabled = sceneActive;
35+
GUILayout.Space(5);
36+
if (GUILayout.Button($"Unload \"{s.name}\"")) manager.UnloadScene(s.name);
37+
GUI.enabled = true;
38+
39+
// End the horizontal group
40+
GUILayout.EndHorizontal();
41+
}
42+
43+
}

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,18 @@ The existing list of serialized equivalents of primitive Unity classes are:
5454
* `Color32` => `SColor32`
5555
* `RaycastHit` => `SRaycastHit`
5656

57-
To use these serialized equivalents, you must import the namespace `using SerializableTypes`.
57+
To use these serialized equivalents, you must import the namespace `using SerializableTypes`.
58+
59+
## Additive Scene Manager
60+
61+
Included in this package is an `AdditiveSceneManager.cs` component. This component is a special helper to enable ADDITIVE scene management. I.E. allows you to load and unload scenes on top of another existing, single scene. Helpful for situations where you may want singleton logic at a scene level, by containing major components in the base scene and only switching out certain content dynamically.
62+
63+
### Usage
64+
65+
Installation is really simple: just add `AdditiveSceneManager.cs` to any GameObject in your base scene, and populate the `Scenes` list with all the additive scenes.
66+
67+
During runtime, if you are in the editor, you can debug how additive scenes load in via the Inspector; you can load and unload your additive scenes via some UI buttons we've added. You can also call the following functions to control loading and unloading:
68+
69+
- `LoadScene(string scene_name, LoadSceneMode mode = LoadSceneMode.Additive)`: Loads a scene based on a string query. You CAN technically use this to load single scenes via the 2nd parameter, but this is not the intended function of this manager. **Only loads in scenes added to its `Scenes` list; doesn't control any scenes NOT added to that list.
70+
- `UnloadScene(string scene_name)`: Unloads a scene based on a string query. Only unloads a scene if 1) it's been added to the `Scenes` list of this manager, and 2) if it's loaded already. Doesn't do anything if the queried scene is unloaded already.
71+
- `QuerySceneLoaded(string scene_name)`: You can check if a scene has been additively loaded from this manager using this function. Returns a boolean indicating so.

0 commit comments

Comments
 (0)