입력 처리

연산자: Buffer TakeUntil

Zip/Skip 연산자를 사용한 스와이프(swipe) 처리

using UnityEngine;
using System.Collections;
using System;
using UniRx;

public  class CameraMove : MonoBehaviour {

    // 메인 카메라
    public Camera MainCamera;

    // FixedUpdate
    void FixedUpdate () {
#if UNITY_EDITOR
        // 마우스를 눌렀을 경우
        if (Input.GetMouseButtonUp ( 0 )) {
        } else  if (Input.GetMouseButton ( 0 )) {
            MapSwipe ();
        }
 #elif UNITY_IOS || UNITY_ANDROID
        if (Input.touchCount == 0 ) {
        } else  if (Input.touchCount == 1 ) {
            MapSwipe ();
        }
       #endif
    }

    public  void MapSwipe ()
    {   
    #if UNITY_EDITOR
        // mousePosition의 취득
        var drug = Observable.EveryUpdate () .Select (pos => Input.mousePosition);
        // 클릭이 말한 경우 수신 거부
        var stop = Observable.EveryUpdate () .Where (_ => Input.GetMouseButtonUp ( 0 ));
    #elif UNITY_IOS || UNITY_ANDROID
        // position의 취득
        var drug = Observable.EveryUpdate () .Select (pos => Input.GetTouch ( 0 ) .position);
         // 터치 카운트가 변경된 경우 수신 거부
        var stop = Observable.EveryUpdate () .Where (_ => Input.touchCount! = 1 );
    # endif

        //  4 프레임 후의 마우스 위치를 비교하여 카메라 Rigidbody 속도를 변경.
        IDisposable onDrug = drug.Zip (drug.Skip ( 4 ), (pos1, pos2) => new {x = pos2.x - pos1.x, z = pos2.y - pos1.y})
             // 클릭이 말한 후 수신 거부
            .TakeUntil (stop)
            .Subscribe (deltaPosition => {
                MainCamera.gameObject.GetComponent <Rigidbody> (). velocity = new Vector3 (deltaPosition.x, 0 , deltaPosition.z) * - 5 ;
            }
        );
    }
}

Buffer 연산자를 사용한 스와이프(swipe) 처리

#if UNITY_EDITOR
    var drag = Observable.EveryUpdate ().Select (pos => Input.mousePosition);
    var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)).First();
#elif UNITY_IOS || UNITY_ANDROID
    var drag = Observable.EveryUpdate ().Select (pos => Input.GetTouch(0).position);
    var stop = Observable.EveryUpdate ().Where(_ => Input.touchCount != 1).First();
#endif

    IDisposable onDrag = drag.Buffer (3)
        .TakeUntil(stop)
        .Subscribe (colPos => {
            float delPosx = colPos.Last().x - colPos.First().x;
            float delPosz = colPos.Last().y - colPos.First().y;
            float Speed = 0 -(5 * (MainCamera.fieldOfView / 60));
            MainCamera.gameObject.GetComponent<Rigidbody>().velocity = new Vector3(delPosx, 0, delPosz) * Speed;
    });

Buffer 연산자를 사용한 쪽의 코드가 훨씬 간결한데다 스와이프 시작을 검사하는 FixedUpdate에서의 코드도 필요하지 않습니다.

using UnityEngine;
 using System.Collections;
 using System;
 using UniRx;

public  class CameraMove : MonoBehaviour {

    // 메인 카메라
    public Camera MainCamera;

    // Update
    void Update () {
    #if UNITY_EDITOR
        // 마우스를 눌렀을 경우
        if (Input.GetMouseButtonUp ( 0 )) {
        } else  if (Input.GetKey (KeyCode.Space) && Input.GetMouseButton ( 0 )) {
             // 편집기에서 멀티 터치를 재현 할 수 없기 때문에 마우스버튼 클리과 스페이스 키 조합을 이용.
            MapPinch ();
        } else  if (Input.GetMouseButton ( 0 )) {
            MapSwipe ();
        }
    #elif UNITY_IOS || UNITY_ANDROID

        if (Input.touchCount == 0 ) {
        } else  if (Input.touchCount == 1 ) {
            MapSwipe ();
        } else  if (Input.touchCount> = 2 ) {
            MapPinch ();
        }
    #endif
    }

    // Swipe ...     

