본문으로 건너뛰기
cccskills
무료GitHub에 공개

uw-dependency-injection

Opt-in DI architecture using Reflex for Unity 6+. Covers container setup, scoping, injection, command pattern, update management, and class taxonomy. Use when ProjectConfig.yaml -> architecture_pattern is "di-first", or when the user asks about dependency injection, inversion of control, service architecture, or testable game code. Triggers on "set up DI", "add dependency injection", "create a service", "wire up dependencies", "make this testable", "decouple these systems", "add a command pattern", "cross-feature communication", or architecture discussions involving testability, decoupling, and service layers. Only activates when ProjectConfig.yaml -> architecture_pattern is "di-first". For simpler projects, use uw-scriptable-object-arch instead.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구Unity
설치 방법 보기

포함된 파일(2)

  • SKILL.md9.2 KB
  • references/class-taxonomy-and-commands.md3.0 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Dependency Injection (Reflex)

DI-first architecture for complex Unity projects. Only applies when ProjectConfig.yaml -> architecture_pattern: di-first. For simpler projects, use uw-scriptable-object-arch (SO-first) instead.

Before You Start

  1. Read docs/ProjectConfig.yaml for:
    • architecture_pattern — must be "di-first" for this skill to apply.
    • di_framework — should be "reflex" (the default and recommended framework).
    • mcp.unity_mcp — if true, call refresh_unity after creating files.
  2. Read docs/CODING_STANDARDS.md for async patterns (Awaitable + CancellationToken), access modifiers (internal for cross-class helpers within an asmdef), and class structure.
  3. Read docs/NAMING_CONVENTIONS.md for file/class naming.
  4. Ensure each feature module has its own .asmdef — create with uw-unity-feature-scaffold. Installers, Controllers, Services all live inside feature asmdefs.

When to Use DI vs SO-First

SO-First (default)DI-First
Small/medium scopeLarge/complex scope
Solo or small teamTeam with testing culture
Rapid prototypingProduction architecture
Simple event-driven communicationCross-feature orchestration via Commands
ScriptableObject event channelsInterface-based injection + factories

Both can coexist: DI containers can bind ScriptableObject data assets as singletons.

Reflex Setup

Install (OpenUPM): openupm install com.gustavopsantos.reflex Or UPM Git URL: https://github.com/gustavopsantos/reflex.git?path=/Assets/Reflex/

Container Hierarchy

RootScope (app lifetime — singletons, core services)
  +-- SceneScope (scene lifetime — per-scene services, controllers)
        +-- Manual child scopes (gameplay round, level, etc.)

Installer Pattern

Each feature module has one Installer that registers its bindings. The Installer lives inside the feature's .asmdef.

using Reflex.Core;
using UnityEngine;

namespace {RootNamespace}.Core
{
    public class CoreInstaller : MonoBehaviour, IInstaller
    {
        [SerializeField] private AudioSettingsData _audioSettings;

        public void InstallBindings(ContainerBuilder builder)
        {
            // Services (singleton, app lifetime)
            builder.AddSingleton(typeof(IAudioService), typeof(AudioService));
            builder.AddSingleton(typeof(IStateMachineService), typeof(StateMachineService));

            // SO data (inject existing asset as value)
            builder.AddInstance(_audioSettings);
        }
    }
}

Binding Types

MethodWhat It DoesLifetime
AddSingleton(type, impl)Container creates one instanceApp/Scene
AddTransient(type, impl)New instance each resolvePer-resolve
AddInstance(obj)Register existing object (SO, config)Singleton

Injection

using Reflex.Attributes;

namespace {RootNamespace}.Combat
{
    public class ArrowController
    {
        [Inject] private readonly IAudioService _audio;
        [Inject] private readonly IArrowMovementController _movement;

        // OR constructor injection (preferred for non-MonoBehaviours):
        public ArrowController(IAudioService audio, IArrowMovementController movement)
        {
            _audio = audio;
            _movement = movement;
        }
    }
}

Constructor injection is preferred for plain C# classes — it makes dependencies explicit and prevents forgetting to inject. Use [Inject] attribute injection for MonoBehaviours (which Unity constructs).

Interface-First Rule

Always bind to interfaces, not concrete types. This enables mock injection for testing, makes dependencies explicit, and follows the Dependency Inversion Principle.

// Correct — bind to interface
builder.AddSingleton(typeof(IAudioService), typeof(AudioService));

// Wrong — binding concrete directly prevents mock injection
builder.AddSingleton(typeof(AudioService));

Circular Dependency Prevention

Circular dependencies (A depends on B, B depends on A) cause infinite resolution loops. Prevent them with:

  1. Commands — if two features need to communicate, use a Command that resolves its deps at execution time instead of at construction time.
  2. Events / ScriptableObject channels — decouple with uw-scriptable-object-arch event channels.
  3. Interfaces in a shared assembly — extract the interface into {RootNamespace}.Core.asmdef so both features depend on the interface, not on each other.

If the container throws a circular dependency error, trace the dependency chain and break it at the point where a Command or event channel makes more sense than a direct reference.

App Lifecycle / Single Entry Point (SEP)

Only one scene has a Start() method. All other initialization flows from there.

