UniRx を試してみた

Unity でイベント処理などが複雑になってきたので、どうにかできないかと思い UniRx を試しました。

github.com

UniRx とは イベントを時系列に並んだシーケンスと捉え、それらを filter したり map したりすることでイベント処理を行うものです。

たとえば、Spaceキーが入力されたときに、プレイヤーをジャンプさせるといったことをする場合は、通常は以下のように Update() でキーが入力されたか判定し、その結果のフラグをプロパティに保持しておき、FixedUpdate() でフラグが立っていれば RidgedBody を操作するといったことをします。

using System;
using UnityEngine;

public class JumpBehaviourScript : MonoBehaviour
{
    private Boolean isEnteredSpaceKey;
    private Rigidbody rigidBody;

    private void Start()
    {
        isEnteredSpaceKey = false;
        rigidBody = GetComponent<Rigidbody>();
    }

    private void Update()
    {
        isEnteredSpaceKey = Input.GetKey(KeyCode.Space);
    }

    private void FixedUpdate()
    {
        if (isEnteredSpaceKey) {
            rigidBody.AddForce(Vector3.up, ForceMode.VelocityChange);
        }
    }
}

この方法では、キーが押されたかの判定とその時の動作が別の場所にあるため、キー入力が多くなってくると見通しが悪くなってきます。

ここで、UniRx を用いると以下のように記述できます。

using UniRx;
using UniRx.Triggers;
using UnityEngine;

public class JumpBehaviourScript : MonoBehaviour
{
    private void Start()
    {
        var rididBody = GetComponent<Rigidbody>();

        this.UpdateAsObservable()
            .Where(_ => Input.GetKey(KeyCode.Space))
            .BatchFrame(0, FrameCountType.FixedUpdate)
            .Subscribe(_ => rididBody.AddForce(Vector3.up, ForceMode.VelocityChange));
    }
}

これは、 UpdateAsObservable()Update() のタイミングでイベントが発生するというストリームを生成します。そして .Where(_ => Input.GetKey(KeyCode.Space)) でキーが押されたときだけ filter します。 そのあとに、 BatchFrame(0, FrameCountType.FixedUpdate) でバッファにイベントをためておき、FixedUpdate() のタイミングでポップします。最後に Subscribe(_ => rididBody.AddForce(Vector3.up, ForceMode.VelocityChange)) でジャンプする動作を行います。

このように、UniRx を用いることで、キー入力判定からジャンプの動作までを一つのストリームで簡潔に記述できます。

そのほかにも、MVPパターンのReactive実装のパターンである MV(R)P パターンの実装など Unity において様々なところで活躍しそうです。

UniRx については以下が詳しいです。

www.slideshare.net qiita.com

また、以下に調査時のサンプルコードがあります。

github.com