• Games
  • Industry
  • Resources
  • Community
  • Learning
  • Support
Development
Unity Engine
Build 2D and 3D games for any platform
DownloadPlans and pricing
Monetization
In-App Purchase (IAP)
Discover and manage IAP across stores
Mediation
Maximize revenue and optimize monetization
Ad Quality
Protect your app’s user experience
Tapjoy
Build long-term user loyalty
All monetization products
User acquisition
User acquisition
Get discovered and acquire mobile users
Unity Vector AI
Connect players with the right games
Aura on-device advertising
Reach users on-device at peak engagement
All growth products
Use cases
3D collaboration
Build and review 3D projects in real time
Immersive training
Train in immersive environments
Customer experiences
Create interactive 3D experiences
All industry solutions
Industries
Manufacturing
Achieve operational excellence
Retail
Transform in-store experiences into online ones
Automotive
Elevate innovation and in-car experiences
All industries
Technical library
Documentation
Official user manuals and API references
Developer tools
Release versions and issue tracker
Roadmap
Review upcoming features
Glossary
Library of technical terms
Insights
Case studies
Real-world success stories
Best practice guides
Expert tips and tricks
All resources
What's new
Blog
Updates, information, and technical tips
News
News, stories, and press center
Community Hub
Discussions
Discuss, problem-solve, and connect
Events
Global and local events
Community stories
Made with Unity
Showcasing Unity creators
Livestreams
Join devs, creators, and insiders
Unity Awards
Celebrating Unity creators worldwide
For every level
Unity Learn
Master Unity skills for free
Professional training
Level up your team with Unity trainers
New to Unity
Getting started
Kickstart your learning
Unity Essential Pathways
New to Unity? Start your journey
How-to Guides
Actionable tips and best practices
Education
For students
Kickstart your career
For educators
Supercharge your teaching
Education Grant License
Bring Unity’s power to your institution
Certifications
Prove your Unity mastery
Support options
Get help
Helping you succeed with Unity
Success plans
Reach your goals faster with expert support
FAQ
Answers to common questions
Contact us
Connect with our team
Plans and pricing
Language
  • English
  • Deutsch
  • 日本語
  • Français
  • Português
  • 中文
  • Español
  • Русский
  • 한국어
Social
Currency
Purchase
  • Products
  • Unity Ads
  • Subscription
  • Unity Asset Store
  • Resellers
Education
  • Students
  • Educators
  • Institutions
  • Certification
  • Learn
  • Skills Development Program
Download
  • Unity Hub
  • Download Archive
  • Beta Program
Unity Labs
  • Labs
  • Publications
Resources
  • Learn platform
  • Community
  • Documentation
  • Unity QA
  • FAQ
  • Services Status
  • Case Studies
  • Made with Unity
Unity
  • Our Company
  • Newsletter
  • Blog
  • Events
  • Careers
  • Help
  • Press
  • Partners
  • Investors
  • Affiliates
  • Security
  • Social Impact
  • Inclusion & Diversity
  • Contact us
Copyright © 2025 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell or Share My Personal Information

"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.

Hero background image

How to use a ScriptableObject-based runtime set

  • Important note before you start
  • Runtime sets
  • Basic implementation
  • Generic version
  • Usage and limitations
  • Patterns demo
  • How runtime sets help
  • More ScriptableObject resources

Important note before you start

Before you dive into the ScriptableObject demo project and this series of mini-guides, remember that, at their core, design patterns are just ideas. They won’t apply to every situation. These techniques can help you learn new ways to work with Unity and ScriptableObjects.

Each pattern has pros and cons. Choose only the ones that meaningfully benefit your specific project. Do your designers rely heavily on the Unity Editor? A ScriptableObject-based pattern could be a good choice to help them collaborate with your developers.

Ultimately, the best code architecture is the one that fits your project and team.

Runtime sets

ScriptableObjects can store static data. They can be modified to hold dynamic data as well. This is particularly useful for referencing a collection of GameObjects or components at runtime.

A “runtime set” like this replicates why some developers use singletons – easy global access. Unfortunately, singletons come with baggage like undesirable dependencies. These extra dependencies can complicate testing and make debugging more difficult.

As an alternative, consider using a ScriptableObject-based runtime set for frequently referenced components. For example, use them to track game elements like spawned enemies, collectibles, or checkpoints.

