はじめに
UniRxを書くようになって、UniRxと相性の良いMVRP(Model-View-Reactive-Presenter)パターンがあるというのは耳にしていたのですが、今回初めて自分で書いてみたので記録として残しておきます。
環境
OS : Windows10
Unity バージョン : 2021.3.2f1
HPゲージの作成
- プレイヤーの頭上に追従するHPゲージを実装したかったため、プレイヤーの子にCanvasを用意します。
- SliderをCanvasの子に作成し、Handle Slide Areaは今回使用しないため削除します。
コンポーネントの作成
今回作成したコンポーネントは以下3つになります。
- HPModel
- HPView
- HPPresenter
HPModel
HPModelでは、ReactivePropertyを使用し、HPを公開しているのみです。
HPModel.cs
using UnityEngine;
using UniRx;
public class HPModel: MonoBehaviour
{
/// <summary>
/// 最大HP
/// </summary>
public readonly int maxHP = 100;
/// <summary>
/// 残っているHP
/// </summary>
public IReadOnlyReactiveProperty<int> HP => _hp;
private readonly IntReactiveProperty _hp = new IntReactiveProperty();
private void Start()
{
_hp.Value = maxHP;
}
/// <summary>
/// ダメージを受けたときの処理
/// </summary>
public void GetDamage()
{
_hp.Value -= 10;
}
private void OnDestroy()
{
_hp.Dispose();
}
}
HPView
HPViewでは、Sliderを変化させるのみです。
HPView.cs
using UnityEngine;
using UnityEngine.UI;
public class HPView : MonoBehaviour
{
/// <summary>
/// HPゲージ
/// </summary>
private Slider _hpGuage;
private void Start()
{
_hpGuage = this.GetComponent<Slider>();
}
/// <summary>
/// HPゲージの設定
/// </summary>
/// <param name="maxHP">最大HP</param>
/// <param name="hp">残っているHP</param>
public void SetGuage(int maxHP, float hp)
{
_hpGuage.value = hp / maxHP;
}
}
HPPresenter
HPPresenterでは、HPModelとHPViewの橋渡しを行います。
HPPresenter.cs
using UnityEngine;
using UniRx;
public class HPPresenter : MonoBehaviour
{
[SerializeField] private GameObject _player;
private HPModel _hPModel;
private HPView _hpView;
private IGetHitEventProvider _getHitEventProvider;
void Start()
{
_getHitEventProvider = _player.GetComponent<IGetHitEventProvider>();
_hPModel = this.GetComponent<HPModel>();
_hpView = this.GetComponent<HPView>();
// 敵に当たった時の処理
_getHitEventProvider.GetHit
.Where(getHit => getHit == true)
.Subscribe(_ => _hPModel.GetDamage());
// HPModel内のHPが減ったことをViewへ知らせる
_hPModel.HP
.Subscribe(hp => _hpView.SetGuage(_hPModel.maxHP, hp)).AddTo(this);
}
}
作成したコンポーネントをアタッチ
最初に作成したSliderにすべてのコンポーネントをアタッチします。
実際に動かすとこのようになりました。