with one click
unity-scriptable-objects
Unity ScriptableObject Architecture
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Unity ScriptableObject Architecture
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Unity Shaders
Unity State Machines
Registers new C# files in resources/manifests/<system>.json (files array + tests.editmode/playmode list) and validates with just validate-registry. Use when creating any new script, adding a new game system, or fixing 'orphan file' CI failures. Trigger phrases: 'add to manifest', 'register file', 'new system', 'validate registry'. Key capabilities: exact JSON manifest format, ACTIVE/DEPRECATED/EXPERIMENTAL status, dependency declarations, test class name mapping for pre-push gating via resolve_module_tests.py. Do NOT use for modifying physics logic or editing game scripts unrelated to registration.
Unity Terrain & Track Creation for RC Racing
Unity Testing, Debugging & QA
Unity Testing Patterns
| name | unity-scriptable-objects |
| description | Unity ScriptableObject Architecture |
Use this skill when designing data-driven systems with ScriptableObjects for configuration assets, event channels, shared runtime state, or runtime sets.
| Pattern | Purpose | Example |
|---|---|---|
| Config Data | Read-only tuning values | Weapon stats, enemy definitions, level configs |
| Event Channels | Decoupled event bus | OnPlayerDied, OnScoreChanged, OnLevelComplete |
| Shared Variables | Runtime-writable state visible to multiple systems | Player health, score, current weapon |
| Runtime Sets | Track active objects without Find/singleton | Active enemies, active projectiles, spawn points |
| Enum Replacement | Extensible type system | Damage types, surface types, AI states |
// SO referencing other SOs -- works great
[CreateAssetMenu(menuName = "Game/Character Class")]
public class CharacterClass : ScriptableObject
{
public string ClassName;
public WeaponData StartingWeapon; // Reference to another SO -- fine
public List<AbilityData> Abilities; // List of SO references -- fine
}
// GOTCHA: Creating SOs at runtime
// SOs created via ScriptableObject.CreateInstance() are NOT saved to disk.
// They exist only in memory and are lost when play mode ends.
var tempConfig = ScriptableObject.CreateInstance<WeaponData>();
// This is fine for runtime-only data, but don't expect persistence.
// GOTCHA: Nested SOs as sub-assets
// If you create a SO and add it to another SO via AssetDatabase.AddObjectToAsset,
// it becomes a sub-asset. This is editor-only and requires careful management.
[CreateAssetMenu(menuName = "Game/Level Data")]
public class LevelData : ScriptableObject
{
[Header("Runtime Data")]
[SerializeField] private string _levelName;
[SerializeField] private int _sceneIndex;
[SerializeField] private int _requiredStars;
[Header("Editor-Only Metadata")]
#if UNITY_EDITOR
[TextArea(3, 10)]
[SerializeField] private string _designNotes;
[SerializeField] private bool _isPlaytested;
#endif
public string LevelName => _levelName;
public int SceneIndex => _sceneIndex;
public int RequiredStars => _requiredStars;
}
| Situation | Better Alternative | Reason |
|---|---|---|
| Per-instance mutable state | MonoBehaviour field | SOs are shared; mutating one affects all references |
| Large datasets (1000+ items) | JSON, SQLite, Addressables | Editor slows down with many SO assets |
| User-generated content | JSON/binary serialization | SOs require AssetDatabase (editor-only) |
| Save game data | JSON/binary file | SOs don't persist runtime changes to disk |
| Temporary runtime data | Plain C# class | No need for Unity serialization overhead |
| Configuration that changes per-build | Build scripts / defines | SOs are baked into builds |
// SOs are easy to create in tests -- no scene or GameObject needed
[Test]
public void WeaponDamage_WithArmorReduction_CalculatesCorrectly()
{
// Arrange
var fireDamage = ScriptableObject.CreateInstance<DamageType>();
var config = ScriptableObject.CreateInstance<WeaponData>();
// Set fields via reflection or make them public for tests
// Act & Assert
// ...
// Cleanup (prevent memory leak in tests)
Object.DestroyImmediate(fireDamage);
Object.DestroyImmediate(config);
}
OnEnable runs in editor -- SOs call OnEnable when loaded in the editor, not just in play mode. Guard runtime-only logic with if (Application.isPlaying).
Shared state persists in editor -- If an SO's runtime value is changed during play mode AND the field is serialized, the change persists after exiting play mode. Use [System.NonSerialized] for runtime-only state.
OnDisable/OnDestroy timing -- SOs are destroyed when no longer referenced or on domain reload. Don't assume they exist forever.
Addressables -- For large projects, load SOs via Addressables instead of direct references to reduce memory footprint and enable asset bundles.