UniRx入门纲要

UniRx学习笔记

定时器
 public class UniRxTimer : MonoBehaviour
    {
        private void Start()
        {
            Observable.Timer(TimeSpan.FromSeconds(5.0f))
                .Subscribe(_ => 
                {
                    Debug.Log("Do Sth...");
                });
        }
    }
独立的Update
 public class UpdateExample : MonoBehaviour
    {

        enum ButtonState
        {
            None,
            Clicked,
            DoubleClicked
        }
        private void Start()
        {
            ButtonState buttonState = ButtonState.None;
            bool buttonClicked = false;
            //监听鼠标左键
            Observable.EveryUpdate()
                .Subscribe(_ =>
                {
                    if (Input.GetMouseButtonDown(0))
                    {
                        print("left mouse button clicked");
                        buttonClicked = true;
                    }
                });
            //监听鼠标右键
            Observable.EveryUpdate()
               .Subscribe(_ =>
               {
                   if (Input.GetMouseButtonDown(1))
                   {
                       print("right mouse button clicked");
                       buttonClicked = true;
                   }
               });
          
            Observable.EveryUpdate()
                .Subscribe(_ =>
                {
                    //监听状态
                    if (buttonClicked && buttonState == ButtonState.None)
                    {
                        buttonState = ButtonState.Clicked;
                    }
                    print(buttonState);
                });
        }

    }

这种应用比较初级,随着学习的深入,会有更好的使用方法。

Observable.XXX().Subscribe() 是⾮常典型的 UniRx 格式。

只要理解什么意思就可以看懂⼤部分的 UniRx 的⽤法了。

⾸先解决词汇问题:

Observable: 可观察的,形容词,形容后边的词(Timer) 是可观察的,我们可以粗暴地把 Observable 后边的理解成发布者。

Timer: 定时器,名词,被 Observable 描述,所以是发布者,是事件的发送⽅。

Subscribe: 订阅,动词,订阅谁呢?当然是前边的 Timer,这⾥可以理解成订阅者,也就是事件的接

收⽅。

AddTo: 暂不⽤理解。

连起来则是:可被观察(监听)的.Timer().订阅()

顺下来应该是:订阅可被观察的定时器。

其概念关系很容易理解。

• Timer 是可观察的。

• 可观察的才能被订阅。

Observable.XXX().Subscribe();

可被观察(监听)的 XX,注册。

以上笔者从发布者和订阅者这个⻆度来进⾏的介绍,以便⼤家理解。

但是 UniRx 的侧重点,不是发布者和订阅者这两个概念如何使⽤,⽽是事件从发布者到订阅者之间的

过程如何处理。

所以两个点不重要,重要的是两点之间的线,也就是事件的传递过程。

 public class IntroExample : MonoBehaviour
    {

        private void Start()
        {
            Observable.EveryUpdate()//开启Update的事件监听
                .Where(_ => Input.GetMouseButtonDown(0))//进行一个鼠标是否抬起的判断
                .First()//只获取第一次的点击事件
                .Subscribe(_=> {//订阅/处理事件
                    print("MouseButton Down.");
                });
        }
    }
where操作符
  1. EveryUpdate 是事件的发布者。他会每帧会发送⼀个事件过来。

  2. Subscribe 是事件的接收者,接收的是 EveryUpdate 发送的事件。

  3. Where 则是在事件的发布者和接收者之间的⼀个过滤操作。会过滤掉不满⾜条件的事件。

    First操作符

    获取第一个通过的事件,First还可以传一个条件,所以上述代码可以不使用where,精简为:

    public class IntroExample : MonoBehaviour
        {
    
            private void Start()
            {
                Observable.EveryUpdate()//开启Update的事件监听
                    .First(_ => Input.GetMouseButtonDown(0))//只获取第一次的点击事件
                    .Subscribe(_=> {//订阅/处理事件
                        print("MouseButton Down.");
                    })
                    .AddTo(this);
            }
        }
    
UGUI的支持
/****************************************************
    文件:UIExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/9 17:8:53
	功能:UniRx对UGUI的支持
*****************************************************/

using UnityEngine;
using System;
using System.Collections;
using UniRx;
using UniRx.Triggers;
using UnityEngine.UI;


