Stop Writing GetComponent Boilerplate in Every Single Script
When using dependency injection with Reflex, you've solved half the problem - your service dependencies get injected cleanly. But you're still stuck writing repetitive GetComponent boilerplate for hierarchy references in every. single. MonoBehaviour.
The Painful Reality:
- Dependencies β β Handled by Reflex (IHealthSystem, IAudioService, etc.)
- Hierarchy references β β Still manual hell (SpriteRenderer, Rigidbody2D, child colliders, etc.)
You're using a modern DI framework but still writing 2008-era Unity boilerplate. Unity Helpers fixes this.
The Solution: This integration automatically wires up relational component fields right after DI injection completes - giving you the best of both worlds with literally zero extra code per component.
Before (Manual):
public class Enemy : MonoBehaviour
{
[Inject] private IHealthSystem _healthSystem;
private Animator _animator;
private Rigidbody2D _rigidbody;
private Collider2D[] _childColliders;
void Awake()
{
_animator = GetComponent<Animator>();
_rigidbody = GetComponent<Rigidbody2D>();
_childColliders = GetComponentsInChildren<Collider2D>();
// 10+ more lines of GetComponent calls...
if (_animator == null) Debug.LogError("Missing Animator!");
if (_rigidbody == null) Debug.LogError("Missing Rigidbody2D!");
// More validation...
}
}After (With Integration):
public class Enemy : MonoBehaviour
{
[Inject] private IHealthSystem _healthSystem;
[SiblingComponent] private Animator _animator;
[SiblingComponent] private Rigidbody2D _rigidbody;
[ChildComponent] private Collider2D[] _childColliders;
// That's it! No Awake() needed - both DI and relational fields are auto-wired
// Automatic validation with helpful error messages included
}β±οΈ Time Saved: 10-20 lines of boilerplate per component Γ hundreds of components = weeks of development time. π§ Mental Load Eliminated: No more context-switching between DI patterns and Unity hierarchy patterns. π Bugs Prevented: Automatic validation catches missing references before they cause runtime errors.
- Add a
SceneScopeto your scene (Reflex component) - Add the
RelationalComponentsInstallercomponent to the same GameObject - Enable "Assign Scene On Initialize" to automatically wire all scene components after the container builds (recommended)
π‘ Beginner tip: Enable all checkboxes in the inspector:
- β Assign Scene On Initialize β Auto-wires all scene objects (saves you from calling it manually)
- β Include Inactive Objects β Scans disabled GameObjects too
- β Listen For Additive Scenes β Auto-wires newly loaded scenes (great for multi-scene setups)
- β Use Single Pass Scan β Faster scanning (always leave this on)
When spawning prefabs at runtime, use the helpers that combine instantiation, DI, and relational assignment:
using UnityEngine;
using Reflex.Core;
using Reflex.Extensions;
using WallstopStudios.UnityHelpers.Integrations.Reflex;
public sealed class EnemySpawner : MonoBehaviour
{
[SerializeField] private Enemy _enemyPrefab;
[SerializeField] private GameObject _enemySquadPrefab;
private Container _container;
private void Awake()
{
_container = gameObject.scene.GetSceneContainer();
}
public Enemy SpawnEnemy(Transform parent)
{
return _container.InstantiateComponentWithRelations(_enemyPrefab, parent);
}
public GameObject SpawnEnemySquad(Transform parent)
{
return _container.InstantiateGameObjectWithRelations(
_enemySquadPrefab,
parent,
includeInactiveChildren: true
);
}
public void HydrateExisting(GameObject root)
{
_container.InjectGameObjectWithRelations(root, includeInactiveChildren: true);
}
}That's it! Both DI injection and relational component wiring happen automatically.
This sample provides a complete working example:
- Scripts/ReflexSampleInstaller.cs - Registers a palette service to demonstrate DI working alongside relational attributes
- Scripts/ReflexRelationalConsumer.cs - Component demonstrating relational attributes working with Reflex injection
- Scripts/ReflexSpawner.cs - Demonstrates
InstantiateComponentWithRelations,InstantiateGameObjectWithRelations, and hierarchy hydration - Scripts/ReflexPaletteService.cs - Sample service showing DI pathway is active
- Prefabs/ - Example prefabs with relational fields
- Scenes/Reflex_Sample.unity - Complete working scene with SceneScope
- Open Unity Package Manager
- Find Unity Helpers in the package list
- Expand the Samples section
- Click Import next to "DI - Reflex"
- Open
Scenes/Reflex_Sample.unityand press Play
Perfect for: Player controllers, enemy AI, simple gameplay scripts
What you get: No more GetComponent calls, no more null reference exceptions from missing components
Example:
public class PlayerController : MonoBehaviour
{
// Injected dependencies
[Inject] private IInputService _input;
[Inject] private IAudioService _audio;
// Hierarchy references (auto-wired)
[SiblingComponent] private Animator _animator;
[SiblingComponent] private Rigidbody2D _rigidbody;
[ChildComponent(TagFilter = "Weapon")] private Weapon _weapon;
// Everything wired automatically when scene loads!
void Update()
{
Vector2 input = _input.GetMovementInput();
_rigidbody.velocity = input * moveSpeed;
_animator.SetFloat("Speed", input.magnitude);
}
}Important: Enable "Assign Scene On Initialize" in the RelationalComponentsInstaller for automatic scene wiring.
Perfect for: Enemy spawners, projectile systems, object pooling
What you get: One-line instantiation that handles DI injection + hierarchy wiring automatically
Example:
public sealed class ProjectileSpawner : MonoBehaviour
{
private Container _container;
[SerializeField] private Projectile _projectilePrefab;
private void Awake()
{
_container = gameObject.scene.GetSceneContainer();
}
public Projectile Fire(Vector3 position, Vector3 direction)
{
Projectile projectile = _container.InstantiateComponentWithRelations(_projectilePrefab);
projectile.transform.SetPositionAndRotation(position, Quaternion.LookRotation(direction));
projectile.Launch(direction);
return projectile;
}
}Perfect for: UI systems, vehicles with multiple parts, procedural generation
What you get: Full control over when and how wiring happens, with helpers for every scenario
Example - Complex Prefabs:
public sealed class VehicleFactory : MonoBehaviour
{
private Container _container;
[SerializeField] private GameObject _vehiclePrefab;
private void Awake()
{
_container = gameObject.scene.GetSceneContainer();
}
public GameObject CreateVehicle()
{
return _container.InstantiateGameObjectWithRelations(
_vehiclePrefab,
parent: null,
includeInactiveChildren: true
);
}
}Morning: You start work on a new enemy type.
public class FlyingEnemy : MonoBehaviour
{
[Inject] private IHealthSystem _health;
[Inject] private IAudioService _audio;
private Animator _animator;
private Rigidbody2D _rigidbody;
private SpriteRenderer _sprite;
private Collider2D[] _hitboxes;
private Transform _weaponMount;
void Awake()
{
_animator = GetComponent<Animator>();
if (_animator == null) Debug.LogError("Missing Animator on FlyingEnemy!");
_rigidbody = GetComponent<Rigidbody2D>();
if (_rigidbody == null) Debug.LogError("Missing Rigidbody2D on FlyingEnemy!");
_sprite = GetComponent<SpriteRenderer>();
if (_sprite == null) Debug.LogError("Missing SpriteRenderer on FlyingEnemy!");
_hitboxes = GetComponentsInChildren<Collider2D>();
if (_hitboxes.Length == 0) Debug.LogWarning("No hitboxes found on FlyingEnemy!");
_weaponMount = transform.Find("WeaponMount");
if (_weaponMount == null) Debug.LogError("Missing WeaponMount on FlyingEnemy!");
// Finally, actual game logic can start...
}
}10 minutes later: You've written 20+ lines of boilerplate before writing any actual game logic.
30 minutes later: Null reference exception in the build! You forgot to add the SpriteRenderer to the prefab.
60 minutes later: You're manually wiring up the 8th enemy variant of the day...
Morning: You start work on a new enemy type.
public class FlyingEnemy : MonoBehaviour
{
[Inject] private IHealthSystem _health;
[Inject] private IAudioService _audio;
[SiblingComponent] private Animator _animator;
[SiblingComponent] private Rigidbody2D _rigidbody;
[SiblingComponent] private SpriteRenderer _sprite;
[ChildComponent] private Collider2D[] _hitboxes;
[ChildComponent(NameFilter = "WeaponMount")] private Transform _weaponMount;
// Start writing game logic immediately
void Start() => _animator.Play("Idle");
}2 minutes later: You're done with wiring and writing game logic.
10 minutes later: You've shipped 5 enemy variants with zero boilerplate.
Never: You never see "Missing component" runtime errors because validation happens automatically with helpful messages.
The installer component provides these settings:
Assign Scene On Initialize (default: true)
- When enabled, automatically wires all scene components with relational attributes after the container builds
- Disable if you want to manually control when scene wiring happens
Include Inactive Objects (default: true)
- When enabled, scans inactive GameObjects and disabled components
- Disable to only wire active objects
Listen For Additive Scenes (default: false)
- When enabled, automatically wires components in additively loaded scenes
- Essential for multi-scene workflows
Use Single Pass Scan (default: true)
- Uses optimized metadata-driven scanning (faster)
- Leave enabled unless debugging scan issues
For dynamic hierarchies or pooled objects:
private Container _container;
void Awake()
{
_container = gameObject.scene.GetSceneContainer();
}
void SetupComplexHierarchy(GameObject root)
{
// Wire all components in hierarchy
_container.AssignRelationalHierarchy(root, includeInactiveChildren: false);
}For large projects, prewarm reflection caches during loading to avoid first-use stalls:
using WallstopStudios.UnityHelpers.Core.Attributes;
public class GameBootstrap : MonoBehaviour
{
void Awake()
{
// Call once during bootstrap/loading screen
RelationalComponentInitializer.Initialize();
}
}Or enable auto-prewarm on the AttributeMetadataCache asset:
- Create:
Assets > Create > Wallstop Studios > Unity Helpers > Attribute Metadata Cache - Enable "Prewarm Relational On Load" in the Inspector
// Inject + assign a single component
container.InjectWithRelations(component);
// Instantiate a component prefab + assign
var comp = container.InstantiateComponentWithRelations(prefabComp, parent);
// Inject + assign a whole hierarchy
container.InjectGameObjectWithRelations(root, includeInactiveChildren: true);
// Instantiate a GameObject prefab + inject + assign hierarchy
var go = container.InstantiateGameObjectWithRelations(prefabGo, parent);Enable "Listen For Additive Scenes" in the installer, or manually control scene assignment:
private Container _container;
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (mode == LoadSceneMode.Additive)
{
// Manually wire additive scene
_container.AssignRelationalScene(scene, includeInactive: true);
}
}Check these common issues:
-
Did you add the installer?
- Ensure
RelationalComponentsInstalleris on yourSceneScopeGameObject - Check that it's enabled in the Inspector
- Ensure
-
Scene components not wired?
- Enable "Assign Scene On Initialize" in the
RelationalComponentsInstaller - Or manually call
_container.AssignRelationalHierarchy(gameObject, includeInactiveChildren: true)at bootstrap time
- Enable "Assign Scene On Initialize" in the
-
Are you using the right attributes?
- Fields need
[SiblingComponent],[ParentComponent], or[ChildComponent]attributes - These are different from
[Inject]- you can use both on the same component
- Fields need
-
Runtime instantiation not working?
- Use
_container.InstantiateComponentWithRelations(...),_container.InstantiateGameObjectWithRelations(...), or_container.InjectGameObjectWithRelations(...) - Regular
Instantiate()won't trigger relational wiring without these helpers
- Use
-
Check your filters:
TagFiltermust match an existing Unity tag exactlyNameFilteris case-sensitive
No! The integration handles this automatically:
- Scene objects: Wired when you enable "Assign Scene On Initialize" (recommended)
- Runtime objects: Wired when you call any of the helper methods (
InstantiateComponentWithRelations,InstantiateGameObjectWithRelations, orInjectGameObjectWithRelations)
Only call AssignRelationalComponents() manually if you need fine-grained control.
Yes! The integration gracefully falls back to standard Unity Helpers behavior if Reflex isn't detected. You can:
- Adopt incrementally without breaking existing code
- Use in projects that mix DI and non-DI components
- Remove Reflex later without refactoring all your components
Minimal: Relational component assignment happens once per component at initialization time. After that, there's zero runtime overhead - the references are just regular fields.
Optimization tips:
- Use
MaxDepthto limit hierarchy traversal - Use
TagFilterorNameFilterto narrow searches - Use
OnlyDescendants/OnlyAncestorsto exclude self when appropriate
Unity Helpers Documentation:
- Relational Components Guide - Complete attribute reference and recipes
- Getting Started - Unity Helpers quick start guide
- Main README - Full feature overview
Reflex Documentation:
- Reflex GitHub - Official Reflex documentation and source code
Troubleshooting:
- Relational Components Troubleshooting - Detailed solutions
- DI Integration Testing Guide - Advanced scenarios
- Try the sample scene: Open
Reflex_Sample.unityand press Play - Read the scripts: See how
ReflexSpawnerandReflexRelationalConsumerwork - Add to your project: Add
RelationalComponentsInstallerto yourSceneScope - Explore attributes: Check out the Relational Components Guide for all options
If you're choosing between DI frameworks, here's how the integrations differ:
| Feature | Reflex | VContainer | Zenject |
|---|---|---|---|
| Setup | Add installer to SceneScope | Call in LifetimeScope.Configure() | Add installer to SceneContext |
| Scene wiring | Toggle on installer | Automatic | Toggle on installer |
| Runtime instantiation | InstantiateComponentWithRelations(), InstantiateGameObjectWithRelations() |
InstantiateComponentWithRelations(), InstantiateGameObjectWithRelations(), BuildUpWithRelations() |
InstantiateComponentWithRelations(), InstantiateGameObjectWithRelations() |
| Performance | Fast | Slightly faster | Good |
| Maintenance | Actively developed | Actively developed | Community-maintained |
All three integrations provide the same relational component features - choose based on your DI framework preference.
Unity Helpers is production-ready and actively maintained. Star the repo if you find it useful!