As project-level assets, ScriptableObjects provide global access to data for all objects within a scene. This feature allows for information sharing without many of the drawbacks associated with singletons.

Download PaddleBallSO

Basic implementation

Here’s one way to make a runtime set for GameObjects. Think of it like a data container that keeps a public collection of elements – but also includes methods to add and remove members.

At runtime, any MonoBehaviour can reference the public Items property to obtain the full list of GameObjects. Another script or component can call Add or Remove to modify the Items list.

Generic version

You can make a runtime set more specific so that it only tracks a particular type of MonoBehaviour. In that case, create specific sets for each type (e.g., EnemyRuntimeSet, PickupRuntimeSet, etc.).

A generic abstract class can streamline this process. You could then derive other runtime sets from this base class. For example, if you wanted to make a runtime set for a custom Enemy component, you could define classes for a generic RuntimeSetSO<T> and concrete EnemyRuntimeSetSO like the code snippet below.

Notice that the concrete class, EnemyRuntimeSetSO, doesn’t have any implementation details, only a CreateAssetMenu attribute.

Each new component you want to track just needs a corresponding runtime set to manage it. Build as many concrete classes as you need. Enemies, NPCs, inventory items, quests, and more can all have their own runtime sets.

Download PaddleBallSO
Mismatch error

Usage and limitations

Managing the runtime set is up to you. Often, you can use a second MonoBehaviour to set up or update it during gameplay.

If you want a component to include itself in a set automatically, you can also invoke the runtime set’s Add or Remove methods from the MonoBehaviour’s OnEnable and OnDisable.

For example, your fictitious Enemy class might look like the code snippet below.

Here, each Enemy component can add or remove itself using its OnEnable or OnDisable methods. If the m_RuntimeSet field is set in the Inspector, the Enemy component will appear in the EnemyRuntimeSetSO automatically. This is especially handy if you’re using the Enemy component with Prefabs.

One limitation of this technique is that if you inspect the ScriptableObject at runtime, you won’t be able to see the contents of the Items list in the Inspector by default.

Instead, a “Type mismatch” appears in each element field. By design, a ScriptableObject can’t serialize a scene object. The list is actually working, but the data does not display correctly.

Use a public property or the HideInInspector attribute if you want to avoid confusion and prevent the list from showing in the Inspector.

You can also fix this issue with a custom Editor script and Inspector. Good examples include Soap – ScriptableObject Architecture Pattern in the Unity Asset Store or the Patterns demo example below.

Runtime sets

Patterns demo

Although PaddleBallSO doesn’t feature a use case for runtime sets, the project’s Patterns demo includes a small sample that shows this design pattern at work.

Click the Spawn Block button to fill in the wall of blocks incrementally. The ball destroys a block on contact.

Choose Select Set to show the BlockRuntimeSet_Data in the Inspector. This contains the list of all the blocks in the scene.

You can continuously fill blocks into the grid as quickly as the ball removes them. At the same time, the runtime set tracks the actively changing number of blocks in the Items list.

The Patterns demo shows a few quality-of-life enhancements when working with runtime sets:

  • Custom Inspector: Since ScriptableObjects cannot serialize scene objects out of the box, the GameObjectRuntimeSetEditor script provides a custom Inspector that overrides the default type mismatch error. Click any block in the Inspector to highlight it in the scene Hierarchy.
  • Update events: The runtime set has a System.Action called ItemsChanged. This notifies the Editor script when adding or removing members from the Items list. This refreshes the Inspector when the Items list changes. An event channel also syncs the current number of Items to a custom RuntimeSetCounter component. This shows the total block count in the onscreen UI.
Download PaddleBallSO
Custom inspector

How runtime sets help

The next time you need a centralized list of GameObjects or components, consider runtime sets. They can be less expensive than a find operation (Object.FindObjectOfType or GameObject.FindWithTag) and less problematic than singletons.

As ScriptableObjects, they are decoupled from individual GameObjects in the scene. Keep as many runtime sets as needed for anything you want to track frequently at runtime.

Runtime sets can simplify how you monitor gameplay objects without incurring unnecessary dependencies. You can spend the time saved during debugging and testing to develop new gameplay experiences for your players.

scriptable outro

More ScriptableObject resources

We hope that runtime sets can benefit your upcoming projects.

Read more about design patterns with ScriptableObjects in our technical e-book, Create modular game architecture in Unity with ScriptableObjects. You can also find out more about common Unity development design patterns in Level up your code with game programming patterns.