namespace UniRxLesson
{
    public class UIExample : MonoBehaviour
    {

        private void Start()
        {
            var button = transform.Find("Button").GetComponent<Button>();
            button.OnClickAsObservable()
                .Subscribe(_ =>
                {
                    print("button clicked");
                });
            var toggle = transform.Find("Toggle").GetComponent<Toggle>();
            toggle.OnValueChangedAsObservable()
                .Subscribe(on =>
                {
                    print(on);
                });
            var image = transform.Find("Image").GetComponent<Image>();

            image.OnBeginDragAsObservable()
                .Subscribe(_ =>
                {
                    print("Begin Drag");
                });
            image.OnDragAsObservable()
               .Subscribe(_ =>
               {
                   print("On Dragging");
               });
            image.OnEndDragAsObservable()
               .Subscribe(_ =>
               {
                   print("End Drag");
               });
        }
    }
}

使用UniRx可以非常方便的对UGUI进行事件发布和订阅,免去实现一些接口的工作。除此之外,UniRx还可以用在任何UNITY Event中。

响应式属性
/****************************************************
    文件:ReactivePropertyExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 10:31:39
	功能:UniRx的响应式属性示例
*****************************************************/

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


namespace UniRxLesson
{
    public class ReactivePropertyExample : MonoBehaviour
    {
        public ReactiveProperty<int> Age = new ReactiveProperty<int>(0);

        private void Start()
        {
            Age.Subscribe(age =>
            {
                print("inner recevied Age change"+age );
            });
            Age.Value = 10;//不管什么时候值发生改变,订阅改变事件的函数必定响应
        }
    }

    public class PersonView
    {
        ReactivePropertyExample mReactivePropertyExample = null;

        void Init()
        {
            mReactivePropertyExample.Age.Subscribe((age) =>
            {
                Debug.Log(age);
            });
        }
    }
}


MVP(Model-View-Presenter)
/****************************************************
    文件:EnemyExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 11:29:27
	功能:MVP简单示例
*****************************************************/

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;


namespace UniRxLesson
{
    public class EnemyExample : MonoBehaviour
    {
        EnemyModel enemy = new EnemyModel(200);
        private void Start()
        {
            var btn_Attack = transform.Find("Button").GetComponent<Button>();
            var txt_HPText = transform.Find("Text").GetComponent<Text>();

           
           
            btn_Attack.OnClickAsObservable()
                .Subscribe(_ =>
                {
                    enemy.HP.Value -= 99;
                });
            enemy.HP.SubscribeToText(txt_HPText);

           /* enemy.isDead
                .Where(isDead => isDead)
               
                .Subscribe(_ =>
                {
                    btn_Attack.interactable = false;
                });*/

            enemy.isDead
               //.Where(isDead => isDead)
               .Select(isDead => !isDead)
               .SubscribeToInteractable(btn_Attack);
               
              //两种方法都行,其中Select()函数是个转换,转换的结果直接赋值到subscribeToInteractable中



        }

    }

    public class EnemyModel
    {
        public LongReactiveProperty HP;
        public IReadOnlyReactiveProperty<bool> isDead;

        public EnemyModel(long initHP)
        {
            HP = new LongReactiveProperty(initHP);
            isDead = HP.Select(hp => hp <= 0).ToReactiveProperty();

        }


    }
}


在 Unity 中,我们把 Scene 中的 GameObject 当做视图层,这些是在 Unity 的 Hierarchy 中定义的。

展示/控制层在 Unity 初始化时将视图层绑定。

SubscribeToText and SubscribeToInteractable 都是简洁的类似绑定的辅助函数。虽然这些⼯工具很简 单,但是⾮非常实⽤用。

在 Unity 中使⽤用开发体验⾮非常平滑,性能也很好,重要的是让你的代码更更简洁。

View -> ReactiveProperty -> Model -> RectiveProperty - View 完全⽤用响应式的⽅方式连接。UniRx 提供 了了所有的适配⽅方法和类,不不过其他的 MVVM (or MV*) 框架也可以使⽤用。UniRx/ReactiveProperty 只是 一个简单的⼯工具包。

Merge操作符

