Tuesday, August 4, 2026

10 ScriptableObject Patterns Every Unity Developer Should Know (Part 2) Variable Assets, Ability Definitions, Item Databases

In the previous article, we explored three of my favorite ScriptableObject patterns:

            • Data Assets

            • Runtime Sets

            • Event Channels

If those patterns help organize your project, the next four we're covering today help organize your gameplay. They're all about making your game easier to balance, extend, and maintain without constantly diving into your code.

As with every design pattern, these aren't solutions looking for problems. They're practical techniques that shine in the right situations, and as always, can become overkill if used everywhere.

Let's jump in!

 

4. Variable Assets

This is one of those patterns that initially seems a little strange. After all, variables already exist. So why would one put it inside a ScriptableObject?

The answer is simple:

Sometimes multiple systems need access to the same value without knowing about each other.

Let's say your game has a difficulty multiplier.

Several systems need to read it.

  • Enemy spawning

  • Enemy health

  • Loot drops

  • Experience rewards

  • Boss damage

Instead of each system referencing a GameManager, they can all reference the same asset.

using UnityEngine;

[CreateAssetMenu(menuName = "Variables/Float Variable")]

public class FloatVariable : ScriptableObject
{
    public float Value = 1f;
}

Now your enemy can simply read it.

[SerializeField] private FloatVariable difficultyMultiplier;

private void Start()
{
    health *= difficultyMultiplier.Value;
}

Simple, clean and no manager required.

 

A Word of Caution 

This pattern is often misunderstood.

Some developers begin creating ScriptableObjects for every single variable in their project. The point is that Variable Assets are intended for shared values, not values unique to individual objects. A player's current health usually belongs only to the Player. The game's global difficulty multiplier? That's a perfect candidate.

Great Uses

Variable Assets work well for:

  • Difficulty multipliers

  • Global volume

  • Mouse sensitivity

  • Time scale modifiers

  • Experience multipliers

  • Day/night speed

  • World gravity settings

Notice the pattern? They're all values shared across multiple systems.


5. Ability Definitions

If you're making an RPG, action game, or anything involving player abilities, ScriptableObjects can save you an incredible amount of duplicated work.

Imagine every spell stores:

  • Mana cost

  • Cooldown

  • Icon

  • Description

  • Animation

  • Particle effect

Without ScriptableObjects, every ability component quickly becomes bloated.

Instead, create an Ability asset.

using UnityEngine;

[CreateAssetMenu(menuName = "Abilities/Ability")]

public class AbilityData : ScriptableObject
{
    public string abilityName;
    public Sprite icon;

    public float cooldown;
    public int manaCost;

    public GameObject effectPrefab;
}

Your player simply references the asset.

public class AbilityCaster : MonoBehaviour
{
    [SerializeField] private AbilityData ability;

    public void Cast()
    {
        Debug.Log($"Casting {ability.abilityName}");
    }
}
 

Now adding a new spell is easy, just create another asset. Done.

 

Why Designers Love This

Imagine balancing twenty abilities. Without ScriptableObjects you'd need to edit twenty different prefabs.

With ScriptableObjects you simply tweak the asset. Even better, designers can adjust cooldowns and mana costs without touching gameplay code.

Everyone wins!

Well...

Except perhaps the overpowered Fireball you've just nerfed...

 

Extending the Pattern

As your project grows, AbilityData can include:

  • Casting animations

  • Audio clips

  • Unlock requirements

  • Cooldown categories

  • Targeting rules

  • Status effects

Notice something?

The MonoBehaviour barely changes.

Only the data grows.

That's exactly what you want.


6. Item Databases

Here's a question. How do you look up item number 47?

Many beginners create huge switch statements.

switch(itemID)
{
    ...
}

Or dozens of if statements, both become difficult to maintain.

Instead, create an Item Database.

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Items/Item Database")]

public class ItemDatabase : ScriptableObject
{
    public List<ItemData> Items = new();
}

Now every item lives inside one central asset.

 

Looking Up Items

Need an item?

ItemData sword = itemDatabase.Items[0];

Or perhaps search by ID.

public ItemData GetItem(int id)
{
    return Items.Find(item => item.ID == id);
}

Suddenly your inventory system becomes much cleaner. Every system references one database.

No duplicated information.

 

Why This Pattern Scales

Imagine your game eventually contains:

  • 300 weapons

  • 200 consumables

  • 150 crafting materials

  • 80 quest items

Would you rather maintain hundreds of switch statements, or just one searchable asset? I know which one I'd pick. My present self has enough problems already.

 

Bonus Tip

If your database becomes large, consider storing items inside a Dictionary at runtime for faster lookups and keep the serialized List for the Inspector. Build the Dictionary automatically during initialization.

Best of both worlds.


7. Spawn Tables

Let's finish with one of my favorites! Spawn Tables. Suppose your game randomly spawns loot.

A beginner solution might look like this.

if(Random.value < 0.5f)
{
    SpawnPotion();
}
else
{
    SpawnSword();
}

Now add:

  • Shields

  • Armor

  • Rare weapons

  • Legendary items

  • Coins

  • Gems

  • Scrolls

Your spawning code quickly starts resembling an accountant's spreadsheet. Instead...

Move the probabilities into a ScriptableObject.

using UnityEngine;

[System.Serializable]

public class SpawnEntry
{
    public GameObject prefab;
    public float weight;
}

Then create a Spawn Table.

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Spawning/Spawn Table")]

public class SpawnTable : ScriptableObject
{
    public List<SpawnEntry> Entries = new();
}

Now your spawning logic simply reads the table, the data determines what appears. The code only performs the selection.

 

Why This Is Better

Let's say you're balancing loot drops. Instead of modifying code, you simply change the weights inside the asset. Want legendary swords to become rarer? Adjust one value. Need a Halloween event? Create a different Spawn Table. No code changes required.

 

More Than Loot

Spawn Tables work beautifully for:

  • Enemy waves

  • NPC encounters

  • Ambient sounds

  • Weather events

  • Random dialogue

  • Treasure chests

  • Dungeon generation

Anywhere something needs to be selected randomly, a Spawn Table is worth considering.


Let's wrap up

Alright, the patterns we've covered today all share one important goal: Move game configuration out of your code. Variable Assets centralize shared values and Ability Definitions separate gameplay logic from ability configuration.

Item Databases provide a single source of truth for your game's items, and Spawn Tables make balancing randomness a matter of changing data instead of rewriting code.

As your project grows, you'll likely find yourself using these patterns more and more, not because they're trendy, but because they naturally reduce duplication and make your game easier to maintain.

And perhaps that's the biggest lesson ScriptableObjects have to teach. They're not just data containers, they're a way of thinking about your architecture.

When your data and your behavior each have a clear responsibility, your project becomes easier to understand, easier to balance, and much less likely to collapse into an unholy bowl of spaghetti code.

In the final part of this series, we'll look at some of the more advanced ScriptableObject patterns, including the Factory Pattern, AI Behaviour Assets, and Global Configuration Assets, as well as discussing when ScriptableObjects are not the right tool for the job.

In the meantime, ~happy coding! 

No comments:

Post a Comment