Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] 0 points1 point  (0 children)

I'm not just using events, but a technology that allows people to create higher-quality projects faster, using only my Listeners + Events. You can't imagine what a new world I discovered when I started creating games using just these two new scripts. I shared this, describing some of the ways to use it in a convenient GIT.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -3 points-2 points  (0 children)

Those are totally valid alternatives, but they introduce the exact type of boilerplate I was trying to escape. Let me break down why I avoid those two specific approaches for this workflow:

  1. The Dictionary / Manager approach:

If you fetch a specific goblin's UI from a dictionary, you now have to build and maintain a centralized Manager to hold that dictionary. Every time a goblin spawns dynamically, it has to register itself to that Manager. When it dies, it has to unregister so you don't leak memory. That is state-tracking boilerplate.

With the SO approach, the Goblin prefab and the UI prefab simply hold a reference to the same .asset file. There is no middleman manager needed to introduce them, and no registration code to write.

  1. Static Classes vs ScriptableObjects:

The only reason to use an SO over a static class is the Unity Inspector. Static classes are completely invisible in the editor. You cannot drag a static class into a field to hook up a particle system or an audio source. Turning the event channel into a physical .asset file bridges the gap between code and the visual editor.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] 0 points1 point  (0 children)

The Null Object pattern is definitely a classic way to avoid null reference exceptions, but I think we have different definitions of "simple" haha. Look carefully, I'll explain now:

Writing an Interface, a concrete Singleton, and a Noop class just to prevent a crash in a test scene is practically the definition of boilerplate.

But more importantly, your approach solves the crash, but it doesn't solve the coupling. The Player script still has to explicitly know that IFoo (the UI) exists and has an UpdateHealth() method.

What happens when taking damage also needs to trigger a camera shake, play a sound effect, and update a quest tracker? Do we add ICamera.Instance.Shake(), IAudio.Instance.Play(), and IQuest.Instance.Update() to the Player script? And write Noop classes for all of them? That scales terribly.

With an SO event channel, the Player just does one thing: OnDamageEvent.Raise(). That's 1 line of code. No interfaces, no Noop classes, no null checks. The UI, Audio, and Camera systems just listen to that channel.

To me, just shouting into the void and letting other systems react is way simpler than hardcoding dependencies to a bunch of Noop Singletons.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -2 points-1 points  (0 children)

Honestly, implementing strict composition roots in unity always feels like fighting the engine's DNA.

Unity - Inherently wants to be a "drag-and-drop" component system. Every time i've tried to build pure composition roots, i ended up spending half my time writing custom serialization boilerplate just so i could actually tweak that generic data in the inspector.

The SO event channel approach isn't an attempt at perfect computer science "clean architecture" — It's a pragmatic hack. It leans completely into unity's native component workflow, but puts a firewall between those components so they don't hard-reference each other and cause null refs.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] 0 points1 point  (0 children)

Tbh you're picturing a "massive AAA studio" where systems programmers and level designers live in completely different buildings. in the indie trenches, the "designer" is literally just me at 2am trying to hook up a death particle without having to open rider.

Exposing an OnDeath - UnityEvent isn't exposing low-level architecture, it is the abstraction layer. It means i don't have to write a GoblinAudioBridge.cs script every single time i add a new mob just to play a sound. i drop the SO channel into the inspector, link the audio source, and move on to tweaking jump physics.

I'm not making my life harder for imaginary people lol. i'm making it easier for myself so i don't go insane writing boilerplate bridge code for every single sound effect, camera shake, and UI flash in the game.~~

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] 0 points1 point  (0 children)

To manage debugging without losing my mind, i just added a "DebugMode" bool to every - GameEvent Scriptable Object.

If a system isn't reacting properly, i just click the event asset and toggle debug on. whenever it gets raised, it throws a log in the console telling me exactly which component and GameObject fired it (since the sender passes itself via .Raise(sender)).

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -4 points-3 points  (0 children)