    // 핀치 처리
    public  void MapPinch ()
    {
    #if UNITY_EDITOR
        // 편집기에서 마우스 포지션으로 확인 (검증)
        var pinch = Observable.EveryUpdate () .Select (pos_dist => Input.mousePosition.x);
        var stop = Observable.EveryUpdate () .Where (_ => Input.GetMouseButtonUp ( 0 ));
    #elif UNITY_IOS || UNITY_ANDROID
        // 2 점의 거리를 취득
        var pinch = Observable.EveryUpdate ()
            .Select (pos_dist => Vector2.Distance (Input.GetTouch ( 0 ) .position, Input.GetTouch ( 1 ) .position));
         // 터치 카운트가 2에서는 없어지면 수신 거부
        var stop = Observable.EveryUpdate (). Where (_ => Input.touchCount! = 2 );
    #endif

        // 다음 프레임의 위치를 취득하고 2 점 좌표의 차이를 가져
        IDisposable onPinch = pinch.Zip (pinch.Skip ( 1 ), (dist1, dist2) => new {diff = dist2 - dist1})
            .TakeUntil (stop)
            .Subscribe (distanceParam => {
                // 카메라의 fieldOfView을 변경하여 위기를 재현하는
                MainCamera.fieldOfView - = distanceParam.diff / 30 ;

                // 0 이하가되면 반전 것이기 때문에 한계를 마련
                if (MainCamera.fieldOfView < 4 ) {
                    MainCamera.fieldOfView = 4 ;
                }

                if (MainCamera.fieldOfView> 70 ) {
                    MainCamera.fieldOfView = 70 ;
                }
            });
    }
}

Buffer 연산자를 사용한 핀치(Pinch)

#if UNITY_EDITOR
       var pinch = Observable.EveryUpdate ().Select (pos_dist => Input.mousePosition.x);
       var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)).First();
#elif UNITY_IOS || UNITY_ANDROID
       var pinch = Observable.EveryUpdate ()
           .Select (pos_dist => Vector2.Distance(Input.GetTouch (0).position, Input.GetTouch (1).position));
       var stop = Observable.EveryUpdate ().Where (_ => Input.touchCount != 2).First();
#endif

       IDisposable onPinch = pinch.Buffer(3)
           .TakeUntil(stop)
           .Subscribe(distanceParam => {
               float diff = distanceParam.Last() - distanceParam.First();

      #if UNITY_EDITOR
               MainCamera.fieldOfView -= diff;
      #elif UNITY_IOS || UNITY_ANDROID
               MainCamera.fieldOfView -= diff / 10;
      #endif
           });

원문: http://befool.co.jp/blog/raharu/unirx-003/

Subject를 이용해서 Unity3D의 컴포넌트로 간단하게 표현

public  class DragObserver : ObservableMonoBehaviour
{
    private Subject <Vector2> onDragStream = new Subject <Vector2> ();

    public IObservable <Vector2> onDragAsObservable {
         get { return onDragStream.AsObservable ();}
    }

    public  override  void Start ()
    {
        var mousePositionAsObservable = UpdateAsObservable (). Select (_ => Input.mousePosition);

        mousePositionAsObservable
            .Zip (mousePositionAsObservable.Skip ( 1 ), (prev, cur) => prev - cur)
            .DistinctUntilChanged ()
            .Where (_ => Input.GetMouseButton ( 0 ))
            .Subscribe (delta => onDragStream.OnNext (delta));
    }
}

아래는 사용예입니다.

    DragObserver onDrag = FindObjectOfType <DragObserver> ();
    onDrag.onDragAsObservable
        .Subscribe (delta => print ( "Delta :" + delta.ToString ()));

마우스의 이전 위치값을 가져와서 현재값과의 차이를 구합니다.

mousePositionAsObservable.Zip(mousePositionAsObservable.Skip(1), (prev, cur) => prev - cur)

Skip(1) 으로 첫번째 마우스 입력을 건너 뛴 다음 두 번째 입력을 받은 시점에서 첫 번째 입력값과의 차를 구한 다음 이를 Zip 연산자로 수집합니다. Zip 연산자는 복수개의 값이 모이면 스트림으로 흘려 보냅니다.

다음으로 DistinctUntilChanged 연산자는 값의 변화가 있는 경우 스트림을 흘려 보내게 됩니다.

실제 구독은 Where (_ => Input.GetMouseButton ( 0 )) 연산을 통해서 마우스 버튼을 눌러진 경우에만 구독 처리가 됩니다.

Where 연산자로 마우스 버튼의 클릭 여부만을 비교하는 방법 대신 아래와 같이 마우스 버튼이 눌러진 후부터 떼기까지를 반복해서 검사하는 방법을 사용할 수도 있습니다.

    SkilUntil(onMouseDown).TakeUntil(onMouseUp).Repeat()

Zip 연산자를 Buffer 연산자를 사용해서 다시 작성한 코드입니다.

public  class DragObserver : ObservableMonoBehaviour
{
    private Subject <Vector2> onDragStream = new Subject <Vector2> ();

    public IObservable <Vector2> onDragAsObservable {
         get { return onDragStream.AsObservable ();}
    }

    public  override  void Start ()
    {
        var mousePositionAsObservable = UpdateAsObservable (). Select (_ => Input.mousePosition);

        mousePositionAsObservable
            .Buffer ( 2 , 1 )
            .Select (mousePosition => mousePosition.First () - mousePosition.Last ())
            .DistinctUntilChanged ()
            .Where (_ => Input.GetMouseButton ( 0 ))
            .Subscribe (delta => onDragStream.OnNext (delta));
    }
}

results matching ""

    No results matching ""