C#Unity

基于池的事件系统扩展

Spread the love

自从接触了ReactiveEx之后,我觉得在界面的开发中完全可以用响应式的思想来实现一些功能。

微软Rx小组在很多不同的平台上面都已经支持了Reactive扩展,包括Unity也有UniRx。

UniRx内容非常多,也非常强大,但是想要让所有人都一下子习惯这样来进行编程肯定是不现实的,所以就萌生了自己编写一套基于流的事件扩展的想法。

很惭愧,没有写出像UniRx这样基于子线程轮询的事件扩展组件。我是基于协程来实现的。下面就来介绍一下具体的使用。

在这之前我们已经有一套事件系统了,所有的事件扩展都是基于该事件系统实现的。

目前只实现了一些简单的扩展方法。接下来对其用法进行一一介绍。

现在将监听作为BaseCommand保存起来,不再以Delegate队列保存,不再以DynamicInvoke进行调用,去除了反射时带来的GC消耗,在频繁调用时也不用担心GC的问题。

扩展方法的使用很简单:

在AddEventListener的后面加上扩展方法即可。

目前支持的方法有:

整个消息处理的过程如下:

第一次检查条件->

在此基础上的所有参数进行操作(OnEveryArgIn)->

若池内为空则开启池并且每一帧进行轮询(EveryFrameCall)->

将参数加入池中->

将参数赋予LastCommand->

第二次检查条件->

检查是否为单次调用->

执行StartCall->

执行事件本体->

执行Callback->

重置池->

返回结果

 

简单的应用:

 

例子1:发送消息并且等待,如果超时则弹框。

解释:SetTimeOutOnce在这里表示,在两秒内监听消息。

如果超过两秒则执行后面的Action并且卸载事件,如果接受到事件,则处理事件并且卸载事件。

 

例子2:双击事件

解释:PoolByTime表示只有在池中积累到两个事件数量的时候才会触发事件,而ResetPoolByTime表示在一定时间之内重置池。

整段代码连起来的意思就是:在1秒钟内连续触发该信息两次。

 

更进一步:

现在我们每次注册一个事件都需要依赖于一个字符串,那么如果我们想对原生的UnityEvent进行操作呢?

比如Button.onClick等等。

新的事件扩展中包含了Listenable,将原生事件封装为我们可以使用的Command。

使用方法也很简单,只需要调用扩展方法GetListenable就可以了。

Listenable后面有Listen,就相当于是处理函数。

然后如果我们需要有什么扩展方法进行应用的话就直接写在后面就行了。

 

例子3:TakeUntil

图就是上面的图,该代码的功能是,如果在一定时间内没有收到事件才会对最后一个事件进行处理。

在一些使用场景中会比较有用,例如,我们需要输入单词并且向服务端请求查询结果。

如果我们直接调用onValueChanged则会疯狂像服务端发送消息,而如果使用了TakeUntil,用户在输入单词的时候就不会主动发送消息,除非他输入得实在是很慢。

其内部的实现机制是,在每次开启池的时候检查,如果池的数量大于1则重置池,并且将新值加入,这样我们就可以始终将池中的参数数量保持为1并且使用PoolByTime,也就等待时间。

最后就实现了TakeUntil的功能。

 

由于该系统用到了大量协程,于是我没有使用原生的Coroutine,而是自己实现了一套高效率的协程,在另外一篇文章进行介绍。

发表评论

电子邮件地址不会被公开。 必填项已用*标注