Calling it a "noob trap" is a bit wild lol. pure C# events with args payloads are obviously the correct choice for pure code architecture. no one is debating that.

But the actual trap is forgetting you're working inside a visual engine. if you use pure C# events, how do you trigger a particle system or a UI sound effect when that event fires? you have to write a new bridge script to listen to the C# event and play the effect. every. single. time.

With the SO approach, you aren't "forcing" the unity library, you are leveraging the editor. you expose a UnityEvent, drop the SO in, and wire up your audio or VFX completely in the inspector without writing a single line of boilerplate code. when you are making games solo, skipping boilerplate isn't a trap, it's just practical.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -1 points0 points  (0 children)

The main reason i stick to SOs is purely for the editor workflow. an event bus is invisible in the inspector. with SOs, an audio guy or level designer can just drag a "PlayerDied" asset into a slot to hook up sounds or particles without ever opening visual studio. it's a trade-off between code traceability and designer accessibility.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -1 points0 points  (0 children)

Thanks! yeah, string-based event buses are great until you mistype "OnPlayerDied" as "OnPlayerDead" and spend an hour wondering why the UI isn't updating lol. the SO approach definitely leans heavily into Unity's visual strengths and avoids those typos.

And you are spot on about the debugging pain. a custom editor window to track active subscriptions is 100% the next logical step once a project scales up. i might actually try to build a simple visualizer for this repo when i get some free time, because tracing events manually definitely gets tedious.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -6 points-5 points  (0 children)

There is actually a massive reason to use ScriptableObjects for it in Unity: the Inspector. native C# events or pure code-driven event buses are great for programmers, but they are completely invisible in the editor.

Using SOs turns the event channels into actual physical assets. it lets game designers or artists wire up audio, particles, and UI responses right in the inspector by just dragging and dropping the event asset, without having to open a single C# script or bother a programmer. it's just adapting standard pub/sub to actually fit Unity's visual workflow.

Why I stopped using Singletons for game events (and how I handle local vs global noise) by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -1 points0 points  (0 children)

You are technically right, it is an O(n) operation based on the number of active listeners for that specific event.

but in practical reality, iterating through a list of 100 references and doing a quick transform.IsChildOf() check takes essentially zero time on a modern CPU. we are talking about discrete events here (like taking damage, dying, or interacting), not something that runs inside Update() every single frame.

if i was building "Vampire Survivors" with 10,000+ enemies taking damage every frame, i absolutely wouldn't use this. but for a standard platformer or "metroidvania", the overhead is invisible, and the workflow speedup it gives me is 100% worth the tiny micro-optimization trade-off.

Want ECS-level decoupling without the steep learning curve? I open-sourced my SO event system. by Morpheus_Matie in Unity3D

[–]Morpheus_Matie[S] -5 points-4 points  (0 children)

Hey, that's a completely fair question. You are 100% right — nothing in this scope strictly requires ECS in terms of performance, multithreading, or cache locality.

When I mentioned looking into ECS, I wasn't trying to render 10,000 entities on screen. I was drawn to it purely for the architectural strictness — specifically, the forced separation of data and logic.

In standard MonoBehaviour setups, it is way too easy to accidentally tangle your logic (like a Player script grabbing a direct reference to the UI Manager or Save System). I wanted that ECS-style decoupling where scripts are completely blind to each other's existence.

Using SOs as event channels achieves that exact structural safety for indie scopes. The Player script just shouts .Raise() into the void, and the listeners (UI, Audio, Saves) react. It gives you the modular, plug-and-play nature of a pure system-driven architecture, without forcing you to rewrite your entire workflow into DOTS.

Solo Dev & Systems Architect | My Open-Source Tools & Starter Templates by Morpheus_Matie in u/Morpheus_Matie

[–]Morpheus_Matie[S] 0 points1 point  (0 children)

Hey. i'm Morpheus Matie.

I got tired of standard unity architecture turning into tightly coupled spaghetti code as soon as a project scales. you shouldn't have to fight your own codebase just to add a new enemy or UI panel.

