Zenject / UniRx Integration
Docs / Adapter (Unity) / Zenject / UniRx
Optional integrations with Zenject (dependency injection) and UniRx (reactive programming).
Overview
ZenECS Unity Adapter supports optional integrations:
- Zenject: Dependency injection for systems and contexts
- UniRx: Reactive programming with observables
These are optional - ZenECS works without them.
Zenject Integration
Setup
- Install Zenject package
- Define
ZENECS_ZENJECT(auto-detected) - Configure in
ProjectInstaller
ProjectInstaller
#if ZENECS_ZENJECT
using Zenject;
using ZenECS.Adapter.Unity;
public class ProjectInstaller : MonoInstaller
{
public override void InstallBindings()
{
// Bind system preset resolver
Container.Bind<ISystemPresetResolver>()
.To<SystemPresetResolver>()
.AsSingle();
// Bind shared context resolver
Container.Bind<ISharedContextResolver>()
.To<SharedContextResolver>()
.AsSingle();
}
}
#endif
System Resolution
Systems can be resolved via DI:
#if ZENECS_ZENJECT
// Systems resolved via Zenject
var resolver = Container.Resolve<ISystemPresetResolver>();
var systems = resolver.InstantiateSystems(systemTypes);
world.AddSystems(systems);
#endif
Context Resolution
Contexts resolved via DI:
#if ZENECS_ZENJECT
// Shared contexts resolved via Zenject
var resolver = Container.Resolve<ISharedContextResolver>();
var context = resolver.Resolve(sharedContextAsset);
#endif
UniRx Integration
Setup
- Install UniRx package
- Define
ZENECS_UNIRX(auto-detected) - Use extension methods
Message Observables
Convert message streams to observables:
#if ZENECS_UNIRX
using UniRx;
using ZenECS.Adapter.Unity.UniRx;
// Observe messages as IObservable
world.ObserveMessages<DamageMessage>()
.Where(msg => msg.Amount > 10)
.Subscribe(msg => Debug.Log($"High damage: {msg.Amount}"));
#endif
Reactive Composition
Compose reactive pipelines:
#if ZENECS_UNIRX
// Combine multiple message streams
var damageStream = world.ObserveMessages<DamageMessage>();
var healStream = world.ObserveMessages<HealMessage>();
damageStream
.Merge(healStream)
.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(msg => UpdateHealthBar());
#endif
Combined Usage
Use both Zenject and UniRx together:
#if ZENECS_ZENJECT && ZENECS_UNIRX
using Zenject;
using UniRx;
using ZenECS.Adapter.Unity;
using ZenECS.Adapter.Unity.UniRx;
public class GameBootstrap : MonoBehaviour
{
[Inject] private ISystemPresetResolver _systemResolver;
private void Start()
{
var world = KernelLocator.CurrentWorld;
// Resolve systems via Zenject
var systems = _systemResolver.InstantiateSystems(systemTypes);
world.AddSystems(systems);
// Observe messages via UniRx
world.ObserveMessages<GameEventMessage>()
.Subscribe(msg => HandleEvent(msg));
}
}
#endif
Benefits
Zenject Benefits
- Dependency Injection: Testable, modular code
- System Resolution: Automatic system instantiation
- Context Management: Shared context resolution
- Lifetime Management: Automatic cleanup
UniRx Benefits
- Reactive Programming: Event-driven architecture
- Composition: LINQ operators for streams
- Throttling: Rate limiting and debouncing
- Combining: Merge, zip, combine streams
Best Practices
✅ Do
- Use Zenject for DI: When you need dependency injection
- Use UniRx for reactivity: When you need reactive streams
- Keep optional: Don't require these packages
- Test without: Ensure code works without integrations
❌ Don't
- Don't require packages: Make integrations optional
- Don't mix patterns: Choose appropriate pattern
- Don't overuse: Use when it adds value
See Also
- Unity Adapter Overview - Integration overview
- Message Bus - Message system
- Binding System - Context binding