2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】VContainerの依存性注入とは何か

Posted at

はじめに

Unity用のDIコンテナであるVContainerの依存性注入とは何かをおさらいしました。

DI = Dependency Injection = 依存性注入、とは言われても「何をどう注入するの?」
という疑問が湧きますよね。
この記事では「カレー定食クラス群」を例に、依存関係の仕組みを考えたいと思います。


依存性の注入(Dependency Injection)とは?

「依存性を注入する」という言葉ではピンと来ないことも多いです。
例えば「クラスAがクラスBを使うにはどうやって“B”を渡すか?」という構造を抜きにしてしまうと、実装が見えづらくなります。
そこで、以下の “カレー定食クラス群(依存関係あり)” を見てみましょう。

// ご飯を作るのに炊飯器が必要
public class ご飯 {
    public ご飯(炊飯器 riceCooker) {
        UnityEngine.Debug.Log("ご飯が炊けました!");
    }
}

// 炊飯器を作るのに米と水が必要
public class 炊飯器 {
    public 炊飯器( rice,  water) {
        UnityEngine.Debug.Log("炊飯器に米と水を入れました!");
    }
}
public class  {
    public () {
        UnityEngine.Debug.Log("米を準備しました!");
    }
}
public class  {
    public () {
        UnityEngine.Debug.Log("水を準備しました!");
    }
}

// カレーを作るのに鍋が必要
public class カレ {
    public カレ( pot) {
        UnityEngine.Debug.Log("カレーができました!");
    }
}

// 鍋を作るのに肉・野菜・ルーが必要
public class  {
    public ( meat, 野菜 veg,  roux) {
        UnityEngine.Debug.Log("鍋に材料を入れました!");
    }
}
public class  {
    public () {
        UnityEngine.Debug.Log("肉を切りました!");
    }
}
public class 野菜 {
    public 野菜() {
        UnityEngine.Debug.Log("野菜を切りました!");
    }
}
public class  {
    public () {
        UnityEngine.Debug.Log("ルーを準備しました!");
    }
}

// 最後にカレー定食を作るのに ご飯 と カレー が必要
public class カレ定食 {
    public カレ定食(ご飯 gohan, カレ curry) {
        UnityEngine.Debug.Log("カレー定食が完成しました!");
    }
}

このように、クラスがそれぞれ“何かを必要として”構築されています。
この「必要としている」部分を丁寧に管理するのが DI です。


VContainerで組み立てる

続いて、VContainerを使った登録・解決の仕組みを見ていきましょう。

using VContainer;
using VContainer.Unity;

public class CurryLifetimeScope : LifetimeScope {
    protected override void Configure(IContainerBuilder builder) {
        // 材料と調理器具を登録
        builder.Register<>(Lifetime.Singleton);
        builder.Register<>(Lifetime.Singleton);
        builder.Register<炊飯器>(Lifetime.Singleton);
        builder.Register<ご飯>(Lifetime.Transient);
        builder.Register<>(Lifetime.Transient);
        builder.Register<野菜>(Lifetime.Transient);
        builder.Register<>(Lifetime.Singleton);
        builder.Register<>(Lifetime.Transient);
        builder.Register<カレ>(Lifetime.Transient);

        // 最後にカレー定食を登録
        builder.Register<カレ定食>(Lifetime.Transient);
    }
}
public class CurryTester : MonoBehaviour {
    [Inject]
    public void Construct(カレ定食 set) {
        UnityEngine.Debug.Log("お客さんにカレー定食を提供しました!");
    }
}

実行ログ(想定)

米を準備しました!
水を準備しました!
炊飯器に米と水を入れました!
ご飯が炊けました!
肉を切りました!
野菜を切りました!
ルーを準備しました!
鍋に材料を入れました!
カレーができました!
カレー定食が完成しました!
お客さんにカレー定食を提供しました!

何が便利か?

  • new を手書きでたくさん書かず、VContainerに任せられる
  • 依存関係を「どのクラスが何を必要としているか」という形で明示できる
  • テストや環境切り替え、ライフタイム管理などがしやすくなる
var 定食 = new カレ定食(
    new ご飯(new 炊飯器(new (), new ())),
    new カレ(new (new (), new 野菜(), new ()))
);

上記のような構築の手間を、VContainerが代行してくれます。


Playmakerで使う

Playmakerと組み合わせて使うケースを検証します。

VContainerがやること(材料の準備)

builder.Register<>(Lifetime.Singleton);
builder.Register<カレ定食>(Lifetime.Transient);

Playmakerがやること(振る舞い・状態管理)

FSM(状態マシン)で「注文 -> 提供 -> 会計」などの流れを管理します。

using HutongGames.Playmaker;
using VContainer;

public class OrderCurry : FsmStateAction {
    public override void OnEnter() {
        var currySet = ProjectContext.Instance.Container.Resolve<カレ定食>();
        UnityEngine.Debug.Log("Playmaker: カレー定食を受け取りました!");
        Finish();
    }
}

このように、

  • Playmaker = 店長/状態管理
  • VContainer = 厨房/依存性解決

という役割分担をイメージできます。


まとめ

  • VContainer =「材料と料理を用意する工場(依存性解決)」
  • “カレー定食をちょうだい”と言うと、自動で米・水・炊飯器…全部組み立てて提供してくれる
  • Playmaker =「お客さん来たら→注文→提供→次」みたいな流れを管理する店長
  • DI を使うと、直接 new をたくさん書く設計と比べて、テスト性・再利用性・複雑系管理のしやすさが向上する

実際のプロジェクトで依存関係が増えてくると、より自然に理解が深まります。


おわりに

ゲームの設計が複数のクラスやモジュールにまたがり始めると、

  • 誰が誰を使っているのか
  • 新しい処理をどこに追加するか
  • いつ生成していつ破棄するか(ライフタイム管理)

といった課題が一気に増えていきます。

カレーの例:

「カレー定食ちょうだい」
-> 米・水・炊飯器・鍋・肉・野菜・ルーが全部そろった状態で出てくる。

ゲームだと:

「敵ちょうだい」
-> HP、AI、アニメ、ステータス、ドロップロジックがセットになった敵が出てくる。

「バトル画面ちょうだい」
-> UI、BGM、キャラ情報、計算ロジック、敵データが全部まとまって生成される。

「セーブデータちょうだい」
-> SaveSystem、JSON処理、暗号化、保存場所などが一式そろった状態で渡ってくる。

そんなときに VContainerが依存関係を整理し、ゲーム全体の構造をスッキリ整えてくれるので、規模が大きくなるほど “導入してよかった” と実感できるはずです。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?