merge操作符用于合并多个事件流,相当于同时订阅两个事件流,只要任何一个事件流发生,订阅的函数和事件就会被执行。

/****************************************************
    文件:MergeExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 14:34:18
	功能:Merge操作符的使用
*****************************************************/

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

namespace UniRxLesson
{
    public class MergeExample : MonoBehaviour
    {
        private void Start()
        {
            var leftClickedEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0));
            var rightClickedEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(1));

            Observable.Merge(leftClickedEvents, rightClickedEvents)
                .Subscribe(_ =>
                {
                    print("mouse Clicked");
                });
        }
    }
}


用Merge和First做一个UI按钮事件锁
/****************************************************
    文件:PanelEventLockExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 14:48:52
	功能:实现一个UI界面按钮锁的功能
*****************************************************/

using UnityEngine;
using System;
using UniRx;
using UnityEngine.UI;

namespace UniRxLesson
{
    public class PanelEventLockExample : MonoBehaviour
    {
        private void Start()
        {
            var btn_A = transform.Find("ButtonA").GetComponent<Button>();
            var btn_B = transform.Find("ButtonB").GetComponent<Button>();
            var btn_C = transform.Find("ButtonC").GetComponent<Button>();

            var aEvents = btn_A.OnClickAsObservable();
            var bEvents = btn_B.OnClickAsObservable();
            var cEvents = btn_C.OnClickAsObservable();

            Observable.Merge(aEvents, bEvents, cEvents)
                .First()
                .Subscribe(_ =>
                {
                    print("Button clicked");
                    Observable.Timer(TimeSpan.FromSeconds(1.0f))
                    .Subscribe(__ =>
                    {
                        gameObject.SetActive(false);
                    });
                });
        }
    }
}


Select的选择操作(操作后返回一个泛型)
 private void Start()
        {
            var btn_A = transform.Find("ButtonA").GetComponent<Button>();
            var btn_B = transform.Find("ButtonB").GetComponent<Button>();
            var btn_C = transform.Find("ButtonC").GetComponent<Button>();

            var aEvents = btn_A.OnClickAsObservable().Select(_ => "A");
            var bEvents = btn_B.OnClickAsObservable().Select(_ => "B");
            var cEvents = btn_C.OnClickAsObservable().Select(_ => "C");

            Observable.Merge(aEvents, bEvents, cEvents)
                .First()
                .Subscribe(btnID =>//用btnID接收事件经过Select操作后的返回值
                {
                    print("Button clicked"+btnID);
                    Observable.Timer(TimeSpan.FromSeconds(1.0f))
                    .Subscribe(__ =>
                    {
                        gameObject.SetActive(false);
                    });
                });
        }

第二章Unity和UniRx

UGUI的增强
/****************************************************
    文件:UGUIExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 15:39:12
	功能:UniRx对unity UGUI的增强
*****************************************************/

using UnityEngine;
using UniRx;
using UnityEngine.UI;

namespace UniRxLesson
{


    public class UGUIExample : MonoBehaviour
    {
        [SerializeField] Button mButton;
        [SerializeField] Toggle mToggle;
        [SerializeField] Scrollbar mScrollbar;
        //[SerializeField] ScrollRect mScrollRect;
        [SerializeField] Slider mSlider;
        [SerializeField] InputField mInputField;
        [SerializeField] Text mText;
        void Start()
        {
            mButton.OnClickAsObservable().Subscribe(_ => Debug.Log("On Button Clicked"));
            mToggle.OnValueChangedAsObservable().Subscribe(on => Debug.Log("Toggle " +
            on));
            
            mScrollbar.OnValueChangedAsObservable().Subscribe(scrollValue =>
            Debug.Log("Scrolled " + scrollValue));
           // mScrollRect.OnValueChangedAsObservable().Subscribe(scrollValue =>
            //Debug.Log("Scrolled " + scrollValue));
            mSlider.OnValueChangedAsObservable().Subscribe(sliderValue =>
            Debug.Log("Slider Value " + sliderValue));
            mInputField.OnValueChangedAsObservable().Subscribe(inputText =>
            Debug.Log("Input Text: " + inputText));
            //mInputField.OnEndEditAsObservable().Subscribe(result =>
            //Debug.Log("Result :" + result));

            //mInputField.OnEndEditAsObservable().SubscribeToText(mText);
            mInputField.OnValueChangedAsObservable().SubscribeToText(mText);//一个绑定操作,非常方便

        }

    }
}

