Unity中使用UniRx入门总结

什么是UniRx?

  UniRx就是Unity版本的Reactive Extensions,Reactive Extensions 中文意思是:响应式扩展,响应式指的是观察者和定时器,扩展指的是 LINQ的操作符。Reactive Extensions以擅长处理时间上异步的逻辑、以及极简的API风格慕名而来。

为什么要使用UniRx?

  因为很多在项目上的一些逻辑操作都需要在时间上异步处理,所以需要实现的异步逻辑往往会比较多。这也是为什么会有携程的概念。
  在项目中,像动画的播放、网络请求、资源加载、场景过度等等都是在时间上异步操作的逻辑,当我们在项目上实现上述功能模块时,往往使用通过大量的回调实现,可能会导致项目充斥着大量的回调来处理某些逻辑,相对较好的方法则是实用消息/事件进行实现,但是结果也可能导致项目中有大量的事件,经过一段时间可能看不明白自己写的逻辑。
  而UniRx的出现刚好解决解决了这个问题,它介于回调和事件之间。

  • 它有事件的概念,只不过它的事件是像流水一样,我们在开发过程中需要对这些事件进行组织、变换、过滤、合并等操作
  • 它也用了回调,只不过它的回调是在事件经过组织之后,只需要调用一次就进行事件处理了

常用API

定时功能

平常项目中可能经常遇到经过一段时间再触发某些逻辑操作
平常的可能通过使用协程

 void Start()
    {
        StartCoroutine(Timer(10, DoSomething));
    }
    
    IEnumerator Timer(float seconds,Action callback)
    {
        yield return new WaitForSeconds(seconds);
        callback();
    }

         
    void DoSomething()
    {
        Debug.Log("TODO");
    }

代码声明实现了跟上述一样的功能,经过10s去打印,代码是不是很清晰。

 void Start()
    {
        Observable
            .Timer(TimeSpan.FromSeconds(10))
            .Subscribe(e => {
                Debug.Log("DoSomething");
            });
    }

  还有一点需要注意的是上述写法没有和Unity中的MonoBehaviour进行生命周期绑定,可能MonoBehaviour销毁了之后,逻辑还在执行,可能会造成空指针。 需要在最后加上.AddTo(this),当生命周期被销毁,脚本逻辑也会跟随销毁。这也是我们平常写逻辑需要注意的点。
代码如下

 void Start()
    {
        Observable
            .Timer(TimeSpan.FromSeconds(10))
            .Subscribe(e => {
                Debug.Log("DoSomething");
            })
            .AddTo(this);
    }

Update

  写功能模块时平常可能在Update中定义某些逻辑,随着项目可能Update中的代码量很大。使用UniRx可以使代码相互独立。如下所示:(注意不要忘记在最后添加.AddTo(this))

void Start()
    {
        Observable
            .EveryUpdate()
            .Subscribe(e => {
                Debug.Log("QQQ");
            })
            .AddTo(this);

        Observable
           .EveryUpdate()
           .Subscribe(e => {
               Debug.Log("WWW");
           })
           .AddTo(this);

        Observable
           .EveryUpdate()
           .Subscribe(e => {
               Debug.Log("EEE");
           })
           .AddTo(this);
    }

上述代码可以在实际项目中通过业务模块的划分将其单独定义,也便于以后的维护。

操作符 First

平常做项目中也可能遇到第一次需要执行后续则不需要执行的相关功能,常规实现我们可能定义一个bool值,在执行一次后将其赋值为false,通过第一次鼠标点击来举例,关键字是First。代码如下

  void Start()
    {
        Observable
            .EveryUpdate()
            .First(_=>Input.GetMouseButtonDown(0))
            .Subscribe(e => {
                Debug.Log("EEE");
            })
           .AddTo(this);
    }

操作符Where

这个Where可以理解为当满足一定条件时才能往下执行。代码如下,当鼠标左键被按下时打印输出。

void Start()
{
	 Observable
            .EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(0))
            .Subscribe( _=>
            {
                Debug.Log("DOSomething");
            })
            .AddTo(this);
}

ReactiveProperty

  ReactiveProperty是响应式属性的意思,顾名思义就是当为项目中某个属性进行赋值会动态执行相关逻辑,直接上代码,下面代码有什么局限性呢,当值改变时,只能在属性内部进行对应方法响应,如果我想在外部进行调用呢?那可能需要定义一个委托进行绑定。UniRx有更简洁的API;
常规写法

 	private int age;
    public int Age
    {
        get
        {
            return age;
        }

        set {
            if (value>0)
            {
                age = value;
                OnAgeChanged();

            }
        }
    }

    void OnAgeChanged()
    {
    }

UniRx用法

	public ReactiveProperty<int> Age = new ReactiveProperty<int>();
    void Start()
    {
        Age.Subscribe(age =>
        {
            Debug.Log("赋值之后改变的方法");
        });

        Age.Value = 22;
        }

对UGUI的支持

可以使用UniRx对UI控件进行动态绑定,其余用法可以自行查询。也可以根据业务需求在定义时添加WhereFirst等操作符。

 public Button btn;
    public Toggle toggle;


    void Start()
    {
        btn.OnClickAsObservable()
            .Subscribe(_ =>
            {
                Debug.Log("BtnClick");
            });

        toggle.OnValueChangedAsObservable()
            .Subscribe(isOn =>
            {
                if (isOn)
                {

                }
                else
                { }

            });
            }

操作符Merge

这里介绍的是对UniRx定义的流逻辑进行合并操作,代码如下:代码分别定义了两个事件流,通过操作符Merge进行合并,当鼠标左键或右键按下时,都会打印输出。

 void Start()
    {
        //定义流1
        var stream01 = Observable
            .EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(0));
        //定义流2
        var stream02 = Observable
            .EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(1));

        Observable.Merge(stream01, stream02)
            .Subscribe(_ => {
                Debug.Log("DoSomeThing");
            })
            .AddTo(this);
     }

基本用法就介绍到这。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity 使用 proto,需要先安装 Google 的 protobuf 工具。然后在 Unity 项目导入相关的 proto 文件,使用 protoc 编译器生成对应的 C# 类代码。在 Unity ,可以通过这些 C# 类来序列化和反序列化 proto 数据。 具体的步骤如下: 1. 下载并安装 protobuf 工具,包括 protoc 编译器和 C# 支持库。 2. 在 Unity 创建一个 C# 类来表示你的 proto 数据结构。 3. 在 Unity 导入 proto 文件,使用 protoc 编译器生成对应的 C# 类代码。 4. 在 Unity 使用生成的 C# 类来序列化和反序列化 proto 数据。 以下是一个简单的示例代码,演示了如何在 Unity 使用 proto: ```csharp using System.Collections; using System.Collections.Generic; using UnityEngine; using Google.Protobuf; public class ProtoTest : MonoBehaviour { void Start() { // 创建一个 proto 数据结构 var msg = new MyMessage { Id = 1, Name = "ProtoTest", Values = { 1, 2, 3 } }; // 将 proto 数据序列化成二进制数据 var bytes = msg.ToByteArray(); // 将二进制数据反序列化成 proto 数据 var newMsg = MyMessage.Parser.ParseFrom(bytes); // 输出 proto 数据的内容 Debug.Log($"Id: {newMsg.Id}, Name: {newMsg.Name}, Values: {string.Join(", ", newMsg.Values)}"); } } // 定义一个 proto 数据结构 message MyMessage { int32 Id = 1; string Name = 2; repeated int32 Values = 3; } ``` 注意:在使用 proto 时,需要保证 Unity 和服务器端使用相同的 proto 文件和版本,否则可能会出现兼容性问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值