CoreScene loads -> RootScope binds -> CoreInitiator.Start()
  -> Load GameScene (additively) -> SceneScope binds -> GameInitiator.Init()
    -> Load GamePlayScene -> SceneScope binds -> GamePlayInitiator.Init()

Rules:

  • CoreScene is always the first scene (set in Build Settings index 0, or via editor DefaultSceneSelector).
  • Each scene has one Installer (bindings) and one Initiator (entry/exit points).
  • Only CoreInitiator has a Start() method — everything else is initialized via async InitEntryPoint().

Class Taxonomy, Commands & Update Management

See references/class-taxonomy-and-commands.md for the full 9-class taxonomy, Command pattern, and centralized Update management.

Key rule: Commands are the ONLY classes allowed to cross feature boundaries. This prevents circular dependencies — each Command resolves its own references from the DI container at execution time.

Cross-Feature Command Example

When Feature A (Combat) needs to notify Feature B (Score) about a hit:

// Lives in a shared Commands assembly or in the feature that initiates it
public class OnHitScoredCommand : ICommand
{
    [Inject] private readonly IScoreController _score;
    [Inject] private readonly IAudioService _audio;

    public void Execute()
    {
        _score.AddPoints(10);
        _audio.PlayOneShot(AudioClipType.Hit);
    }
}

The Combat feature doesn't reference Score directly — it resolves and executes the Command, which the container wires up. Register in the installer: builder.AddTransient(typeof(OnHitScoredCommand));

Integration with ScriptableObject Data

DI and SO work together — SO holds data, DI manages services and wiring:

// In installer: inject SO data asset into container
[SerializeField] private WeaponDatabase _weaponDatabase;

public void InstallBindings(ContainerBuilder builder)
{
    builder.AddInstance(_weaponDatabase); // SO data available via [Inject]
}

See uw-scriptable-object-arch for data container and event channel patterns that complement DI.

After Setup

  • Scaffold features: Use uw-unity-feature-scaffold to create feature modules with their own .asmdef — each feature gets its own Installer.
  • State management: Use uw-state-machine for game flow states, with states receiving dependencies via constructor injection.
  • Write tests: Use uw-unity-test-runner — interface-based DI makes testing easy: construct classes with mock dependencies, no container needed in tests.
  • SO data: Use uw-scriptable-object-arch for game data assets that get injected into services via AddInstance.

Rules

  • Only applies when ProjectConfig.yaml -> architecture_pattern: di-first.
  • Always bind to interfaces, not concrete types (interface-first rule).
  • Constructor injection preferred for plain C# classes. [Inject] attribute for MonoBehaviours.
  • Commands are the ONLY classes allowed to cross feature boundaries.
  • Each feature module needs its own .asmdef (per NAMING_CONVENTIONS.md). Installers live inside the feature's asmdef.
  • [SerializeField] private for Inspector-exposed fields on Installers and MonoBehaviours — never public fields.
  • Use Awaitable with CancellationToken for async operations (per CODING_STANDARDS.md).
  • CoreScene is Build Settings index 0. Only CoreInitiator has Start().
  • Break circular dependencies with Commands, events, or shared interface assemblies — never with direct cross-feature references.
  • If ProjectConfig.yaml -> mcp.unity_mcp is true, call refresh_unity after creating files.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

adopt

무료

Brownfield onboarding — audits existing project artifacts for template format compliance (not just existence), classifies gaps by impact, and produces a numbered migration plan. Run this when joining an in-progress project or upgrading from an older template version. Distinct from /project-stage-detect (which checks what exists) — this checks whether what exists will actually work with the template's skills.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

IdoCohen560/claude-unity-game-studio222026년 7월 8일 업데이트

Creates an Architecture Decision Record (ADR) documenting a significant technical decision, its context, alternatives considered, and consequences. Every major technical choice should have an ADR.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

IdoCohen560/claude-unity-game-studio222026년 7월 8일 업데이트

Validates completeness and consistency of the project architecture against all GDDs. Builds a traceability matrix mapping every GDD technical requirement to ADRs, identifies coverage gaps, detects cross-ADR conflicts, verifies engine compatibility consistency across all decisions, and produces a PASS/CONCERNS/FAIL verdict. The architecture equivalent of /design-review.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

IdoCohen560/claude-unity-game-studio222026년 7월 8일 업데이트

art-bible

무료

Guided, section-by-section Art Bible authoring. Creates the visual identity specification that gates all asset production. Run after /brainstorm is approved and before /map-systems or any GDD authoring begins.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

IdoCohen560/claude-unity-game-studio222026년 7월 8일 업데이트

Audits game assets for compliance with naming conventions, file size budgets, format standards, and pipeline requirements. Identifies orphaned assets, missing references, and standard violations.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

IdoCohen560/claude-unity-game-studio222026년 7월 8일 업데이트

Generate per-asset visual specifications and AI generation prompts from GDDs, level docs, or character profiles. Produces structured spec files and updates the master asset manifest. Run after art bible and GDD/level design are approved, before production begins.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

IdoCohen560/claude-unity-game-studio222026년 7월 8일 업데이트

IdoCohen560의 스킬 모두 보기

이 스킬의 문제 신고