ToolAIPilotTAP
Sub

Ad

i designed my unity 6 scriptableobject architecture with claude before writing a single line and it was the best decision i made on this project
developerGuideยท 7 min readยท 2,085

i designed my unity 6 scriptableobject architecture with claude before writing a single line and it was the best decision i made on this project

ScriptableObjects are one of the most powerful patterns in Unity and one of the most misused. I have rebuilt a ScriptableObject-based data system twice on previous projects after getting the architecture wrong. On my current project I spent one evening with Claude designing the entire ScriptableObject architecture before opening Unity and I have not needed a rebuild in four months. This is what that design session looked like and the system it produced.

๐Ÿ”ง Tools mentioned in this article
Claude

Claude

Used to design the entire ScriptableObject architecture before any code was written, Pro plan $20 per month

claude.ai

Visit
Cursor

Cursor

Used to implement the designed architecture in Unity 6 C#, Pro plan $20 per month

cursor.sh

Visit
Unity

Unity

Unity 6 LTS, Personal plan free under $100k revenue

unity.com

Visit
Unity Muse

Unity Muse

Muse Chat used for Unity 6 specific ScriptableObject API questions, $30 per month

unity.com

Visit
Marcus Webb

Marcus Webb

June 28, 2026

#unity 6 scriptableobject architecture claude cursor personal honest 2026#designing unity scriptableobject with ai claude personal experience 2026#unity 6 scriptableobject system design claude cursor personal 2026#unity scriptableobject architecture ai personal honest guide 2026#claude cursor unity 6 scriptableobject design personal honest 2026

The two previous failures: RPG project one, I started with ItemData as a plain C# class. Six weeks in I realised the Item data needed to be editable in the Unity Inspector. Rebuilt as ScriptableObjects and spent two days reconnecting references. RPG project two, I built ScriptableObjects for Item and Quest data but not for the event system. By month three the event spaghetti between systems was unmanageable. Rebuilt the event architecture. Total wasted rebuild time across two projects: approximately nine hours. The Claude architecture session for the current project took two hours and prevented both categories of rebuild.

The Claude Architecture Session: What I Asked and What Came Back

I started the Claude session with a complete description of my game: a 3D action RPG with item loot, quest tracking, character progression, and dialogue. I asked Claude to design a ScriptableObject architecture that covered all four systems with the specific constraint that systems should be able to communicate through events without direct references to each other. I also told Claude I had made two specific mistakes on previous projects and described them. Claude designed an architecture that directly addressed both previous failure modes before I asked it to.

The Architecture That Came Out of the Session

  • GameEvent ScriptableObjects: A base GameEvent class and typed subclasses like ItemPickedUpEvent and QuestCompletedEvent. Any system can raise an event by calling GameEvent.Raise(). Any system can listen by registering a listener on the event asset. No system references another system directly.
  • ItemData ScriptableObjects: One class covering all item properties including name, description, icon, stats modifiers, weight, and type enum. A separate ItemDatabase ScriptableObject that holds a list of all items and exposes lookup by ID. Items are never stored as class instances at runtime; they are always references to ScriptableObject assets.
  • QuestData ScriptableObjects: Quest definition including objectives as a nested class list, rewards, and prerequisite quest references. A QuestState ScriptableObject separate from QuestData that tracks runtime completion state. This separation means the base quest data is always read-only during gameplay.
  • RuntimeSets: A pattern Claude recommended that I had not used before. A RuntimeSet is a ScriptableObject that holds a list of objects that register and unregister themselves. An EnemyRuntimeSet holds all active enemies. Any system that needs to know how many enemies are alive queries the ScriptableObject, not a manager class.
  • Variable ScriptableObjects: IntVariable, FloatVariable, BoolVariable ScriptableObjects that store a single runtime value. Player health is a FloatVariable. Player gold is an IntVariable. The HUD reads these directly and responds to their change events. No GameManager needed to relay these values.

The GameEvent ScriptableObject Implementation

csharp
// GameEvent.cs
// Base ScriptableObject event system
// Designed by Claude, implemented with Cursor in Unity 6
// Create assets via right-click > Create > Events > Game Event

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "NewGameEvent", menuName = "Events/Game Event")]
public class GameEvent : ScriptableObject
{
    // Listeners register and unregister themselves
    private readonly List<GameEventListener> listeners = new List<GameEventListener>();

    public void Raise()
    {
        // Iterate backwards so listeners can safely remove themselves during iteration
        for (int i = listeners.Count - 1; i >= 0; i--)
        {
            listeners[i].OnEventRaised();
        }
    }

    public void RegisterListener(GameEventListener listener)
    {
        if (!listeners.Contains(listener))
            listeners.Add(listener);
    }

