This article explores ReactiveEntitySet, a feature coming in v2.1.0 of Reactive SO — a ScriptableObject-based reactive architecture for Unity.
Unity Asset StoreReactive SO | Game ToolkitsScriptableObject-based reactive architecture for Unity. Variables, Event Channels, Runtime Sets, GPU Sync, Reactive Entity Sets, and dedicated debugging windows.When I first explained ReactiveEntitySet to other developers, most of them responded with:
“Oh, so it’s like VariableSO but as an array?”
This is a fundamental misunderstanding. The surface-level similarities — ScriptableObject-based, state management, event firing — obscure what’s actually a paradigm shift in how we think about game state.
The Instancer Approach — “Ownership”
Unity Atoms’ Instancer creates runtime copies of a base VariableSO, giving each instance its own independent state.
This is the ownership paradigm. Each object “owns” its state. It’s a natural extension of OOP thinking — objects encapsulate data and behavior.
The Payroll Analogy
Imagine each employee carrying their own payroll slip.
- Want to see everyone’s salary? You have to ask each person individually.
- Want to process salaries in bulk? You need to collect all the data and convert it into an array first.
The ReactiveEntitySet Approach — “Belonging”
ReactiveEntitySet manages data centrally. Each instance accesses its state via an ID.
This is the belonging paradigm. Entities “register” with a set. State “exists” in the set, not in the object.
The Accounting Department Analogy
The accounting department manages all employee salary data centrally.
- Want to see everyone’s salary? Just look at the accounting spreadsheet.
- Want to process in bulk? Hand over the spreadsheet as-is.
- Each employee accesses their data via their employee ID.
The Correct Lineage
ReactiveEntitySet is not an extension of VariableSO. It’s an extension of RuntimeSet.
RuntimeSet manages “who exists.” ReactiveEntitySet manages “who exists + what they have.” This is a continuous evolution.
The jump from VariableSO to ReactiveEntitySet is a discontinuity. The paradigm is different.
Physical Memory Layout Matters
This isn’t just an abstract conceptual difference. It’s a physical memory layout difference.
This physical arrangement determines everything.
Optimizations Enabled by Central Aggregation
The paradigm shift from “ownership” to “belonging” enables optimizations that are simply impossible with Instancer:
| Optimization | Instancer | RES | Why |
|---|---|---|---|
| Pagination | No | Yes | Requires central ID→Index management |
| Slice-based detection | No | Yes | Can’t slice without contiguous array |
| Double buffering | No | Yes | Buffer concept doesn’t exist |
| Backward iteration | No | Yes | No central array to iterate |
Try implementing any of these with Instancer. You can’t.
Slice-based Change Detection
Using bitmasks to detect changes in 64-entity slices. Without a contiguous array, the concept of “slice” doesn’t exist.
The Core Question
“Why does each object need to own its own state?”
OOP’s answer:
“Because objects encapsulate data and behavior.”
ReactiveEntitySet’s counter:
“Data is more efficient when managed centrally. Objects only need behavior. State is not an object’s ‘property’ — it’s an ‘entry’ in a set.”
Relationship with ECS
ReactiveEntitySet is a hybrid that selectively adopts ECS concepts.
| ECS Principle | RES | Notes |
|---|---|---|
| Entity | Yes | MonoBehaviour.GetInstanceID |
| Component | Yes | TData struct |
| System | Partial | No explicit System class |
| Data-oriented | Yes | Contiguous array |
But there’s a crucial difference:
- ECS: Full scan every frame (Query)
- RES: Notify only on change (Reactive)
Where ECS forces “all or nothing,” RES lets you get data-oriented benefits while keeping your GameObject workflow.
A Note on Performance
When updates are infrequent — which is common for things like UI state, damage events, or AI decisions — the Reactive approach can be efficient since it only processes entities that actually changed.
The combination of contiguous memory layout and change-based processing seems to work well for these scenarios, though your mileage may vary depending on the specific use case.
Wrap-up
You don’t have to choose between “abandon everything for data-oriented” or “stay with OOP.” ReactiveEntitySet offers a gradual adoption path while keeping your GameObject workflow.
The technical decisions behind this design — why Sparse Set storage, what the reactive change detection borrows from existing ECS frameworks — are covered in the companion post below.