Unity ⽣命周期 与 Trigger

对于 Unity 的 Observable 增强,我们在第⼀章就接触过了。

Observable.EveryUpdate() 就是⽀持的 Unity 的 API。

单单 Update 就是⽀持⾮常多细分类型的 Update 事件捕获。

Observable.EveryFixedUpdate().Subscribe(_ => {}); 

Observable.EveryEndOfFrame().Subscribe(_ => {}); 

Observable.EveryLateUpdate().Subscribe(_ => {}); 

Observable.EveryAfterUpdate().Subscribe(_ => {}); 

除了 Update 还⽀持其他的事件,⽐如 ApplicationPause,Quit 等。

Observable.EveryApplicationPause().Subscribe(paused => {}); 

Observable.EveryApplicationFocus().Subscribe(focused => {}); 

Observable.EveryApplicationQuit().Subscribe(_ => {}): 

学习了以上这些,就不⽤再去创建⼀个单例类去实现⼀个诸如“应⽤程序退出事件监听”这种逻辑了。

命名⼏⾏代码就可以搞定的事情,何必再去创建⼀个类去搞定?

Trigger 简介

Observable.EveryUpdate() 这个 API 有的时候在某个脚本中实现,需要绑定 MonoBehaviour 的⽣命周 期(主要是 OnDestroy),当然也有的时候是全局的,⽽且永远不会被销毁的。

需要绑定 MonoBehaviour ⽣命周期的 EveryUpdate。只需要⼀个 AddTo 就可以进⾏绑定了。⾮常简

单,代码如下。

Observable.EveryUpdate() 

.Subscribe(_ => {}) 

.AddTo(this); 

但其实有更简洁的实现:

this.UpdateAsObservable() 

.Subscribe(_ => {}); 

这种类型的 Observable 是什么呢?

答案是:Trigger,即触发器。

字如其意,很容易理解。

Trigger 类型的关键字

触发器,字如其意,是当某个事件发⽣时,则会将该事件发送到 Subscribe 函数中,⽽这个触发器,

本身是⼀个功能脚本,这个脚本挂在 GameObject 上,来监听 GameObject 的某个事件发⽣,事件发

⽣则会回调给注册它的 Subscribe 中。

触发器的操作和其他的事件源 (Observable) 是⼀样的,都⽀持 Where、First、Merge 等操作符。

Trigger 类型的 Observable 和我们之前讲的所有的 Observable 在表现上有⼀点不⼀样:

\1. Trigger ⼤部分都是都是 XXXAsObsrevable 命名形式的。

\2. 在使⽤ Trigger 的 GameObject 上都会挂上对应的 Observable XXXTrigger.cs 的脚本。

Trigger 在此之前我们是接触过的。

AddTo() 这个 API 其实是封装了⼀种 Trigger: ObservableDestroyTrigger。

2顾名思义,就是当 GameObject 销毁时获取事件的⼀个触发器。

⼀般的 Trigger 都会配合 MonoBehaviour ⼀起使⽤。

⽐如 ObservableDestroyTrigger 的使⽤代码如下:

this.OnDestroyAsObservable() 

.Subscribe(_ => {}); 

除了 Destroy 还有⾮常多的 Trigger。

⽐如各种细分类型的 Update:

this.FixedUpdateAsObservable().Subscribe(_ => {}); 

this.LateUpdateAsObservable().Subscribe(_ => {}); 

this.UpdateAsObservable().Subscribe(_ => {}); 

还有各种碰撞的 Trigger:

this.OnCollisionEnterAsObservable(collision => {}); 

this.OnCollisionExitAsObservable(collision => {}); 

this.OnCollisionStayAsObservable(collision => {}); 
// 同样 2D 的也⽀持 

this.OnCollision2DEnterAsObservable(collision2D => {}); 

this.OnCollision2DExitAsObservable(collision2D => {}); 

this.OnCollision2DStayAsObservable(collision2D => {}); 

⼀些脚本的参数监听:

this.OnEnableAsObservable().Subscribe(_ => {}); 

this.OnDisableAsObservable().Subscribe(_ => {}); 

3.除了 MonoBehaviour ,Trigger 也⽀持了其他组件类型,⽐如 RectTransform、Transform、

UIBehaviour 等等。这⾥不再赘述。

详情可以查看 ObservableTriggerExtensions.cs 和 ObervableTriggerExtensions.Component.cs 中的 API。

UI Trigger

在项⽬中⽤的⽐较多的⼏个 Trigger:

mImage.OnBeginDragAsObservable().Subscribe(dragEvent => {}); 

mGraphic.OnDragAsObservable().Subscribe(dragEvent => {}); 

mText.OnEndDragAsObservable().Subscribe(dragEvent => {}); 

mImage.OnPointerClickAsObservable().Subscribe(clickEvent => {});
UniRx对协程的支持

UniRx 对 Unity 的 Coroutine 也提供⽀持,可以将⼀个 Coroutine 转化为事件源(Observable)

/****************************************************
    文件:RxCoroutineTest.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 17:36:21
	功能:UniRx对协程的支持
*****************************************************/

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

namespace UniRxLesson
{
    public class RxCoroutineTest : MonoBehaviour
    {
        IEnumerator CoroutineA()
        {
            yield return new WaitForSeconds(1.0f);
            Debug.Log("A");
        }
        void Start()
        {
            Observable.FromCoroutine(_ => CoroutineA())
            .Subscribe(_ =>
            {
                // do something
                print("666");
            }).AddTo(this);
        }
    }
}

当然也⽀持将 Observable 转化为⼀个 Coroutine 中的 yield 对象

⽐如:

/****************************************************
    文件:Rx2YieldTest.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/10 17:40:15
	功能: Observable 转化为⼀个 Coroutine 中的 yield 对象
*****************************************************/

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


namespace UniRxLesson
{


    public class Rx2YieldTest : MonoBehaviour
    {
        IEnumerator Delay1Second()
        {
            yield return
            Observable.Timer(TimeSpan.FromSeconds(1.0f)).ToYieldInstruction();
            Debug.Log("B");
        }
        void Start()
        {
            StartCoroutine(Delay1Second());
        }
    }
}
WhenAll操作符
WhenAll在协程上的用法
/****************************************************
    文件:WhenAllCoroutineExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 9:39:56
	功能:UniRx when all操作符
*****************************************************/

using UnityEngine;
using UniRx;
using System.Collections;

namespace UniRxLesson
{


    public class WhenAllCoroutineExample : MonoBehaviour
    {
        IEnumerator A()
        {
            yield return new WaitForSeconds(1.0f);
            Debug.Log("A");
        }
        IEnumerator B()
        {
            yield return new WaitForSeconds(2.0f);
            Debug.Log("B");
        }
        void Start()
        {
            var aStream = Observable.FromCoroutine(_ => A());
            var bStream = Observable.FromCoroutine(_ => B());
            Observable.WhenAll(aStream, bStream)
            .Subscribe(_ =>
            {
                print("C");
            }).AddTo(this);
        }
    }
}
WhenAll在按钮点击上的用法
/****************************************************
    文件:ButtonAllClickedOnce.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 9:44:40
	功能:所有按钮一次点击后事件
*****************************************************/

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

namespace UniRxLesson
{
    public class ButtonAllClickedOnce : MonoBehaviour
    {
        [SerializeField] Button mButtonA;
        [SerializeField] Button mButtonB;
        [SerializeField] Button mButtonC;
        void Start()
        {
            var aStream = mButtonA.OnClickAsObservable().First();
            var bStream = mButtonB.OnClickAsObservable().First();
            var cStream = mButtonC.OnClickAsObservable().First();

            Observable.WhenAll(
            aStream,
            bStream,
            cStream)
            .Subscribe(_ =>
            {
                Debug.Log("clicked");
                
            }).AddTo(this);
        }
    }
}


事件流的结束 OnCompleted
/****************************************************
    文件:onCompletedExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 10:40:13
	功能:事件流的结束
*****************************************************/

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