    public void UnregisterListener(GameEventListener listener)
    {
        listeners.Remove(listener);
    }
}

// GameEventListener.cs
// MonoBehaviour that listens to a GameEvent and calls a UnityEvent response
using UnityEngine;
using UnityEngine.Events;

public class GameEventListener : MonoBehaviour
{
    [Tooltip("The GameEvent asset this listener responds to")]
    public GameEvent Event;

    [Tooltip("Response to invoke when the event is raised")]
    public UnityEvent Response;

    void OnEnable()
    {
        if (Event != null) Event.RegisterListener(this);
    }

    void OnDisable()
    {
        if (Event != null) Event.UnregisterListener(this);
    }

    public void OnEventRaised()
    {
        Response?.Invoke();
    }
}

// FloatVariable.cs
// ScriptableObject that stores a runtime float with change event
using UnityEngine;
using System;

[CreateAssetMenu(fileName = "NewFloatVariable", menuName = "Variables/Float Variable")]
public class FloatVariable : ScriptableObject
{
    [SerializeField] private float value;
    public event Action<float> OnValueChanged;

    public float Value
    {
        get => value;
        set
        {
            this.value = value;
            OnValueChanged?.Invoke(this.value);
        }
    }

    // Called in OnEnable of scenes to reset runtime values
    // Prevents values from persisting between Editor play sessions
    public void ResetToDefault(float defaultValue)
    {
        Value = defaultValue;
    }
}

// Usage example - Player health:
// PlayerHealth.cs references a FloatVariable asset in the Inspector
// When player takes damage:
// playerHealthVariable.Value -= damageAmount;
// The HUD FloatVariable.OnValueChanged listener updates the health bar automatically
// No PlayerHealth to HUD reference needed

What Cursor Added on Top of the Claude Design

  • Implementing all classes with my project naming conventions: Claude designed the architecture in plain language. Cursor implemented every class using PascalCase for my public fields, my preferred event pattern using C# Action delegates where applicable, and the Unity 6 API patterns for ScriptableObject creation menus.
  • Generating the ItemDatabase with lookup methods: Claude specified that ItemDatabase should expose lookup by ID. Cursor implemented the Dictionary-based lookup cache inside the ItemDatabase ScriptableObject using my ItemData class structure which it already knew from the project index.
  • Writing the QuestManager that interfaces with QuestData and QuestState: the QuestManager MonoBehaviour that handles quest activation, objective tracking, and completion was written by Cursor with full knowledge of both the QuestData ScriptableObject design Claude had specified and the GameEvent system Cursor had already implemented.
  • Adding null safety and defensive coding throughout: Cursor consistently adds null checks and defensive guard clauses to generated code without being asked. Several places in the ScriptableObject system where a missing asset reference could produce confusing runtime errors are protected.

Four Months Without a Rebuild: Why This Architecture Held

The key property that Claude built into this architecture was that no system has a direct reference to another system. The Player does not reference the HUD. The QuestManager does not reference the Player. Every communication flows through ScriptableObject events or variables. When I needed to add a new system in month three, a crafting system, it registered listeners on existing events and read from existing variables without requiring changes to any existing system. Adding a system was additive not integrative. This is the property that prevents the spaghetti rebuilds I had experienced on previous projects.

Mistakes Even With a Good Architecture

  • Not resetting FloatVariable values between Editor play sessions: The FloatVariable ScriptableObject persists its runtime value between play mode sessions in the Editor. A player who died with 20 health would start the next play session with 20 health in the Editor. Added a SceneInitialiser MonoBehaviour that resets all Variable ScriptableObjects to their default values on scene load. Claude identified this as a known gotcha when I described unexpected starting values.
  • Too many GameEvent assets: by month two I had 34 GameEvent assets in the project for very granular events. Events like EnemyTookDamage and EnemyTookKnockback that could have been one event with parameters. Consolidated to 18 events. Muse Chat suggested typed GameEvent subclasses that carry data for this consolidation.
  • Listener iteration order dependency: two listeners on the same GameEvent responded to the same event and one depended on the other having processed first. The listener list does not guarantee order. Refactored the dependent logic into one listener.

Final Thoughts

Two hours with Claude before writing a single line of Unity code prevented nine hours of rebuilding that I have spent on every previous RPG project. The ScriptableObject architecture Claude designed is not original, it draws from well-known Unity architecture patterns. What Claude added was the ability to design the whole system for my specific game requirements in a conversation rather than assembling it piece by piece from documentation and tutorials. Cursor then implemented the architecture correctly and quickly. Four months without a rebuild is the result.

Ad