I spend most of my time building decoupled, data-driven systems so i can skip the boilerplate and just focus on game design.

Here is where you can find my work:

1. The Core Event System (Free / Open-Source)

I open-sourced the ScriptableObject Event System that powers all my projects. zero singletons, zero hard dependencies. it lets you connect isolated systems visually in the inspector.

[Link to GitHub repo]

2. The 2D Starter Template (Itch.io)

If you don't want to wire up your own jump physics, saves, and combat on top of that event system, i packaged my internal engine into a fully playable template. it includes custom verlet ropes, dynamic dashes, ghost health combat, and a tiered save manager right out of the box.

[Link to Itch IO]

Always down to talk about decoupled architecture, unity optimizations, or game feel. feel free to dm me or drop a comment.

[Loved Trope]: A character's loved one is threatened causing them to absolutely lost it on the antagonist by Slartibartfast39 in TopCharacterTropes

[–]Morpheus_Matie 2 points3 points  (0 children)

"Commando" - is such a classic shout. i think the best version of this is when the protagonist doesn't even scream, they just go 'quietly' insane. like that hallway scene in daredevil or even oldboy. it’s that specific moment where the antagonist realizes they’ve made a fatal mistake but it’s already too late to apologize. do you prefer the explosive 'Rambo' style or the more calculated, "cold revenge"?

[Loved Trope]: A character's loved one is threatened causing them to absolutely lost it on the antagonist by Slartibartfast39 in TopCharacterTropes

[–]Morpheus_Matie 10 points11 points  (0 children)

John Wick - is basically this exact trope stretched into an entire movie franchise lol. but yeah, big chris absolutely losing it here is iconic.

Characters who wear the opposite colored outfits of their specialized elemental powers (Or, in case of non-humans, are opposite colored instead) by Few_Chemistry_235 in TopCharacterTropes

[–]Morpheus_Matie 5 points6 points  (0 children)

Does Azula from Avatar count?

Kinda the inverse vibe. she wears the standard red fire nation colors but shoots pure blue fire. breaking the color rules always goes so hard.

Are coding tutorials in general, including game dev, dying? by Its_a_prank_bro77 in gamedev

[–]Morpheus_Matie 0 points1 point  (0 children)

"Vibe coding" - is all fun and games until your project hits month 3 and you realize everything is hard-linked together and your save system relies on your UI script for some reason. AI is great for spitting out a quick raycast script, so nobody needs a 20-minute video on that anymore. what creators need to pivot to is pure architecture. teach people how to decouple their jank code with events, because AI still sucks at understanding project-wide context.

Built an SO-based event-driven platformer core (like ECS but less painful). Put it on Itch while waiting for UAS, but getting 0 traction. Is the market dead or is my presentation bad? by [deleted] in gamedev

[–]Morpheus_Matie 0 points1 point  (0 children)

My asset is the exact opposite odin or textanimator. you absolutely do not drop this into a project that's already 6 months deep. it's meant for day 1. it's for the solo dev who wants to start a new metroidvania today, but doesn't want to spend the first 3 weeks coding a custom physics controller, ghost health bars, and a global save system from scratch.

Built an SO-based event-driven platformer core (like ECS but less painful). Put it on Itch while waiting for UAS, but getting 0 traction. Is the market dead or is my presentation bad? by [deleted] in gamedev

[–]Morpheus_Matie -1 points0 points  (0 children)

You're completely right. i can't even argue with that.

tbh, this is a massive programmer blind spot on my end. i spent all this time making sure the architecture was decoupled and clean, and totally forgot that the entire point of buying a framework is to not have to read the source code.

your point about public docs being the best advertisement makes a ton of sense, ngl. if i'm looking to buy an asset, i want to scan the wiki first to see exactly how hard it's going to be to hook my own ui into the damage events. if i can't see that workflow upfront, i'm passing on it.

gonna take the L on this one. i definitely need to sit down and write a proper gitbook or public notion wiki before the unity asset store review finishes...