かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

UniRxを使ってオブジェクトをマウスドラッグで回転させる

またまたありがちな例ですがUniRxとUnityに慣れるために書いてみました。

UniRx版

using UnityEngine;
using System.Collections;
using UniRx;

public class UniRxRollingBehaviour : ObservableMonoBehaviour
{
    public override void Awake()
    {
        var drag = this.UpdateAsObservable()
            .Where(_ => Input.GetMouseButton(0))
            .SkipUntil(this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButtonDown(0))
                .Select(_ =>
                {
                    RaycastHit rh;
                    return Tuple.Create(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out rh), rh);
                })
                .Where(x => x.Item1 && x.Item2.collider.gameObject == this.gameObject))
            .TakeUntil(this.UpdateAsObservable().Where(_ => Input.GetMouseButtonUp(0)))
            .Repeat()
            .Select(_ => Input.mousePosition);

        drag.Zip(drag.Skip(1), (x, y) => Tuple.Create(x, y))
            .Select(x => x.Item2 - x.Item1)
            .Select(x => new Vector3(x.y, -x.x, x.z))
            .Subscribe(x => this.transform.Rotate(x));

        base.Awake();
    }
}

今回はがっつり1ステートメントに詰め込みました。そのぶん短くなったかな。コメントがあれば個人的には許容範囲かも。

続いて比較のためにUniRx無い版を書いてみた。状態管理のためのフラグとかが増えてきてちょっといやな感じを醸し出しはじめてるけど、まだ許容範囲。

using UnityEngine;
using System.Collections;

public class NormalRollingBehaviour : MonoBehaviour
{
    private bool drag;

    private bool first = true;

    private Vector3 prevPosition;

    // Update is called once per frame
    void Update()
    {
        print("update");
       // ドラッグ中じゃなくてマウスが押されたら
        if (!drag && Input.GetMouseButtonDown(0))
        {
            // 対象オブジェクトの上でクリックされたかチェックして
            RaycastHit rh;
            if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out rh))
            {
                if (rh.collider.gameObject == this.gameObject)
                {
                    // 対象オブジェクトの場合は、ドラッグ中の状態にする
                    drag = true;
                }
            }
        }

        // ドラッグ中にマウスが離されたらドラッグ中を解除して処理を抜ける
        if (drag && Input.GetMouseButtonUp(0))
        {
            drag = false;
            return;
        }

        // ドラッグ中は
        if (drag)
        {
            print("drag");
            if (!first)
            {
                var diff = Input.mousePosition - prevPosition;
                print(diff);
                this.transform.Rotate(new Vector3(diff.y, -diff.x, diff.z));
            }
            first = false;
            prevPosition = Input.mousePosition;
        }
    }
}