AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Uw Scriptable Object Arch

skill-devdavv-unity-ai-workflow-uw-scriptable-object-arch · by devdavv

Generate ScriptableObject-based systems including data containers, event channels, and runtime sets. Use when creating game data (weapons, enemies, items, abilities), cross-system events, or live object tracking. Triggers on requests like "create weapon data", "add an event system", "make a runtime set", "decouple these systems", "create item database", "add a damage event", "track active enemies…

No reviews yet
0 installs
4 views
0.0% view→install

Install

$ agentstack add skill-devdavv-unity-ai-workflow-uw-scriptable-object-arch

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-devdavv-unity-ai-workflow-uw-scriptable-object-arch)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Uw Scriptable Object Arch? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

ScriptableObject Architecture

Generate SO patterns for data, events, and runtime collections.

Before You Start

  1. Read docs/ProjectConfig.yaml for:
  • architecture_pattern"so-first" (default, this skill is primary) or "di-first" (SOs still hold data, but events become Commands — see uw-dependency-injection).
  • mcp.unity_mcp — if true, call refresh_unity after creating files.
  1. Read docs/TDD_Template.md for data architecture decisions.
  2. Read docs/NAMING_CONVENTIONS.md for SO file naming (PascalCase: SwordData.asset).
  3. Ensure the feature has an .asmdef — create with uw-unity-feature-scaffold if needed.

Three Patterns

1. Data Container

Store game-tunable values in a ScriptableObject. Designers edit them in the Inspector without touching code.

using UnityEngine;

[CreateAssetMenu(fileName = "New WeaponData", menuName = "Game/Data/Weapon Data")]
public class WeaponData : ScriptableObject
{
    [Header("Combat")]
    [SerializeField] private float _damage = 10f;
    [SerializeField] private float _fireRate = 0.5f;
    [SerializeField] private float _range = 15f;

    [Header("Ammo")]
    [SerializeField] private int _maxAmmo = 30;
    [SerializeField] private float _reloadTime = 1.5f;

    [Header("Feel")]
    [SerializeField] private ShakeProfile _hitShakeProfile;
    [SerializeField] private AudioClip _fireSound;
    [SerializeField] private GameObject _muzzleFlashPrefab;

    // Read-only properties — game code reads, designers tune in Inspector
    public float Damage => _damage;
    public float FireRate => _fireRate;
    public float Range => _range;
    public int MaxAmmo => _maxAmmo;
    public float ReloadTime => _reloadTime;
    public ShakeProfile HitShakeProfile => _hitShakeProfile;
    public AudioClip FireSound => _fireSound;
    public GameObject MuzzleFlashPrefab => _muzzleFlashPrefab;
}

2. Event Channel

Decouple systems by broadcasting events through a ScriptableObject asset. Any system can subscribe without knowing who raises the event.

Parameterless event:

using System;
using UnityEngine;

[CreateAssetMenu(fileName = "New GameEvent", menuName = "Game/Events/Game Event")]
public class GameEvent : ScriptableObject
{
    private event Action _onRaise;

    public void Raise() => _onRaise?.Invoke();
    public void Subscribe(Action listener) => _onRaise += listener;
    public void Unsubscribe(Action listener) => _onRaise -= listener;
}

Typed event channels for events that carry data:

using System;
using UnityEngine;

[CreateAssetMenu(fileName = "New IntEvent", menuName = "Game/Events/Int Event")]
public class IntEvent : ScriptableObject
{
    private event Action _onRaise;

    public void Raise(int value) => _onRaise?.Invoke(value);
    public void Subscribe(Action listener) => _onRaise += listener;
    public void Unsubscribe(Action listener) => _onRaise -= listener;
}

[CreateAssetMenu(fileName = "New FloatEvent", menuName = "Game/Events/Float Event")]
public class FloatEvent : ScriptableObject
{
    private event Action _onRaise;