namespace UniRxLesson
{
    public class onCompletedExample : MonoBehaviour
    {
        private void Start()
        {
            /*Observable.Timer(TimeSpan.FromSeconds(1.0f)).Subscribe(_=> print("OnNext after 1 Sec "),
                ()=> print("onComplete")
                );*/
            //Observable.EveryUpdate().First().Subscribe(_ =>
            //{
            //    Debug.Log("OnNext:First");
            //}, () =>
            //{
            //    Debug.Log("OnCompleted");
            //}).AddTo(this);
            Observable.FromCoroutine(A)
                 .Subscribe(_ =>
                 {
                     Debug.Log("OnNext:");
                 }, () =>
                 {
                     Debug.Log("OnCompleted:");
                 });

        }
        IEnumerator A()
        {
            yield return new WaitForSeconds(2.0f);
        }
    }
}


协程有Oncompleted事件,EveryUpdate没有,只有OnNext事件,默认Subscribe后面触发的是OnNext事件。正因为有OnCompleted事件,才有WhenAll操作。

Start:让多线程更简单

多线程,是作为⾼级开发者必须具备的⼀种技术。了解了多线程可以让我们充分利⽤多核移动端的计

算优势,也可以让我们的游戏体验更平滑。

在 Unity 中我们⼀般⽤ Thread.Start 开启⼀个线程。当逻辑⾮常复杂的时候多线程⾮常难以管理。

⽽ UniRx 改善了这⼀种状况。

⼀个”当所有线程运⾏完成后,在主线程执⾏某个任务” 这个功能,使⽤ UniRx 实现如下:

/****************************************************
    文件:ThreadExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 11:22:17
	功能:UniRx管理多线程
*****************************************************/

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

namespace UniRxLesson
{

    public class ThreadExample : MonoBehaviour
    {
        private void Start()
        {
            var threadAStream = Observable.Start(() =>
            {
                Thread.Sleep(TimeSpan.FromSeconds(1.0f));
                return 10;
            });
            var threadBStream = Observable.Start(() =>
            {
                Thread.Sleep(TimeSpan.FromSeconds(3.0f));
                return 10;
            });

            Observable.WhenAll(threadAStream, threadBStream)
                .ObserveOnMainThread()
                .Subscribe(results => print(results[0] + ":" + results[1]));
        }
    }
}

3 秒后,输出的结果如下:

10:10

这⾥有两个新的 API,⼀个是 Observable.Start,这个 API 意思开启⼀个线程流。

ObserveOnMainThread,意思是把 WhellAll 结果转到主线程上。这样 Subscribe ⾥的回调就可以使⽤ Unity 的 API 了(Unity 的很多 API 不可以在其他线程中使⽤ )。

使⽤ UniRx 来处理线程逻辑⾮常简单。

线程和 Coroutine (协程)都可以使⽤ WhenAll 这种操作符。

ObservableWWW 优雅的⽹络请求操作

以往我们不管使⽤ WWW 还是 UnityWebRequest 都要使⽤ Coroutine 去驱动。

但是使⽤协程写出来的代码,需要⼀堆判断,导致代码⾮常混乱。

⽽ UniRx 则是以以往⼀样简练的⻛格提供了对⽹络请求的⽀持。

代码如下:

/****************************************************
    文件:WWWExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 11:49:55
	功能:UniRx优雅的网络请求操作
*****************************************************/

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

namespace UniRxLesson
{
    public class WWWExample : MonoBehaviour
    {
        private void Start()
        {
            ObservableWWW.Get("baidu.com")
                .Subscribe(responseText =>
                {
                    print(responseText.Substring(0, 10));
                },
                e=> 
                {
                    Debug.LogError(e);
                });
        }
    }
}

支持whenAll操作:
/****************************************************
    文件:WWWWhenAllExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 11:55:21
	功能:WWW 中的WhenALL操作
*****************************************************/

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

namespace UniRxLesson
{
    public class WWWWhenAllExample : MonoBehaviour
    {

        private void Start()
        {
            var aStream = ObservableWWW.Get("baidu.com");

            var bStream = ObservableWWW.Get("sikiedu.com");

            Observable.WhenAll(aStream, bStream)
                .Subscribe(responseText =>
                {
                    print(responseText[0].Substring(0, 10));
                    print(responseText[1].Substring(0, 100));

                });
        }
    }
}


