概述
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操作符
-
EveryUpdate 是事件的发布者。他会每帧会发送⼀个事件过来。
-
Subscribe 是事件的接收者,接收的是 EveryUpdate 发送的事件。
-
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);
});
});
}
}
}
最后
以上就是狂野小天鹅为你收集整理的UniRx入门纲要UniRx学习笔记的全部内容,希望文章能够帮你解决UniRx入门纲要UniRx学习笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复