    public void Raise(float value) => _onRaise?.Invoke(value);
    public void Subscribe(Action listener) => _onRaise += listener;
    public void Unsubscribe(Action listener) => _onRaise -= listener;
}

Usage:

// Publisher (doesn't know who listens)
[SerializeField] private IntEvent _onScoreChanged;
_onScoreChanged.Raise(newScore);

// Subscriber (doesn't know who publishes)
[SerializeField] private IntEvent _onScoreChanged;
private void OnEnable() => _onScoreChanged.Subscribe(UpdateScoreUI);
private void OnDisable() => _onScoreChanged.Unsubscribe(UpdateScoreUI);

3. Runtime Set

Track live objects (active enemies, collectibles, spawned projectiles) without FindObjectsOfType. Objects register themselves on spawn and unregister on destroy.

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "New RuntimeSet", menuName = "Game/Sets/Runtime Set")]
public class RuntimeSet : ScriptableObject
{
    private readonly List _items = new();
    public IReadOnlyList Items => _items;
    public int Count => _items.Count;

    public void Add(T item)
    {
        if (!_items.Contains(item))
            _items.Add(item);
    }

    public void Remove(T item) => _items.Remove(item);

    private void OnDisable() => _items.Clear(); // Prevent stale refs across play sessions
}

Concrete sets (needed because Unity can't serialize open generics):

[CreateAssetMenu(fileName = "New EnemySet", menuName = "Game/Sets/Enemy Set")]
public class EnemyRuntimeSet : RuntimeSet { }

Self-registering pattern:

public class EnemyController : MonoBehaviour
{
    [SerializeField] private EnemyRuntimeSet _activeEnemies;

    private void OnEnable() => _activeEnemies.Add(this);
    private void OnDisable() => _activeEnemies.Remove(this);
}

Naming Convention

| Pattern | Naming | Example | |---------|--------|---------| | Data Container | {Type}Data | WeaponData, EnemyData | | Event Channel | {Action}Event | OnDeathEvent, ScoreChangedEvent | | Typed Event | {Type}Event | IntEvent, FloatEvent, StringEvent | | Runtime Set | {Type}Set or {Type}RuntimeSet | EnemySet, CollectibleRuntimeSet |

After Setup

  • Add game feel: Use uw-game-feel-integrator — SO data containers pair well with feel parameters (ShakeProfile, tween durations stored in the SO).
  • Write tests: Use uw-unity-test-runner — test event channels (subscribe, raise, verify callback) and runtime sets (add, remove, clear) in EditMode tests.
  • Custom inspectors: Use uw-unity-editor-tools for designer-friendly SO inspectors (preview panels, validation).
  • Graduate to DI: If the project outgrows SO events, use uw-dependency-injection — SO data stays, events become Commands.

When to Consider DI Instead

If your project needs any of these, check ProjectConfig.yaml -> architecture_pattern and consider switching to di-first with the uw-dependency-injection skill:

  • Cross-feature orchestration beyond simple events (Command pattern)
  • Constructor injection for testability with mock services
  • Scoped lifetimes (per-scene, per-level services)
  • Factory patterns with automatic dependency resolution

DI + SO coexist: In DI-first projects, ScriptableObjects still hold data — they're injected into the container as instances. Events are replaced by Commands.

Rules

  • Always use [CreateAssetMenu] on every ScriptableObject.
  • Always use [SerializeField] private + public read-only properties for data fields.
  • Use Action/Action delegates for events, not UnityEvents (better performance, no boxing).
  • Runtime sets must clear on OnDisable() to prevent stale references across play sessions.
  • Always unsubscribe from events in OnDisable — matching every Subscribe with an Unsubscribe.
  • All SO code must live inside an .asmdef.
  • SO file names use PascalCase (per NAMING_CONVENTIONS.md): SwordData.asset.
  • If ProjectConfig.yaml -> mcp.unity_mcp is true, call refresh_unity after creating files.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.