<|start_filename|>Assets/UniRxWorkBook/Operators/11_ThrottleFirst/Lesson_11_ThrottleFirst.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{

    public class Lesson_11_ThrottleFirst : MonoBehaviour
    {
        [SerializeField] private GameObject bulletObject;

        private void Start()
        {
            // 下記スクリプトは「左クリックをしている間弾を発射する」スクリプトである
            // ただしこのままでは毎フレーム弾が生成されてしまう
            // そこで、____を書き換えて「左クリックをしている間100msに１回ずつ弾を発射する」という動作にしよう
            this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButton(0))
                ._____()
                .Subscribe(_ =>
                {
                    var b = Instantiate(bulletObject, transform.position, Quaternion.identity) as GameObject;
                    Destroy(b, 2.0f);
                });
        }

    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/12_TakeUntil/Answer/Answer_Lesson_12_TakeUntil.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using UniRx;
using UniRx.Triggers;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{

    public class Answer_Lesson_12_TakeUntil : MonoBehaviour
    {
        [SerializeField]
        private Button onButton;
        [SerializeField]
        private Button offButton;
        [SerializeField]
        private GameObject cube;

        private void Start()
        {
            // TakeUntil は引数で与えたストリームにメッセージが到達した際にOnCompletedを発行する
            // SkiptUntilと組み合わせることで、「イベントAが来てからイベントBが来るまで処理する」といったことが簡単に記述できる
            var onStream = onButton.OnClickAsObservable();
            var offStream = offButton.OnClickAsObservable();
            this.UpdateAsObservable()
                .SkipUntil(onStream)
                .TakeUntil(offStream)
                .RepeatUntilDestroy(gameObject)
                .Subscribe(_ => RotateCube());

            // なお、TakeUntilは本流にメッセージが到達しているか否かに関係なく動作する点に注意するべきである
            // たとえば、Repeatを外して
            //
            // this.UpdateAsObservable()
            //    .SkipUntil(onStream)
            //    .TakeUntil(offStream)
            //    .Subscribe(_ => RotateCube(), () => Debug.Log("OnComplted!"));
            //
            // このような構成にした状態で、OFFボタンを先に押してみよう。ログに「OnComplted！」と表示されるはずである。
            // SkipUntilによってメッセージが阻まれ、TakeUntilにまだメッセージが到達していないにもかかわらずTakeUntilが発動してしまった。
            //
            // このように、TakeUntilはSubscribeされた瞬間に稼働を始め、OnNextが到達したかどうかは関係ないという点を覚えて多く必要がある。
            // (　✕：OnNextメッセージが来た瞬間に有効になる　○：Subscribeした瞬間に既に有効になっている） 
        }

        private void RotateCube()
        {
            cube.transform.rotation = Quaternion.AngleAxis(1.0f, Vector3.up) * cube.transform.rotation;
        }
    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/09_CombineLatest/Answer/Answer_Lesson_9_CombineLatest.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{

    public class Answer_Lesson_9_CombineLatest : MonoBehaviour
    {
        [SerializeField]
        private InputField leftInput;
        [SerializeField]
        private InputField rightInput;
        [SerializeField]
        private Text resultLabel;
        private void Start()
        {
            var leftStream = leftInput.OnValueChangeAsObservable().Select(x => Int32.Parse(x));
            var rightStream = rightInput.OnValueChangeAsObservable().Select(x => Int32.Parse(x));

            // ZipをCombineLatestに書き換えれば良い
            // Zipは複数のストリームのメッセージが1つずつ揃った時に放出するものであったが、
            // CombineLatestはすべてのストリームの値が揃ってなくても直前の値を代わりに使って放出するオペレータである
            // [参考] http://reactivex.io/documentation/operators/combinelatest.html
            leftStream
                .CombineLatest(rightStream, (left, right) => left + right)
                .SubscribeToText(resultLabel);
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/StreamSources/2_BehaviorSubject/Lesson_2_BehaviorSubject.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.StreamSources
{

    public class Lesson_2_BehaviorSubject : MonoBehaviour
    {
        [SerializeField]
        private Button subscribeButton;
        [SerializeField]
        private Button onNextButton;
        [SerializeField]
        private Button onCompletedButton;
        [SerializeField]
        private Button resetButton;
        [SerializeField]
        private Text resultText;

        private int onNextCount = 0;

        //BehaviorSubjectは Subject に「直前の」OnNextを記憶させる機能を持たせたものである
        //Subjectとの大きな違いとしては、Subscribeした瞬間に「直前の」値を発行してくる点である
        //
        //似た挙動をするSubjectにReplaySubjectというものもあるが、こちらは全てのOnNextを記憶して再生するものである
        private BehaviorSubject<int> behaviorSubject;

        private void Start()
        {
            //BehaviorSubjectは初期値を設定できる
            behaviorSubject = new BehaviorSubject<int>(0);

            /*
            OnNext → Subscribe と実行し、Subscribeした瞬間に直前の値が発行されることを確認しよう
            */

            // Subscribeボタンが押されたらSubjectをSubscribeしてresultTextに表示する
            subscribeButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (behaviorSubject != null)
                {
                    behaviorSubject.Subscribe(
                        time => resultText.text += time.ToString() + "　", //OnNext
                        () => resultText.text += "OnCompleted　"); //OnCompleted
                }
            });

            // OnNextボタンが押されたら今が何度目のOnNextであるかを発行する
            onNextButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (behaviorSubject != null)
                {
                    behaviorSubject.OnNext(++onNextCount);
                }
            });

            // OnCompletedボタンが押されたらOnCompletedを発行する
            onCompletedButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (behaviorSubject != null)
                {
                    behaviorSubject.OnCompleted();
                }
            });

            // Resetボタンが押されたら全体を初期化する
            resetButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (behaviorSubject != null)
                {
                    behaviorSubject.OnCompleted();
                }
                behaviorSubject = new BehaviorSubject<int>(0);
                resultText.text = "";
                onNextCount = 0;
            });

        }


    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/forSceneObject/SimpleJump.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx.Triggers;
