Course contentsShow
← Unity Game Development
Lesson 452 of 8287. Advanced Game ArchitectureFree lesson

Implementing ScriptableObject-Based Global Managers

You will transition from MonoBehaviour singletons to ScriptableObject managers to persist data independently of the scene hierarchy and improve architectural modularity.

In this lesson, you will learn how to replace fragile MonoBehaviour singletons with ScriptableObject global managers to create persistent, scene-independent data and logic containers.

Moving Beyond the Singleton

In your previous work with singletons, you likely encountered the "Don't Destroy On Load" dance—manually managing scene transitions, dealing with initialization order, and fighting the DontDestroyOnLoad hierarchy clutter. By shifting your global managers to ScriptableObject, you decouple your architectural logic from the active scene's lifecycle.

A ScriptableObject exists in your project’s memory independently of any specific scene. When you reference it in a component, you are pointing to a shared data asset rather than a scene-bound object.

Implementing the Global Manager

To create a global manager, define it as a ScriptableObject instead of a MonoBehaviour. Consider a GameSettingsManager:

[CreateAssetMenu(menuName = "Managers/GameSettings")]
public class GameSettingsManager : ScriptableObject
{
    public float masterVolume = 1.0f;
    public bool isMusicEnabled = true;

    public void ToggleMusic() => isMusicEnabled = !isMusicEnabled;
}

Because this is a ScriptableObject, you don't need a "Manager GameObject" in your scene. Instead, you create an instance of this asset in your Project folder. Any MonoBehaviour—whether it’s a UI slider or an Audio Player—can hold a reference to this specific asset:

public class MusicController : MonoBehaviour
{
    public GameSettingsManager settings; // Drag the asset here in Inspector

    void Start()
    {
        if (settings.isMusicEnabled) PlayMusic();
    }
}

Architectural Benefits

This approach provides three distinct advantages:

  1. Persistence: The state of your ScriptableObject persists across scene loads, making it an ideal place for cross-scene data storage.
  2. Editor Debugging: You can inspect the ScriptableObject asset in the Project window while the game is running to see your global state change in real-time.
  3. Reduced Boilerplate: You eliminate the need for Instance checks, Awake initialization, and potential race conditions caused by DontDestroyOnLoad objects attempting to find each other.

Key Takeaway: Moving your global logic to ScriptableObjects decouples your system state from the scene hierarchy, allowing for a cleaner, more modular architecture that survives scene transitions naturally.