【Unity】VContainerをざっくりと使ってみた

# はじめに
この記事は[Hamster Output Advent Calendar 2024](https://qiita.com/advent-calendar/2024/game_hamster)の4日目の記事です！

ここ最近、ゲーム開発でサービスロケーターを利用して1つの悩みがありました。
それは「インスタンスの登録や解除を毎回手動で行うのが面倒だ」という悩みでした。

そんな時、VContainerを利用している記事を見つけ、もしかしたらサービスロケーターの悩みを解決できるかも知れないと思い、使ってみた...というのが本記事の内容です。

# 参考にしたリンク

https://vcontainer.hadashikick.jp/ja/

https://zenn.dev/qemel/articles/14d247b9945527

# ダウンロードしたらエラーに遭遇した

公式サイトのmanifest.jsonにリンクを追加してダウロードを行いましたが、プロジェクトを起動したらエラーに遭遇しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/e06662f9-0219-717a-5937-42e8decd437d.png)

:::note alert 
遭遇したエラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/f189354b-868d-ad06-308b-4fd07eadcbdd.png)
:::


調べたところ、パソコンの環境変数のPathにgit.exeのパスを設定すると解決するエラーらしいです。下の記事を参考にしてエラーを直しました。

https://baba-s.hatenablog.com/entry/2020/02/26/163000

# とりあえず使ってみる
VContainerを利用するにはLifetimeSpopeを継承したクラスが必要みたいなので、クラスを作成します。

```C#
using VContainer;
using VContainer.Unity;

public class TestLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {

    }
}
```

作成したTestLifetimeScopeを適当なGameObjectにアタッチします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/4bb8f710-4e2b-306e-1cff-78764d566ae7.png)

GameObjectにアタッチできるんだ...と思いクラスを覗いたらMonoBehaviourを継承していることが分かりました。後の処理は...良く分からないので飛ばします😓
```C#
public partial class LifetimeScope : MonoBehaviour, IDisposable
```

次にLifetimeScopeに登録するクラスを作ります。Testクラスはシーン上の適当なGameObjectにアタッチします。
```C#
using UnityEngine;

public class TestMonoBehaviour : MonoBehaviour
{
    private TestPureCSharp _testPureCSharp;

    private void Start()
    {
        _testPureCSharp.TestLog();
    }
}

public class TestPureCSharp
{
    public void TestLog()
    {
        Debug.Log("TestPureCSharp");
    }
}
```

作成したクラスをLifetimeScopeに登録します。ピュアC#とMonoBehaviourのクラスでは登録方法が少し違いますが、ひとまずそのまま進めていきます。引き数のLifetimeについては後ほど触れます。
```C#
using VContainer;
using VContainer.Unity;

public class TestLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<TestPureCSharp>(Lifetime.Singleton);
        builder.RegisterComponentInHierarchy<TestMonoBehaviour>();
    }
}
```

現状、TestMonoBehaviourクラスでTestPureCSharpのインスタンスを作成していないので、実行するとエラーが出ます。ここで、VContainerの登場です。

まず、TestMonoBehaviourクラスの_testPureCSharp変数に**Inject属性**をつけます。
```C#
using UnityEngine;
using VContainer;

public class TestMonoBehaviour : MonoBehaviour
{
    // Injectをここに追加する
    [Inject]
    private TestPureCSharp _testPureCSharp;

    private void Start()
    {
        _testPureCSharp.TestLog();
    }
}
```

LifetimeScopeがアタッチされているGameObjectのインスペクターには**Auto Inject Game Objects**というリストがあります。ここに、先ほど**Inject属性**をつけた変数を持っているTestMonoBehaviourを入れます。

![スクリーンショット 2024-12-01 172921.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/565ec56e-e169-8931-cdba-f999a36ca99e.png)

リストの中に入れたら再生を行います。コンソールを確認するとエラーが出ずに、ログが出ていることが分かります。手動登録の手間が少ないので、この時点でサービスロケーターの登録よりも正直楽です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/61ba1bec-59ed-f9c5-cb89-9bf91150ca20.png)

一度動かすことができたので、先ほど出てきたLifetimeという部分について触れます。
Lifetimeはインスタンスの利用方法について指定をする引き数で3つの中から選ぶことができます。それぞれの違いをざっくりと書きます。

### ・Singleton
一度生成したインスタンスを使い回す。

### ・Transient
都度生成してインスタンスを渡す。

### ・Scoped
**Singleton**と少し似ていて、LifetimeScopeに既に作成したインスタンスがあればそれを使い回し、なければ新しく生成して使い回す。

かなり雑な説明にはなってしまいましたが、ざっくりと動かしてサービスロケーターのような手動登録の手間が少なく便利そうだということが分かりました。

# まとめ
現時点では、～こうやって～こうすると登録出来て～使えますなどかなり省いた内容でしたが...正直サービスロケーターより使いやすいです。

ただ、インスタンス登録処理もかなりあったり、VContainerのインタフェースを利用して色々出来るなど...便利だと感じる反面、利用が難しそうだなと感じる部分もありましたので、アウトプットを通じてVContainerを使いこなせるようになりたいですね。