下载文件
/****************************************************
    文件:ProgressExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 12:24:0
	功能:用UniRx下载文件,并且显示进度
*****************************************************/

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

namespace UniRxLesson
{
    public class ProgressExample : MonoBehaviour
    {
       

        private void Start()
        {
            var progressObserable = new ScheduledNotifier<float>();
            ObservableWWW.GetAndGetBytes("http://liangxiegame.com/media/QFramework_v0.0.9.unitypackage", progress: progressObserable)
                .Subscribe(bytes =>
                {

                },
                e=>
                {
                    Debug.Log(e);
                });

            progressObserable.Subscribe(progress =>
            {
                Debug.LogFormat("进度为:{0}", progress);
            });
        }
    }
}

ReactiveCommand

我们先来看下 ReactiveCommand 定义 :

public interface IReactiveCommand<T> : IObservable<T> 

{ 

IReadOnlyReactiveProperty<bool> CanExecute { get; } 

bool Execute(T parameter); 

}

它提供了两个 API:

• CanExecte

• Execute

Execute ⽅法是被外部调⽤的。也就是这个 Command 的执⾏。这个很容易理解,只要外部调⽤的

Execute 就会执⾏。

⽽ CanExecute 则是内部使⽤的,并且对外部提供了只读访问。

当 CanExecute 为 false 时,在外部调⽤ Execute 则该 Command 不会被执⾏。

当 CanExecute 为 true 时,在外部调⽤ Execute 则该 Command 会被执⾏。

是什么决定 CanExecute 为 false 或 true 呢?

答案是其他的 Observable。

新创建的 ReactiveCommand 默认 CanExecute 为 true。

/****************************************************
    文件:ReactiveCommandExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 14:45:40
	功能:ReactiveCommand示例
*****************************************************/

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


namespace UniRxLesson
{
    public class ReactiveCommandExample : MonoBehaviour
    {
        private void Start()
        {
            var reactiveCommand = new ReactiveCommand();
            reactiveCommand.Subscribe(_ =>
            {
                print("执行");
            });
            reactiveCommand.Execute();
            reactiveCommand.Execute();
            reactiveCommand.Execute();
        }
    }
}

输出的结果是:

执行

执行

执行

⾮常地简单,只要调⽤ Execute。command 就会通知 Subscribe 的回调(因为 CanExecute 为 true)。

CanExecute 的开启关闭是由 Observable (事件源)决定的。

/****************************************************
    文件:MouseDownUPExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 14:49:9
	功能:熟悉ReactiveCommand中的CanExcuse属性
*****************************************************/

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

namespace UniRxLesson
{
    public class MouseDownUPExample : MonoBehaviour
    {
        private void Start()
        {
            var leftMouseDownStream = this.UpdateAsObservable().
               Where(_ => Input.GetMouseButtonDown(0))
               .Select(_ => true);
            var leftMouseUPStream = this.UpdateAsObservable().
              Where(_ => Input.GetMouseButtonUp(0))
              .Select(_ => false);

            var isMouseDown = Observable.Merge(leftMouseDownStream, leftMouseUPStream);

            var reactiveCommand = new ReactiveCommand(isMouseDown, false);
            reactiveCommand.Subscribe(x =>
            {
                print("reactiveCommand"+x.ToString());
            });
            this.UpdateAsObservable().Subscribe(_ => reactiveCommand.Execute());

        }
    }
}

在上面的示例代码中,鼠标按下事件通过Select操作符让其Observable返回一个true,鼠标抬起事件通过Select操作符让其Observable事件源返回一个false。用Merge操作符将两个事件源合并成一个事件源作为ReactiveCommand的监听事件源,所以reactiveCommand中的CanExcuse属性则有合并后的事件源isMouseDown的返回值决定。当鼠标按下时,返回true,每帧调用的Excuse函数会被执行,输出字符串,抬起时,每帧调用的Excuse函数不会被执行,就不会在控制台输出字符串。

ReactiveCollection 与 ReactiveDictionary
ReactiveCollection

ReactiveCollection 类似于 List。

我们可以使⽤如下的操作符:

ObserverAdd // 当 新的 Item 添加则会触发

