The Death of the Update Loop: Inside UniState
How a web-inspired architecture uses asynchronous execution and dependency injection to rescue game developers from state machine spaghetti.

UniRx has made it easier to subscribe to and filter the state of variables, but strong references between classes remain a problem. To address this, I created a simple state management library, UniState, which is modeled after Zustand but adjusted for game development. UniState centers around the Store class, designed to manage
- UniState replaces the traditional frame-bound Update loop with a purely asynchronous lifecycle powered by UniTask.
- The framework solves the notoriously difficult problem of passing data between disconnected states using a type-safe payload injection pattern.
- By acting as an abstraction layer for dependency injection, UniState allows developers to use standard containers like VContainer or Zenject without tight coupling.
Escaping the Frame Rate
For years, Unity developers have been trapped in the rigid execution of MonoBehaviour.Update(). Building complex state machines meant wrestling with frame-by-frame polling, leading to spaghetti code and tight coupling. UniState abandons this paradigm entirely. It relies on a purely asynchronous lifecycle using UniTask.
Instead of ticking a state machine every frame, UniState allows states to wait for animations, network responses, or user input natively. This happens without blocking the main thread or relying on convoluted callback chains. Memory allocations are kept to an absolute minimum, which is critical for mobile game performance.
public async UniTask Execute(CancellationToken cancellationToken)
{
// Wait for an animation to finish natively
await _animator.PlayAsync("OpeningTransition", cancellationToken);
// Proceed with logic without a single Update() tick
_networkService.Connect();
}
Solving the Payload Problem
Most state machines fail when trying to pass data between isolated states. Moving a Level ID from a loading screen to a gameplay state usually requires global variables or messy singletons. UniState solves this elegantly through its IState implementation.
The system captures the payload during the transition request and injects it safely into the next state before execution. This guarantees type safety and eliminates the need for shared mutable state.
Importing Web Architecture to Games
The architectural shift in UniState did not come from a vacuum. The creator, known as bazyleu, transitioned from game client development to backend APIs and web infrastructure. This exposure highlighted the flaws of strong class references often found in reactive Unity frameworks.
The Unix Philosophy of Dependency Injection
UniState does not force a proprietary dependency injection container on the developer. It acts as a bridge. By utilizing an ITypeResolver interface, the framework integrates seamlessly with standard Unity DI solutions like VContainer and Zenject.
| Feature | Traditional MonoBehaviour | UniState Architecture |
|---|---|---|
| Execution | Frame-bound Update() tick | Purely asynchronous UniTask |
| Data Passing | Global singletons or tight coupling | Type-safe Payload injection |
| Memory Profile | High allocation on state swaps | Zero-allocation transitions |
| Dependencies | Hardcoded GetComponent() | Injected via ITypeResolver |
This modularity means two developers can work on separate states in total isolation. The shipping container of logic remains unchanged, regardless of which crane picks it up.