かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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;
        }
    }
}