ObserverRemove // 删除

ObserverReplace // 替换(Update)

ObserverMove // 移动

ObserverCountChanged // 数量有改变(Add、Remove)

ReactiveCollection 示例代码:

/****************************************************
    文件:ReactiveCollectionExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 15:36:55
	功能: ReactiveCollection示例
*****************************************************/

using UnityEngine;
using UniRx;

namespace UniRxLesson
{
    public class ReactiveCollectionExample : MonoBehaviour
    {
        ReactiveCollection<int> mAges = new ReactiveCollection<int> { 1,2,3,4,5};
        void Start()
        {
            mAges.ObserveAdd()
             .Subscribe(addAge =>
             {
                 Debug.LogFormat("add:{0}",addAge);
             });
            mAges.ObserveRemove()
             .Subscribe(removedAge =>
             {
                 Debug.LogFormat("remove:{0}",removedAge);
             });
            mAges.ObserveCountChanged()
             .Subscribe(count =>
             {
                 Debug.LogFormat("count:{0}",count);
             });
            foreach (var age in mAges)
            {
                Debug.Log(age);
            }
            mAges.Add(6);
            mAges.Remove(2);
        }
    }
}

输出结果为

1

2

3

4

5

add:Index:5 Value:6

count:6

remove:Index:1 Value:2

count:5

ReactiveDictionary

ReactiveDictionary 功能与 Dictionary ⼀样。

同样地,它⽀持了⼏个操作符:

ObserverAdd // 当 新的 Item 添加则会触发

ObserverRemove // 删除

ObserverReplace // 替换(Update)

ObserverMove // 移动

ObserverCountChanged // 数量有改变(Add、Remove)

示例代码如下:

/****************************************************
    文件:ReactiveDictionaryExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 15:40:0
	功能:ReactiveDictionary示例
*****************************************************/

using UniRx;
using UnityEngine;
namespace UniRxLesson
{
    public class ReactiveDictionaryExample : MonoBehaviour
    {
        private ReactiveDictionary<string, string> mLanguageCode = new
        ReactiveDictionary<string, string>(){ {"en","英语"},{"cn","中⽂"}};
        // Use this for initialization
        void Start()
        {
            mLanguageCode.ObserveAdd()

             .Subscribe(addedLanguage =>
             {
                 Debug.LogFormat("add:{0}", addedLanguage.Value);
             });
            mLanguageCode.ObserveRemove()
             .Subscribe(removedLanguage =>
             { Debug.LogFormat("remove:{0}", removedLanguage.Value); });
            mLanguageCode.ObserveCountChanged()
          .Subscribe(count =>
         {
             Debug.LogFormat("count:{0}", count);
         });
            mLanguageCode.Add("jp", "⽇语");
            mLanguageCode.Remove("en");
        }
    }
}

输出结果为

add:⽇语

count:3

remove:英语

count:2

加载场景 AsyncOperation

我们在异步加载资源或者异步加载场景的时候往往会⽤到 AsyncOperation。

UniRx 对 AsyncOperation 做了⽀持。使得加载操作可以很容易地监听加载进度。

示例代码如下:

/****************************************************
    文件:AsyncOperationExample.cs
	作者:Paul   邮箱: 794451358@qq.com
    日期:2019/10/11 15:48:35
	功能:用UniRx进行异步操作
*****************************************************/

using UnityEngine;
using UniRx;
using UnityEngine.SceneManagement;


namespace UniRxLesson
{
    public class AsyncOperationExample : MonoBehaviour
    {
        private void Start()
        {
            var progressObserable = new ScheduledNotifier<float>();
            SceneManager.LoadSceneAsync(0).AsAsyncOperationObservable(progress: progressObserable).Subscribe(asyncOperation =>
            {
                print("load Done");

                asyncOperation.allowSceneActivation = true;
                Resources.LoadAsync<GameObject>("TestCanvas").AsAsyncOperationObservable(progressObserable).Subscribe(resourceRequest =>
                {
                    GameObject.Instantiate(resourceRequest.asset);
                });
                progressObserable.Subscribe(progress =>
                {
                    Debug.LogFormat("已经加载了{0}", progress);
                });
            });
        }

    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

int_Paul

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值