はじめに
今回はVContainerを試してみる記事です。
ネット上でZenjectと比較してかなり高速でシンプルと聞いたので、実際に試してみました。
サンプルプロジェクト
試してみる
こんなものを試しに作りました。クリックすると箱がジャンプして、テキストにジャンプした回数が表示されます。
MVPパターンで実装していて、入力を環境によって分けています。また、Modelのテストに備えて、ModelをInterfaceで切り離しています。
導入
今回はunitypackage経由でインストールしました。
1. manifest.jsonに「"com.unity.nuget.mono-cecil": "1.10.1", 」を記述
2. 最新リリースからunitypackageをダウンロード
3. unitypackageインポート
準備
Zenjectだとコンストラクタインジェクションは[inject]は必要なかったのですが、VContainerでは必要みたいなのでコンスタントにも[inject]をつけています。
public class Model : IModel
{
public IReactiveProperty CountProp=>_countProp;
private readonly IntReactiveProperty _countProp;
public Model()
{
_countProp=new IntReactiveProperty(0);
}
public void AddCount()
{
_countProp.Value++;
}
}
public class Presenter : IStartable, IDisposable
{
private readonly View _view;
private readonly IModel _model;
private readonly CompositeDisposable _compositeDisposable = new CompositeDisposable();
[Inject]
public Presenter(View view, IModel model)
{
_view = view;
_model = model;
}
public void Start()
{
Bind();
SetEvent();
}
private void Bind()
{
_model.CountProp
.Subscribe(_view.SetCount)
.AddTo(_compositeDisposable);
}
private void SetEvent()
{
_view.OnAnimationCallback += () => _model.AddCount();
_view.InputJump()
.Subscribe(_=>_view.Jump())
.AddTo(_compositeDisposable);
}
public void Dispose()
{
_compositeDisposable.Dispose();
}
}
public class View : MonoBehaviour
{
public event Action OnAnimationCallback;
[SerializeField] private Transform _cubeTransform;
private Sequence _sequence;
[SerializeField] private Text _countText;
[Inject] IInputProvider _input;
public void SetCount(int count)
{
_countText.text = count.ToString();
}
public IObservable InputJump()
{
return _input.InputJump();
}
public void Jump()
{
if (_sequence.IsActive()) return;
_sequence = DOTween.Sequence()
.Join(_cubeTransform.DOJump(new Vector3(0, 0, 0), 3f, 1, 1.0f).SetRelative())
.Join(_cubeTransform.DOPunchRotation(new Vector3(360f, 360f, 360f), 1.0f,5).SetRelative())
.SetEase(Ease.OutCubic).OnComplete(()=>OnAnimationCallback?.Invoke()).SetLink(this.gameObject);
}
}
public interface IInputProvider
{
public IObservable InputJump();
}
public class KeyInputProvider : IInputProvider
{
public IObservable InputJump()
{
return InputAsObservable.GetKeyDown(KeyCode.Space);
}
}
MVPでViewとPresenterを互いを知らない状態にしつつ、Interfaceを設けることでPresenterがModelの存在を知らない状態を実現しています。入力も同じように、Interfaceを設けてEditorとWebGLで切り替えています。
登録
Zenjectと同じように登録できました。RegisterEntryPoint()で注入先を指定して、Register()とRegisterComponet()で注入するクラスを登録しています。
public class MvpLifetimeScope : LifetimeScope
{
[SerializeField] private View _view;
protected override void Configure(IContainerBuilder builder)
{
#if UNITY_EDITOR
builder.Register<IInputProvider, GamepadInputProvider>(Lifetime.Transient);
#elif UNITY_WEBGL
builder.Register<IInputProvider,KeyInputProvider>(Lifetime.Transient);
#endif
builder.Register<IModel,Model>(Lifetime.Transient);
builder.RegisterComponent(_view);
builder.RegisterEntryPoint(Presenter);
}
}
おわりに
普段Zenjectを使っている身からすると、VContainerに移行しなくても良いかなと思いました。Zenjectにはあって、VContainerには無い機能もあったりしますし、ZenjectからVContainerへの移行に伴うリファクタを考えると頭が...
是非、読者登録をしていただくと助かります!