using UniRx;

namespace UniRxWorkBook
{
    public class SimpleJump : MonoBehaviour
    {
        [SerializeField] private float _jumpPower = 5;

        private void Start()
        {
            var controller = GetComponent<CharacterController>();
            //クリックまたはスペースキーでジャンプ
            this.UpdateAsObservable()
                .Where(_ => controller.isGrounded && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)))
                .Subscribe(_ =>
                {
                    controller.Move(_jumpPower*Vector3.up*Time.deltaTime);
                });

            this.UpdateAsObservable()
                .Subscribe(_ =>
                {
                    var currentY = controller.velocity.y;
                    var nextYSpeed = currentY + Physics.gravity.y*Time.deltaTime;
                    controller.Move(new Vector3(0, nextYSpeed, 0)*Time.deltaTime);
                });
        }
    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/02_Where/Answer/Answer_Lesson_2_Where.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{

    public class Answer_Lesson_2_Where : MonoBehaviour
    {

        private void Start()
        {
            // Whereオペレータを挟むことで、一定の条件を満たしている時のみストリームを通過させることができるようになる
            this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButton(0))
                .Subscribe(_ => RotateCube());
        }

        private void RotateCube()
        {
            this.transform.rotation = Quaternion.AngleAxis(1.0f, Vector3.up)*this.transform.rotation;
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/01_Subscribe/Answer/Answer_Lesson_1_Subscribe.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{

    public class Answer_Lesson_1_Subscribe : MonoBehaviour
    {
        private void Start()
        {
            // UniRx.Triggerを追加することでthis.UpdateAsObservable()でUpdate()をストリームとして扱うことができるようになる
            // あとはそれをSubscribeし、毎フレームCubeが回転するようになる
            this.UpdateAsObservable().Subscribe(_ => RotateCube());

            //ちなみにラムダ式の左辺に _ を使っているが、これは「デリゲート内でこの引数を使うことはない」という意味である
        }

        private void RotateCube()
        {
            this.transform.rotation = Quaternion.AngleAxis(1.0f, Vector3.up)*this.transform.rotation;
        }
    }

}


<|start_filename|>Assets/UniRxWorkBook/Operators/13_DistinctUntilChanged/Lesson_13_DistinctUntilChanged.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;
using UniRx.Triggers;
using UnityEngine.UI;

namespace UniRxWorkBook
{
    public class Lesson_13_DistinctUntilChanged : MonoBehaviour
    {
        [SerializeField] private GameObject target;
        [SerializeField] private Text statusText;

        private void Start()
        {
            var controller = target.GetComponent<CharacterController>();

            /*
            オブジェクトが着地または離陸したタイミングを検知して画面に表示したい
            ____を書き換え、isGroundedが true→false または false→true に変わった瞬間を検知させてみよう
            */

            this.UpdateAsObservable()
                .Select(_ => controller.isGrounded)
                ._____()
                .Subscribe(isGrounded => StatusOutput(isGrounded));
        }

        #region Output
        private List<string> logList = new List<string>();
        private int maxLogLength = 20;

        /// <summary>
        /// 着地または離陸の状態を文字列に変換して表示する
        /// </summary>
        /// <param name="isGrounded"></param>
        private void StatusOutput(bool isGrounded)
        {
            var text = isGrounded ? "OnGrounded\n" : "OnJumped\n";
            AddLog(text);
            statusText.text = logList.Aggregate((p, c) => p + c);
        }

        /// <summary>
        /// ログのテキストを先頭に追加する
        /// </summary>
        private void AddLog(string text)
        {
            logList.Insert(0,text);
            if (logList.Count > maxLogLength) logList.RemoveAt(maxLogLength);
        }
        #endregion
    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/02_Where/Lesson_2_Where.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{

    public class Lesson_2_Where : MonoBehaviour
    {

        private void Start()
        {
            // _____()の部分を正しい形に置換して、マウスの左クリックをしている間のみCubeが回転するようにしよう
            this.UpdateAsObservable()
                ._____()
                .Subscribe(_ => RotateCube());
        }

        private void RotateCube()
        {
            this.transform.rotation = Quaternion.AngleAxis(1.0f, Vector3.up) * this.transform.rotation;
        }

    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/04_Skip/Answer/Answer_Lesson_4_Skip.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{
    public class Answer_Lesson_4_Skip : MonoBehaviour
    {
        private void Start()
        {
            var clickStream = this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButtonDown(0));

            //Skip(n)はn回メッセージが到着するまでメッセージを遮断するオペレータ
            //3回目でメッセージが通るようにしたいので、この場合は最初の2回をSkipさせれば良い
            this.UpdateAsObservable()
                .SkipUntil(clickStream.Skip(2))
                .Subscribe(_ => RotateCube());
        }

        private void RotateCube()
        {
            this.transform.rotation = Quaternion.AngleAxis(1.0f, Vector3.up) * this.transform.rotation;
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/StreamSources/3_ReplaySubject/Lesson_3_ReplaySubject.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.StreamSources
{

    public class Lesson_3_ReplaySubject : MonoBehaviour
    {
        [SerializeField]
        private Button subscribeButton;
        [SerializeField]
        private Button onNextButton;
        [SerializeField]
        private Button onCompletedButton;
        [SerializeField]
        private Button resetButton;
        [SerializeField]
        private Text resultText;

        private int onNextCount = 0;

        // ReplaySubjectは過去のOnNextを全て記憶し、Subscribe時に全てまとめて発行する機能をもつSubjectである
        // BehaviorSubjectとの違いは、BehaviorSubjectは直前の値のみをキャッシュするものであり、ReplaySubjectは過去全てをキャッシュする
        private ReplaySubject<int> replaySubject;

        private void Start()
        {
            //ReplaySubjectも初期を設定することができる（今回は設定しない）
            replaySubject = new ReplaySubject<int>();

            /*
            OnNextを何回か繰り返す → Subscribe と実行し、Subscribeした瞬間に過去の値がまとめて値が発行されることを確認しよう
            */

            // Subscribeボタンが押されたらSubjectをSubscribeしてresultTextに表示する
            subscribeButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (replaySubject != null)
                {
                    replaySubject.Subscribe(
                        time => resultText.text += time.ToString() + "　", //OnNext
                        () => resultText.text += "OnCompleted　"); //OnCompleted
                }
            });

            // OnNextボタンが押されたら今が何度目のOnNextであるかを発行する
            onNextButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (replaySubject != null)
                {
                    replaySubject.OnNext(++onNextCount);
                }
            });

            // OnCompletedボタンが押されたらOnCompletedを発行する
            onCompletedButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (replaySubject != null)
                {
                    replaySubject.OnCompleted();
                }
            });

            // Resetボタンが押されたら全体を初期化する
            resetButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (replaySubject != null)
                {
                    replaySubject.OnCompleted();
                }
                replaySubject = new ReplaySubject<int>();
                resultText.text = "";
                onNextCount = 0;
            });

        }


    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/09_CombineLatest/Lesson_9_CombineLatest.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Lesson_9_CombineLatest : MonoBehaviour
    {
        [SerializeField] private InputField leftInput;
        [SerializeField] private InputField rightInput;
        [SerializeField] private Text resultLabel;
        private void Start()
        {
            var leftStream = leftInput.OnValueChangeAsObservable().Select(x => Int32.Parse(x));
            var rightStream = rightInput.OnValueChangeAsObservable().Select(x => Int32.Parse(x));

            // 下記のオペレータチェーンは2つのInputFieldに入力された数値を合計して表示するストリームを生成している
            // ただ、Zipでは挙動がおかしいので、Zipを適切なオペレータに変更しInputFiledの変更が即時反映されるようにしよう
            leftStream
                .Zip(rightStream, (left, right) => left + right)
                .SubscribeToText(resultLabel);
        }
    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/11_ThrottleFirst/Answer/Answer_Lesson_11_ThrottleFirst.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{

    public class Answer_Lesson_11_ThrottleFirst : MonoBehaviour
    {
        [SerializeField]
        private GameObject bulletObject;

        private void Start()
        {
            // ThrottleFirstはThrottleの逆で、「最初にメッセージが来てから一定期間メッセージを遮断する」オペレータである
            // これを使うことで多すぎるメッセージを簡単に間引くことができる
            // なお、フレーム数を指定できるThrottleFirstFrameもある
            this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButton(0))
                .ThrottleFirst(TimeSpan.FromMilliseconds(100)) //１つメッセージが来てから100ms間メッセージを遮断する
                .Subscribe(_ =>
                {
                    var b = Instantiate(bulletObject, transform.position, Quaternion.identity) as GameObject;
                    Destroy(b, 2.0f);
                });
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/06_First/Lesson_6_First.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using System.Linq;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Lesson_6_First : MonoBehaviour
    {

        [SerializeField]
        private Text resultLabel;
        [SerializeField]
        private Button buttonA;
        [SerializeField]
        private Button buttonB;
        [SerializeField]
        private Button buttonC;

        private void Start()
        {
            var aStream = buttonA.OnClickAsObservable().Select(_ => "A");
            var bStream = buttonB.OnClickAsObservable().Select(_ => "B");
            var cStream = buttonC.OnClickAsObservable().Select(_ => "C");

            // _____を書き換え、最初の１回目が押された時のみTextが書き換わるようにしよう
            Observable.Merge(aStream, bStream, cStream)
                ._____()
                .SubscribeToText(resultLabel);
        }

    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/10_Trottle/Lesson_10_Throttle.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{

    public class Lesson_10_Throttle : MonoBehaviour
    {
        [SerializeField] private InputField inputField;
        [SerializeField] private Text resultText;

        private void Start()
        {

            // _____を書き換え、最後に文字入力されてから1秒後にresultTextに反映されるようにしてみよう
            inputField
                .OnValueChangeAsObservable()
                ._____()
                .SubscribeToText(resultText);
        }
    } 
}

<|start_filename|>Assets/UniRxWorkBook/Operators/10_Trottle/Answer/Answer_Lesson_10_Throttle.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{

    public class Answer_Lesson_10_Throttle : MonoBehaviour
    {
        [SerializeField]
        private InputField inputField;
        [SerializeField]
        private Text resultText;

        private void Start()
        {

            // Throttleはメッセージが連続した時に、落ち着くまで待つオペレータ
            //
            // 指定した時間より短い間隔でメッセージが大量に来た場合、メッセージをすべて無視する
            // そして指定時間以上経過したときに、受け取ったメッセージのうち一番最後に来ていたものを１つだけ放出する
            // 今回のケースの様に、確定するまで値がブレたりするものに使うことで「安定するまで待つ」といった処理が簡単に書ける
            //
            // なお、フレーム数を指定できるThrottleFrameもある
            inputField
                .OnValueChangeAsObservable()
                .Throttle(TimeSpan.FromSeconds(1))
                .SubscribeToText(resultText);
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/StreamSources/1_Subject/Lesson_1_Subject.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.StreamSources
{

    public class Lesson_1_Subject : MonoBehaviour
    {
        [SerializeField] private Button subscribeButton;
        [SerializeField] private Button onNextButton;
        [SerializeField] private Button onCompletedButton;
        [SerializeField] private Button resetButton;
        [SerializeField] private Text resultText;

        private int onNextCount = 0;

        // SubjectとはIObserverとIObservableの両方を実装するクラスである。
        // つまり、SubjectはOnNext,OnCompleted,OnError,Subscribeの全てを持っており、Rxのストリームの根幹となるクラスである
        // よく使う UpdateAsObservable の定義をたどり、どういう実装になっているのかを確認するのも良いかもしれない
        private Subject<int> subject;

        private void Start()
        {
            subject = new Subject<int>();

            /*
            以下は、SubjectをGUIでいろいろいじれるようにしたものである。
            いくつか実行のパターンを記すので、この順序でボタンを押してどうなるか確認してほしい

            １．Subscribe → OnNext → OnCompleted　　　　　　　（値が発行されたあとストリームが終了する）
            ２．OnNext → Subscribe → OnNext → OnComplated 　（Subscribeしたタイミングでストリームが生成され値が受け取れるようになる）
            ３．Subscribe ×２ → OnNext → OnCompleted 　　　　 (Subscribeを実行した数だけストリームが生成され稼働する）
            */

            // Subscribeボタンが押されたらSubjectをSubscribeしてresultTextに表示する
            subscribeButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (subject != null)
                {
                    subject.Subscribe(
                        time => resultText.text += time.ToString() + "　", //OnNext
                        () => resultText.text += "OnCompleted　"); //OnCompleted
                }
            });

            // OnNextボタンが押されたら今が何度目のOnNextであるかを発行する
            onNextButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (subject != null)
                {
                    subject.OnNext(++onNextCount);
                }
            });

            // OnCompletedボタンが押されたらOnCompletedを発行する
            onCompletedButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (subject != null)
                {
                    subject.OnCompleted();
                }
            });

            // Resetボタンが押されたら全体を初期化する
            resetButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (subject != null)
                {
                    subject.OnCompleted();
                }
                subject = new Subject<int>();
                resultText.text = "";
                onNextCount = 0;
            });

        }


    }
}


<|start_filename|>Assets/UniRxWorkBook/ObservableExtension.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;

namespace UniRxWorkBook
{
    public static class ObservableExtension
    {
        public static IObservable<T> _____<T>(this IObservable<T> source)
        {
            return source;
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/07_Zip/Answer/Answer_Lesson_7_Zip.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Answer_Lesson_7_Zip : MonoBehaviour
    {

        [SerializeField] private Text resultLabel;
        [SerializeField] private Button buttonLeft;
        [SerializeField] private Button buttonRight;

        private void Start()
        {
            var rightStream = buttonRight.OnClickAsObservable();
            var leftStream = buttonLeft.OnClickAsObservable();

            // Zipは複数のオペレータの値を１つずつまとめて流すオペレータである
            // 今回は2本のストリームを指定しているので、2本のストリームの両方のメッセージが1つずつ揃った時にメッセージを放流する
            // その際、第二引数に与えるデリゲートで値の加工が可能である（今回は値を使わないのでUnitを流している）
            //
            // また、Zipは内部にBufferいる点も重要である
            // 例えば以下のFirstを削除した状態で実行し、Leftを連続で3回押した後に、Rightを連続で3回押してみよう
            // (実行された回数がわかりやすいようにTextの更新を追記する形にしておく）
            leftStream
                .Zip(rightStream, (l, r) => Unit.Default)
                .First()
                .SubscribeToText(resultLabel, _ => resultLabel.text += "OK\n");
        }

    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/forSceneObject/SimpleMover.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx.Triggers;
using UniRx;
namespace UniRxWorkBook
{
    public class SimpleMover : MonoBehaviour
    {
        [SerializeField] private float speed = 10;

        private void Start()
        {
            this.UpdateAsObservable()
                .Subscribe(_ =>
                {
                    this.transform.position += new Vector3(speed, 0,0) * Time.deltaTime;
                });
        }
    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/01_Subscribe/Lesson_1_Subscribe.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

namespace UniRxWorkBook.Operators
{
    public class Lesson_1_Subscribe : MonoBehaviour
    {
        private void Start()
        {
            // _____()の部分を正しい形に置換してCubeが回転するようにしよう
            this.UpdateAsObservable()._____();
        }

        private void RotateCube()
        {
            this.transform.rotation = Quaternion.AngleAxis(1.0f, Vector3.up)*this.transform.rotation;
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/06_First/Answer/Answer_Lesson_6_First.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Answer_Lesson_6_First : MonoBehaviour
    {

        [SerializeField]
        private Text resultLabel;
        [SerializeField]
        private Button buttonA;
        [SerializeField]
        private Button buttonB;
        [SerializeField]
        private Button buttonC;

        private void Start()
        {
            var aStream = buttonA.OnClickAsObservable().Select(_ => "A");
            var bStream = buttonB.OnClickAsObservable().Select(_ => "B");
            var cStream = buttonC.OnClickAsObservable().Select(_ => "C");

            // First,FirstOrDefault を使うとこで一番最初のメッセージのみを通過させることができる
            // 一番最初のメッセージをを通過させた後、FirstはOnCompletedを放出する点に注意
            // 
            // FirstとFirstOrDefaultでは、メッセージが一度も発行されることなくDisposeされた時、
            // Firstは [OnError] を発行するが　FirstOrDefault　は [OnNext + OnCompleted] を発行するという違いがある。
            // 用途に合わせ、適切な方を選択するべきである
            Observable.Merge(aStream, bStream, cStream)
                .First()
                .SubscribeToText(resultLabel);
        }
    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/07_Zip/Lesson_7_Zip.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Lesson_7_Zip : MonoBehaviour
    {
        [SerializeField]
        private Text resultLabel;
        [SerializeField]
        private Button buttonLeft;
        [SerializeField]
        private Button buttonRight;

        private void Start()
        {
            var rightStream = buttonRight.OnClickAsObservable();
            var leftStream = buttonLeft.OnClickAsObservable();

            // _____を書き換え、LeftとRightが両方共最低１回ずつ押された時にTextが書き換わるようにしてみよう
            leftStream
                ._____()
                .First()
                .SubscribeToText(resultLabel, _ => "OK");
        }

    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/05_Buffer/Answer/Answer_Lesson_5_Buffer.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using System.Linq;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Answer_Lesson_5_Buffer : MonoBehaviour
    {

        [SerializeField]
        private Text resultLabel;
        [SerializeField]
        private Button buttonA;
        [SerializeField]
        private Button buttonB;
        [SerializeField]
        private Button buttonC;

        private void Start()
        {
            var aStream = buttonA.OnClickAsObservable().Select(_ => "A");
            var bStream = buttonB.OnClickAsObservable().Select(_ => "B");
            var cStream = buttonC.OnClickAsObservable().Select(_ => "C");

            // Buffer(n)で、過去n個分のメッセージをバッファすることができる
            // 何個溜まったら放出するかは第二引数で指定することができる（デフォルトは第一引数と同じ値がセットされる）
            //
            // Buffer(3)をBuffer(3,1)に変えて挙動の違いを確認してみよう
            Observable.Merge(aStream, bStream, cStream)
                .Buffer(3)
                .SubscribeToText(resultLabel, x => x.Aggregate((p, c) => p + c));
        }

    }
}

<|start_filename|>Assets/UniRxWorkBook/Operators/05_Buffer/Lesson_5_Buffer.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using System.Linq;
using UniRx;
using UniRxWorkBook;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Lesson_5_Buffer : MonoBehaviour
    {
        [SerializeField] private Text resultLabel;
        [SerializeField] private Button buttonA;
        [SerializeField] private Button buttonB;
        [SerializeField] private Button buttonC;

        private void Start()
        {
            var aStream = buttonA.OnClickAsObservable().Select(_ => "A");
            var bStream = buttonB.OnClickAsObservable().Select(_ => "B");
            var cStream = buttonC.OnClickAsObservable().Select(_ => "C");

            // _____()を書き換え、
            // 過去３回分の押されたボタンの履歴を表示してみよう
            // （３回押される度に更新される仕様で良い）
            Observable.Merge(aStream, bStream, cStream)
                ._____()
                .SubscribeToText(resultLabel, x => x);

            // IEnmerable<String>を１つのStringに合成するなら
            // strings.Aggregate((p, c) => p + c) とAggregateを使うと簡単に書ける
        }

    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/08_Repeat/Lesson_8_Repeat.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Lesson_8_Repeat : MonoBehaviour
    {
        [SerializeField]
        private Text resultLabel;
        [SerializeField]
        private Button buttonLeft;
        [SerializeField]
        private Button buttonRight;

        private void Start()
        {
            var rightStream = buttonRight.OnClickAsObservable();
            var leftStream = buttonLeft.OnClickAsObservable();

            // _____を書き換え、LeftとRightを交互に1回ずつ押した時にOKが表示されるようにしよう
            // 
            // First()を外すだけではLeftとRightを連打した時の挙動が怪しいのでダメである
            // 適切なオペレータをFirstの後ろに入れよう
            leftStream
                .Zip(rightStream, (l, r) => Unit.Default)
                .First()
                ._____()
                .SubscribeToText(resultLabel, _ => resultLabel.text += "OK\n");
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/Operators/08_Repeat/Answer/Answer_Lesson_8_Repeat.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UniRxWorkBook;
using UnityEngine.UI;

namespace UniRxWorkBook.Operators
{
    public class Answer_Lesson_8_Repeat : MonoBehaviour
    {

        [SerializeField] private Text resultLabel;
        [SerializeField] private Button buttonLeft;
        [SerializeField] private Button buttonRight;

        private void Start()
        {
            var rightStream = buttonRight.OnClickAsObservable();
            var leftStream = buttonLeft.OnClickAsObservable();

            // Repeat はOnCompletedが発行された時に、再度ストリームをSubscribeし直してくれるオペレータである
            // (流れてきた値を再現して繰り返すような機能ではないので注意）
            // 引数に数値を与えることで、指定した回数のみ動作させることもできる（デフォルトは無限動作）
            //
            // ！！！！Repeatは危険なオペレータであるということを認識しなくてはいけない！！！
            // 下手に使うと無限Subscribeを引き起こしフリーズを引き起こす可能性がある
            // 特にシーン遷移時など、オブジェクトが破棄されOnCompletedが発行されるタイミングには注意が必要である
            //
            // UniRxには、
            // 短期間にRepeatが連発した時にDisposeする　【RepeatSafe】
            // GameObjectがDisableになったタイミングでDisposeする　【RepeatUntilDisable】
            // GameObjectがDestroyされたタイミングでDisposeする　【RepeatUntilDestory】
            // という安全に配慮されたオペレータが用意されているので、こちらを使った方が良い場合が多い
            leftStream
                .Zip(rightStream, (l, r) => Unit.Default)
                .First()
                .RepeatUntilDestroy(gameObject)
                .SubscribeToText(resultLabel, _ => resultLabel.text += "OK\n");
        }
    }
}


<|start_filename|>Assets/UniRxWorkBook/StreamSources/5_ReactiveProperty/Lesson_5_ReactiveProperty.cs<|end_filename|>
﻿using System;
using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;
using UnityEngine.UI;

namespace UniRxWorkBook.StreamSources
{

    public class Lesson_5_ReactiveProperty : MonoBehaviour
    {
        [SerializeField]
        private Text subscribeText; //RPをSubscribeした結果を表示する
        [SerializeField]
        private Text updateText;    //Updat内でRPを監視して表示する
        [SerializeField]
        private Text toReactivePropertyText; //ストリームをRPに変換して表示する

        // ReactiveProperty(以下RP）は、普通の変数にSubjectの機能を付け加えたものである
        // 要するに、「Subscribeができる変数」である。挙動としてはBehaviorSubjectに似ている
        //
        // RPにはValueというプロパティが用意されており、このValueに値を代入することでOnNextを発行することができる
        // また、このValueはSubscribeなしで値にアクセス可能である（つまりSubscribeせずに普通の変数のようにReadができる）
        private ReactiveProperty<int> reactiveProperty = new ReactiveProperty<int>(0);

        private void Start()
        {

            //RPをSubscribeしてsubscribeTextに反映してみるパターン
            reactiveProperty.Subscribe(value => subscribeText.text = value.ToString());

            //-------------------

            //RPのValueを毎フレームReadしてupdateTextに反映してみるパターン
            this.UpdateAsObservable().Subscribe(_ =>
            {
                //RPのValueプロパティでいつでも最新の値が取得できる
                updateText.text = reactiveProperty.Value.ToString();
            });

            //-------------------

            //他のストリームをReactivePropertyに変換してみるパターン
            var interbalRP 
                = Observable.Timer(DateTimeOffset.Now,TimeSpan.FromSeconds(1)) //1秒毎にカウントアップ
                .ToReactiveProperty(0); //RPに変換(初期値は０）
            interbalRP.Subscribe(value => toReactivePropertyText.text = value.ToString())
                .AddTo(this); //GameObject破棄時にDisposeする

            //-------------------

            //RPの更新開始
            StartCoroutine(CountUpCoroutine());
        }

        //RPを１秒毎に更新する（カウントアップする）
        private IEnumerator CountUpCoroutine()
        {
            yield return new WaitForSeconds(1);
            while (true)
            {
                reactiveProperty.Value++;
                yield return new WaitForSeconds(1);
            }
        }


    }
}


<|start_filename|>Assets/UniRxWorkBook/StreamSources/4_AsyncSubject/Lesson_4_AsyncSubject.cs<|end_filename|>
﻿using UnityEngine;
using System.Collections;
using UniRx;
using UnityEngine.UI;

namespace UniRxWorkBook.StreamSources
{

    public class Lesson_4_AsyncSubject : MonoBehaviour
    {
        [SerializeField]
        private Button subscribeButton;
        [SerializeField]
        private Button onNextButton;
        [SerializeField]
        private Button onCompletedButton;
        [SerializeField]
        private Button resetButton;
        [SerializeField]
        private Text resultText;

        private int onNextCount = 0;

        // AsyncSubjectは非同期処理を模したSubjectである
        // OnNextが発行されるたびに最新の値をキャッシュし、OnCompletedの実行時に最新のOnNextを１つだけ通知する
        // （非同期で処理を回し、非同期処理完了を持って最後の結果を通知するイメージである）
        private AsyncSubject<int> asyncSubject;

        private void Start()
        {
            //BehaviorSubjectは初期値を設定できる
            asyncSubject = new AsyncSubject<int>();

            /*
            Subscribe後にOnNextを繰り返しても値が発行されず、OnCompletedを実行した際に初めてOnNextが通知されるところ確認しよう
            また、その時のOnNextの値は最後の値１つだけになっていることも確認しよう
            */

            // Subscribeボタンが押されたらSubjectをSubscribeしてresultTextに表示する
            subscribeButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (asyncSubject != null)
                {
                    asyncSubject.Subscribe(
                        time => resultText.text += time.ToString() + "　", //OnNext
                        () => resultText.text += "OnCompleted　"); //OnCompleted
                }
            });

            // OnNextボタンが押されたら今が何度目のOnNextであるかを発行する
            onNextButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (asyncSubject != null)
                {
                    asyncSubject.OnNext(++onNextCount);
                }
            });

            // OnCompletedボタンが押されたらOnCompletedを発行する
            onCompletedButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (asyncSubject != null)
                {
                    asyncSubject.OnCompleted();
                }
            });

            // Resetボタンが押されたら全体を初期化する
            resetButton.OnClickAsObservable().Subscribe(_ =>
            {
                if (asyncSubject != null)
                {
                    asyncSubject.OnCompleted();
                }
                asyncSubject = new AsyncSubject<int>();
                resultText.text = "";
                onNextCount = 0;
            });

        }


    }
}
