计时
public class UniRxTimerExample : MonoBehaviour
{
private void Start()
{
Observable.Timer(TimeSpan.FromSeconds(5.0f))
.Subscribe(_ =>
{
Debug.Log("do something");
});
}
}
帧事件
// 监听鼠标左键
Observable.EveryUpdate()
.Subscribe(_ =>
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("left mouse button clicked");
buttonClicked = true;
}
});
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(_ => {});
操作符
where 是⼀个过滤的操作,过滤掉不满⾜条件的事件。类似于if
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonUp(0))
.Subscribe(_ =>
{
// do something
}).AddTo(this);
First 获取第⼀个通过的事件.如果你只想条件只执行一次
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonUp(0))
.First()
.Subscribe(_ => { /* do something */ })
.AddTo(this);
Observable.EveryUpdate()
.First(_ => Input.GetMouseButtonUp(0))
.Subscribe(_ => { /* do something */ })
.AddTo(this);
Take
// 双击判断
//用了一个selectMany的技巧把传来的无效参数重新转换成一个事件源
Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0))
.SelectMany(_ =>Observable.EveryUpdate().Take(30).Where(___=>Input.GetMouseButtonDown(0)))
.Subscribe(_=>print("double clicked"));
单击后拿取后面30个update元素再进行单击过滤
Select
Observable.EveryUpdate().Where(_=>Input.GetMouseButtonDown(0)). Select((_, index) =>index)
.Subscribe(_ => print("点击了"+_+"次"));
SelectMany
public class SelectMany : MonoBehaviour
{
void Start()
{
var a = Observable.FromCoroutine(A);
var b = Observable.FromCoroutine(B);
var c = Observable.FromCoroutine(C);
//对协程执行顺序进行任意组合
//原理是协程(可观察的)默认只会在结束后被观察到一次,A结束后被转成了B,B结束后又转成了C ,全部观察完后 输出end
a.SelectMany(b.SelectMany(c)).Subscribe(_ => print("end"));
//a.SelectMany(sa=> {
// print("a convered to b");
// return b;
//}).Subscribe(_=>print("end"));
//todo怎么组合带参数的协程?
}
IEnumerator A()
{
yield return new WaitForSeconds(1.0f);
print("A");
}
IEnumerator B()
{
yield return new WaitForSeconds(1.0f);
print("B");
}
IEnumerator C()
{
yield return new WaitForSeconds(1.0f);
print("C");
}
}
AddTo
添加到Unity 的 GameObject 或者 MonoBehaviour。GameObject 和 MonoBehaviour 可以获取到 OnDestroy 事件。也就是 GameObject 或者MonoBehaviour 的销毁事件.获取之后⽤来 进⾏与 UniRx 进⾏销毁事件的绑定,也就是当 GameObject 或者 MonoBehaviour 被销毁时,同样去销毁正在进⾏的 UniRx 任务。 当 GameObject 销毁时,就会调⽤ IDisposable 的 OnDispose 这个⽅法。
Observable.Timer(TimeSpan.FromSeconds(1.0f)
.Subscribe()
.AddTo(this);
SubscribeToInteractable / SubscribeToText
ugui 组件订阅,当发布者修改数据时,组件更新
MySlider.OnValueChangedAsObservable()
.SubscribeToText(MyText, x => Math.Round(x, 2).ToString());
MyToggle.OnValueChangedAsObservable().SubscribeToInteractable(MyButton);
Trigger
.1. Trigger ⼤部分都是都是 XXXAsObsrevable 命名形式的。
2. 在使⽤ Trigger 的 GameObject 上都会挂上对应的 Observable XXXTrigger.cs 的脚本除了 MonoBehaviour ,Trigger 也⽀持了其他组件类型,⽐如 RectTransform、Transform、UIBehaviour 等等。
this.OnDestroyAsObservable()
.Subscribe(_ => {});
各种细分类型的 Update:
this.FixedUpdateAsObservable().Subscribe(_ => {});
this.LateUpdateAsObservable().Subscribe(_ => {});
this.UpdateAsObservable().Subscribe(_ => {});
还有各种碰撞的 Trigger:
this.OnCollisionEnterAsObservable().Subscribe(collision => {});
this.OnCollisionExitAsObservable().Subscribe(collision => {});
this.OnCollisionStayAsObservable().Subscribe(collision => {});
// 同样 2D 的也⽀持
this.OnCollision2DEnterAsObservable().Subscribe(collision2D => {});
this.OnCollision2DExitAsObservable().Subscribe(collision2D => {});
this.OnCollision2DStayAsObservable().Subscribe(collision2D => {});
⼀些脚本的参数监听:
this.OnEnableAsObservable().Subscribe(_ => {});
this.OnDisableAsObservable().Subscribe(_ => {});
UIBehaviour Triggle
[SerializeField] Button mButton;
[SerializeField] Toggle mToggle;
[SerializeField] Scrollbar mScrollbar;
[SerializeField] ScrollRect mScrollRect;
[SerializeField] Slider mSlider;
[SerializeField] InputField mInputField;
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));
}
Subscribe
Text resultText = GetComponent<Text>();
mInputField.OnValueChangedAsObservable().SubscribeToText(resultText);
mImage.OnBeginDragAsObservable().Subscribe(dragEvent => {});
mGraphic.OnDragAsObservable().Subscribe(dragEvent => {});
mText.OnEndDragAsObservable().Subscribe(dragEvent => {});
mImage.OnPointerClickAsObservable().Subscribe(clickEvent => {});
UnityEvent
UnityEvent mEvent;
void Start()
{
mEvent.AsObservable()
.Subscribe(_ =>
{
// process event
});
}
响应式属性ReactiveProperty
当任何时候,Age 的值被设置,就会通知所有 Subscribe 的回调函数。
⽽ Age 可以被 Subscribe 多次的。
并且同样⽀持 First、Where 等操作符。
public class ReactivePropertyExample : MonoBehaviour
{
public IntReactiveProperty Age = new IntReactiveProperty(0);
void Start()
{
Age.Subscribe(age =>
{
Debug.Log("inner received age changed");
});
Age.Value = 10;
}
}
public class PersonView
{
ReactivePropertyExample mReactiveProeprtyExample;
void Init()
{
mReactiveProeprtyExample.Age.Subscribe((age) =>
{
Debug.Log(age);
});
}
}
public enum Mode
{
Add,
Edit
}
public ReactiveProperty<Mode> Mode = new ReactiveProperty<Mode>(UniRxLesson.Mode.Add);
mInputCtrl.Mode.Subscribe(mode =>
{
if (mode == Mode.Add)
{
mEvenMaskObj.SetActive(false);
}
else
{
mEvenMaskObj.SetActive(true);
}
});
MVC模式
public class EnemyExample : MonoBehaviour
{
[SerializeField] EnemyModel mEnemy = new EnemyModel(200);
void Start()
{
var attackBtn = transform.Find("Button").GetComponent<Button>();
var HPText = transform.Find("Text").GetComponent<Text>();
attackBtn.OnClickAsObservable()
.Subscribe(_ =>
{
mEnemy.HP.Value -= 99;
});
mEnemy.HP.SubscribeToText(HPText);
mEnemy.IsDead
.Where(isDead => isDead)
.Select(isDead => !isDead)
.SubscribeToInteractable(attackBtn);
}
}
// Model
public class EnemyModel
{
public ReactiveProperty<long> HP;
public IReadOnlyReactiveProperty<bool> IsDead;
public EnemyModel(long initialHP)
{
HP = new ReactiveProperty<long>(initialHP);
IsDead = HP.Select(hp => hp <= 0).ToReactiveProperty();
}
}
Merge
UniRx 可以开启两个或多个事件流。并使⽤ Merge 进⾏事件流的合并,比如实现⿏标左键或右键点击时都会进⾏处理
var leftMouseClickStream = Observable.EveryUpdate().Where(_ =>
Input.GetMouseButtonDown(0));
var rightMouseClickStream = Observable.EveryUpdate().Where(_ =>
Input.GetMouseButtonDown(1));
Observable.Merge(leftMouseClickStream, rightMouseClickStream)
.Subscribe(_ =>
{
// do something
});
Coroutine
public class Observable2YieldExample : MonoBehaviour
{
IEnumerator Delay1Second()
{
yield return Observable.Timer(TimeSpan.FromSeconds(1.0f)).ToYieldInstruction();
Debug.Log("delay 1 seconds");
}
void Start()
{
StartCoroutine(Delay1Second());
}
}
WhenAll
public class CoroutineSpawnExample : MonoBehaviour
{
IEnumerator A()
{
yield return new WaitForSeconds(1.0f);
Debug.Log("A");
}
IEnumerator B()
{
yield return new WaitForSeconds(1.0f);
Debug.Log("B");
}
void Start()
{
var aStream = Observable.FromCoroutine(_ => A());
var bStream = Observable.FromCoroutine(_ => B());
Observable.WhenAll(aStream, bStream)
.Subscribe(_ =>
{
Debug.Log("when all 处理了");
});
}
}
public class AllButtonClickedOnceExample : MonoBehaviour
{
void Start()
{
var leftMouseClickedEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)).First();
var rightMouseClickedEvetns = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(1)).First();
Observable.WhenAll(leftMouseClickedEvents, rightMouseClickedEvetns)
.Subscribe(_ =>
{
Debug.Log("mouse clicked");
});
}
}
}
OnCompleted
public class OnCompletedExample : MonoBehaviour
{
void Start()
{
Observable.FromCoroutine(A)
.Subscribe(_ =>
{
Debug.Log("OnNext:");
}, () =>
{
Debug.Log("OnCompleted:");
});
}
IEnumerator A()
{
yield return new WaitForSeconds(2.0f);
}
}
Start 多线程
Observable.Start:开启⼀个线程流。
ObserveOnMainThread : 把 WhellAll 结果转到主线程上。这样 Subscribe ⾥的回调就可以使⽤Unity 的 API 了(Unity 的很多 API 不可以在其他线程中使⽤ )。
public class ThreadExample : MonoBehaviour
{
void Start()
{
var threadAStream = Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
return 10;
});
var threadBStream = Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(3));
return 10;
});
Observable.WhenAll(threadAStream, threadBStream)
.ObserveOnMainThread()
.Subscribe(results =>
{
Debug.LogFormat("{0}:{1}", results[0], results[1]);
});
}
}
ObservableWWW
https://blog.csdn.net/dengshunhao/article/details/85391015
除了 Get 也⽀持了 Post,还有 GetWWW 和 PostWWW 这种的辅助封装,还有 GetAndGetBytes 和PostAndGetBytes。
ObservableWWW 的 API 都可以传进去⼀个 ScheduledNotifier<T>() ,⽤来监听下载进度的。Subscribe 之后传回来的值则是,当前的进度。
void Start()
{
ObservableWWW.Get("http://sikiedu.com")
.Subscribe(responseText =>
{
Debug.Log(responseText);
}, e =>
{
Debug.LogError(e);
});
}
private void Start()
{
var progressObservable = new ScheduledNotifier<float>();
ObservableWWW.GetAndGetBytes("http://liangxiegame.com/media/QFramework_v0.0.9.unitypackage", progress:progressObservable)
.Subscribe(bytes =>
{
});
progressObservable.Subscribe(progress =>
{
Debug.LogFormat("进度为:{0}", progress);
});
}
void Start()
{
var sikieduStream = ObservableWWW.Get("http://sikiedu.com");
var qframeworkStream = ObservableWWW.Get("http://qframework.io");
Observable.WhenAll(sikieduStream, qframeworkStream)
.Subscribe(responseTexts =>
{
Debug.Log(responseTexts[0].Substring(0, 100));
Debug.Log(responseTexts[1].Substring(0, 100));
});
}
ReactiveCommand
https://blog.csdn.net/dengshunhao/article/details/85391015
它提供了两个 API,CanExecte和Execute
Execute ⽅法是被外部调⽤的。也就是这个 Command 的执⾏。这个很容易理解,只要外部调⽤的Execute 就会执⾏。⽽ CanExecute 则是内部使⽤的,并且对外部提供了只读访问。当 CanExecute 为 false 时,在外部调⽤ Execute 则该 Command 不会被执⾏。当 CanExecute 为 true 时,在外部调⽤ Execute 则该 Command 会被执⾏。其他的 Observable决定 CanExecute 为 false 或 true ,新创建的 ReactiveCommand 默认 CanExecute 为 true。
当然 ReactiveCommand 也是可以被订阅(Subscribe) 的,在订阅之前呢,也可以使⽤ Where 等操作符进⾏事件操作。
private void Start()
{
var mouseDownStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)).Select(_ => true);
var mouseUpStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonUp(0)).Select(_ => false);
var isMouseUp = Observable.Merge(mouseUpStream, mouseDownStream);
var reactiveCommand = new ReactiveCommand(isMouseUp, false);
reactiveCommand.Subscribe(_ =>
{
Debug.Log("reactive command executed;");
});
Observable.EveryUpdate().Subscribe(_ =>
{
reactiveCommand.Execute();
});
}
ReactiveCollection
ObserverAdd // 当 新的 Item 添加则会触发
ObserverRemove // 删除
ObserverReplace // 替换(Update)
ObserverMove // 移动
ObserverCountChanged // 数量有改变(Add、Remove)
ReactiveDictionary
ObserverAdd // 当 新的 Item 添加则会触发
ObserverRemove // 删除
ObserverReplace // 替换(Update)
ObserverMove // 移动
ObserverCountChanged // 数量有改变(Add、Remove)
AsyncOperation
我们在异步加载资源或者异步加载场景的时候往往会⽤到 AsyncOperation。
UniRx 对 AsyncOperation 做了⽀持。使得加载操作可以很容易地监听加载进度。
public class AsyncOperationExample : MonoBehaviour
{
void Start()
{
var progressObservable = new ScheduledNotifier<float>();
SceneManager.LoadSceneAsync(0).AsAsyncOperationObservable(progressObservable)
.Subscribe(asyncOperation =>
{
Debug.Log("load done");
Resources.LoadAsync<GameObject>("TestCanvas").AsAsyncOperationObservable()
.Subscribe(resourceRequest =>
{
Instantiate(resourceRequest.asset);
});
});
progressObservable.Subscribe(progress =>
{
Debug.LogFormat("加载了:{0}", progress);
});
}
}