UniRx

UniRxの導入

以下のURLを参考にパッケージマネージャーからインストールする

UniRxの導入

UniRxの用途

UniRxはイベント処理を扱うのに長けたライブラリです。

UniRxでInputイベントを扱う

using UniRx;
using UnityEngine;

namespace Events
{
    public sealed class InputEventProvider : MonoBehaviour
    {
        /// <summary>
        /// 攻撃ボタン入力
        /// </summary>
        public IReadOnlyReactiveProperty<bool> Attack => _attack;

        /// <summary>
        /// 移動方向入力
        /// </summary>
        public IReadOnlyReactiveProperty<Vector3> Move => _move;

        /// <summary>
        /// ジャンプ入力
        /// </summary>
        public IReadOnlyReactiveProperty<bool> Jump => _jump;

        // 実装
        private ReactiveProperty<bool> _attack = new BoolReactiveProperty();
        private ReactiveProperty<bool> _jump = new BoolReactiveProperty();
        private ReactiveProperty<Vector3> _move = new ReactiveProperty<Vector3>();

        private void Start()
        {
            // Destroy時にDispose()する
            _attack.AddTo(this);
            _jump.AddTo(this);
            _move.AddTo(this);
        }

        private void Update()
        {
            // 各種入力をReactivePropertyに反映
            _jump.Value = Input.GetButton("Jump");
            _attack.Value = Input.GetButton("Attack");
            _move.Value = new Vector3(
                x:Input.GetAxis("Horizontal"), 
                y:0,
                z:Input.GetAxis("Vertical"));
        }
    }
}
using System;
using UniRx;
using UnityEngine;

namespace Events
{
    /// <summary>
    /// 例:Inputをみて移動する
    /// </summary>
    public class PlayerMove : MonoBehaviour
    {
        [SerializeField] private float _moveSpeed = 1.0f;
        [SerializeField] private InputEventProvider _inputEventProvider;

        private CharacterController _characterController;

        private void Start()
        {
            _characterController = GetComponent<CharacterController>();

            // ジャンプ
            // ジャンプボタン入力イベントを判定
            _inputEventProvider.Jump
                // ボタンが押された時に、
                .Where(x => x)
                // 接地中であり、
                .Where(_ => _characterController.isGrounded)
                // 最後にジャンプしてから1秒以上経過しているなら、
                .ThrottleFirst(TimeSpan.FromSeconds(1))
                .Subscribe(_ =>
                {
                    // ジャンプ処理を実行する
                    _characterController.Jump();
                });
            
            // 移動処理
            _inputEventProvider
                .MoveDirection
                // 一定値以上入力されたなら
                .Where(x => x.magnitude > 0.5f)
                .Subscribe(x =>
                {
                    // そっち方向に移動する
                    _characterController.Move(x.normalized * _moveSpeed);
                });
        }
    }
}


Model-View-(Reactive)Presenterパターン

Modelの実装方法

using UniRx;
using UnityEngine;

namespace MVRP.Models
{
    /// <summary>
    /// アクションゲームにおけるプレイヤー
    /// </summary>
    public sealed class PlayerStatusModel : MonoBehaviour
    {
        /// <summary>
        /// 体力
        /// </summary>
        public IReadOnlyReactiveProperty<int> Health => _health;
        /// <summary>
        /// 経験値
        /// </summary>
        public IReadOnlyReactiveProperty<int> Exp => _exp;
        

        private IntReactiveProperty _health= new IntReactiveProperty(100);
        private IntReactiveProperty _exp = new IntReactiveProperty(0);

        /// <summary>
        /// 衝突イベント
        /// </summary>
        private void OnCollisionEnter(Collision collision)
        {
            // Enemyに触れたら体力を減らす
            if (collision.gameObject.TryGetComponent<Enemy>(out var _))
            {
                _health.Value -= 10;
            }
        }

        private void OnDestroy()
        {
            _health.Dispose();
            _exp.Dispose();
        }
    }
}

Viewの実装方法

using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

namespace MVRP.Views
{
    /// <summary>
    /// uGUIのSliderをアニメーションさせるコンポーネント(View)
    /// </summary>
    public sealed class AnimationSlider : MonoBehaviour
    {
        [SerializeField] private Slider _slider;

        public void SetValue(float value)
        {
            // アニメーションしながらSliderを動かす
            DOTween.To(() => _slider.value, 
                n => _slider.value = n,
                value, 
                duration: 1.0f);
        }
    }
}

Presenterの実装方法

using MVRP.Models;
using MVRP.Views;
using UniRx;
using UnityEngine;

namespace MVRP.Presenters
{
    /// <summary>
    /// Playerの体力をViewに反映するPresenter
    /// </summary>
    public sealed class PlayerHealthPresenter : MonoBehaviour
    {
        // Model
        [SerializeField] private PlayerStatusModel _player;

        // View
        [SerializeField] private AnimationSlider _animationSlider;

        private void Start()
        {
            // PlayerのHealthを監視
            _player.Health
                .Subscribe(x =>
                {
                    // Viewに反映
                    _animationSlider.SetValue((float)x / _player.MaxHealth);
                })
                .AddTo(this);
        }
    }
}

参考文献

2022年現在におけるUniRxの使いみち

コメント

タイトルとURLをコピーしました