Decoupling Events, Better Lerps, and Zero-Garbage Tags

editor tools extension methods game architecture garbage collection naughtyattributes optimization programming scriptableobjects unity unity beginner guide unity game development Dec 16, 2025

Welcome to Local Space.

If you are new here, this is my recurring dev log. I spend my week building in Unity, figuring out how to make things work, and inevitably breaking them. Then, I share the notes, tools, and code snippets that actually survived the process.

In this log, we are looking at decoupling your architecture, a math trick for mapping values, and a free asset that saves you hours of UI work.

The Deep Dive: ScriptableObject Events

One of the most common architectural traps in Unity is direct referencing. We have all been there. You want the UI to update when the Player dies, so you write:

FindObjectOfType<UIManager>().UpdateHealth();

The Problem: Your Player script now depends on the UI Manager. If you delete the UI, disable it, or move it to another scene, the Player script breaks. This is the definition of "spaghetti code."

💡 The Solution: Event Assets
Instead of Scripts talking to Scripts, Scripts should talk to an Event Asset (a ScriptableObject) sitting in your project folder.

  1. The Sender (Player) tells the Asset "I took damage."
  2. The Receiver (UI) listens to the Asset.
  3. Neither script needs to know the other exists.

Ryan Hipple gave a famous talk on this at Unite Austin years ago, and as far as I know it remains the gold standard for keeping Unity projects modular. If you haven't implemented this pattern yet, check it out!

Snippet: The "Remap" Extension

Mathf.Lerp is great, but frequently I need to map a value from one specific range to another—for example, mapping a Player's HP (0 to 100) to a UI Color Gradient (0.0 to 1.0) or Audio Volume (-80db to 0db).

Mathematically, this is linear interpolation. Instead of rewriting the math every time, I use this static extension method in almost every project.

public static class ExtensionMethods
{
    // Map a value from one range to another
    public static float Remap(this float value, float from1, float to1, float from2, float to2)
    {
        return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
    }
}

How to use it:

// Map speed (0 to 20) to Audio Decibels (-80 to 0)
float volume = playerSpeed.Remap(0f, 20f, -80f, 0f);

Wait, how does that work?

If you are new to C#, Extension Methods might look like magic. You are adding a new function to the standard float type, which was written by Microsoft years ago. You can't edit their source code, so how are we adding to it?

🎮 The "DLC" Analogy
Think of Extension Methods as installing DLC (Downloadable Content) for existing code.

The float type is the base game. It comes with standard features. When we write (this float value...), we are telling the compiler to "glue" our custom method onto every float in the game.

Without extension methods, you would have to write:

// The "Old" Way
ExtensionMethods.Remap(mySpeed, 0, 10, 0, 1);

But with the this keyword, Unity lets us write it as if it belongs to the variable itself:

// The "Extension" Way (Cleaner!)
mySpeed.Remap(0, 10, 0, 1);

Want the technical breakdown? Read the official Microsoft documentation here.

Hidden Gem: NaughtyAttributes

Writing Custom Editors in Unity is tedious. Usually, you have to create a separate script inside an Editor folder just to add a simple debug button to your inspector.

NaughtyAttributes is an open-source library that solves this using attributes directly in your MonoBehaviour.

  • Want a button? [Button] private void Attack() { ... }
  • Want a conditional field? [ShowIf("isEnemy")] public float aggroRange;

It’s free, lightweight, and essential for tool building.

Get NaughtyAttributes

Performance Watch: Tags

If you are using OnCollisionEnter, check your tag comparisons.

❌ Avoid this:

if (collision.gameObject.tag == "Player")

This allocates memory (garbage) every time it runs because it creates a new string.

✅ Do this instead:

if (collision.gameObject.CompareTag("Player"))

It is zero-allocation and slightly faster.



// When you are ready

Here are 3 ways I can help you level up your game dev journey:

Local Space is a production of Faktory Studios.
© 2024 All rights reserved.

Start with the free Unity Kickstart Mini-Series

Perfect for learning the fundamentals.

We hate SPAM. We will never sell your information, for any reason.