Tired of writing singletons? Hate having 30 managers cluttering every scene?
Manager<T> is a tiny Unity framework for persistent, scene-aware manager singletons.
Write your manager once, drop it on a prefab, add it to one list — and it spawns itself,
survives every scene load, and gives you a clean Instance accessor. No boilerplate,
no DontDestroyOnLoad copy-paste, no manager objects sitting in your scenes.
public class AudioManager : Manager<AudioManager>
{
protected override void Init() { /* one-time setup */ }
protected override void ReInit(string fromScene, Scene toScene) { /* per scene change */ }
protected override void Delete() { /* teardown */ }
}
// anywhere in your game:
AudioManager.Instance.PlaySfx(clip);That's the whole thing. No singleton plumbing to write, ever again.
The usual Unity manager looks like this, copy-pasted into every manager you own:
public static FooManager Instance;
void Awake()
{
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject);
}Then you drag a FooManager object into every scene, hope you didn't forget one,
and end up with a bootstrap scene full of thirty manager GameObjects. Manager<T>
replaces all of that:
- The singleton is written once, in the base class, using the CRTP pattern
(
class FooManager : Manager<FooManager>). You never writeAwake,Instance, orDontDestroyOnLoadagain. - Managers live on prefabs, not in scenes. They're listed in a single ScriptableObject and spawned automatically before the first scene loads.
- A scene-change lifecycle is built in. Override
ReInitand your manager reacts to every scene load — swap music, reset state, refetch references — without wiring up scene events yourself.
Coming from Godot? This mirrors Godot's AutoLoad (singleton) workflow: you register a node once in a central list, the engine spawns it automatically at startup, it persists across scene changes, and you reach it by name from anywhere. Here the "AutoLoad list" is the
ManagerListScriptableObject and the global handle isYourManager.Instance. If you've built autoloads in Godot, this flow will feel immediately familiar.
Install via Unity Package Manager (Window → Package Manager → + → Add package from git URL),
or add it to your manifest.json:
"com.playermadegames.managerst": "https://github.com/16Byte/ManagersT.git#v1.0.0"Dependency: ManagersT requires com.pmg.utilities (it uses SceneEvents for the
scene-change hook). Make sure that package is installed too.
Requires Unity 6000.0 or newer. Recommended Unity 6000.3 LTS
Derive from Manager<T> using your own type as T (this is the CRTP trick that gives
you a strongly-typed Instance for free):
using PMG.ManagersT;
public class GameManager : Manager<GameManager>
{
public int Score { get; private set; }
protected override void Init() => Score = 0; // runs once, at Start
protected override void Delete() { } // runs on teardown
public void AddPoint() => Score++;
}You override three hooks instead of Unity messages:
| Hook | When it runs | Notes |
|---|---|---|
Init() |
Once, on Start() after the singleton is claimed |
Your one-time setup. Required override. |
ReInit(fromScene, toScene) |
On every scene change | Optional. Scene-aware reset logic. |
Delete() |
On destroy, for the live instance only | Your teardown. Required override. |
You never write
Awake,OnEnable,Start,OnDisable, orOnDestroyyourself — the base class owns them. They'reprotectedon purpose: if you accidentally re-declare one, the compiler flags it (CS0108) instead of silently breaking the singleton.
Create an empty GameObject, add your manager component, and save it as a prefab
(e.g. GameManager.prefab). Delete the GameObject from the scene after saving — the framework will spawn it for you on Step 4.
Create the list asset via Assets → Create → PlayerMadeGames → ManagersT → ManagerList.
- Name the asset
Managersand place it atAssets/Resources/Managers. (The bootstrapper loads it by that name from aResourcesfolder.) - Drag your manager prefabs into the
Managerslist. (Prefabs, not scripts — the bootstrapper instantiates each entry's GameObject.)
When you enter Play mode, ManagersBootstrapper runs automatically
([RuntimeInitializeOnLoadMethod(BeforeSceneLoad)]), instantiates every prefab in the
list, and each one claims its singleton and marks itself DontDestroyOnLoad. Access any
manager from anywhere via GameManager.Instance.
The reason ReInit exists: managers usually need to react to scene loads, not just
survive them. A persistent AudioManager that keeps the same AudioSource alive across
scenes still wants to swap the track when you move from the menu to the level.
protected override void ReInit(string fromScene, Scene toScene)
{
PlayMusicForScene(toScene.name);
}ReInit only fires on actual scene changes — it's suppressed on the very first load
(where there's no meaningful "from" scene), so Init() owns first-scene setup and
ReInit owns everything after. Because the initial activeSceneChanged event is
inconsistent in Unity, the recommended pattern is:
Init()handles the opening scene.ReInit()handles every scene change after that.
See the Audio Manager Example sample for a complete, working implementation of all three hooks across two scenes.
Import via Package Manager → PMG ManagersT → Samples:
- Audio Manager Example — a full
Init/ReInit/Deletelifecycle that swaps the soundtrack per scene across two demo scenes.
- Mis-wired CRTP is caught loudly. If you write
class Foo : Manager<Bar>by mistake, the framework logs a clear error and disables that singleton rather than throwing or silently misbehaving. - Duplicates self-destruct. If a second instance of a manager is ever created, it destroys its own GameObject and leaves the original untouched.
OnDestroyis sealed. You can't accidentally override it and forgetbase.OnDestroy()(which would leak the static instance). UseDelete()for teardown.- No ManagerList found? If
Assets/Resources/Managersis missing, the bootstrapper logs an error and spawns nothing — your game runs, just without managers.
MIT. See LICENSE.md.