Unity官方开发者社区:详解UniRx插件的使用
创作时间:
作者:
@小白创作中心
Unity官方开发者社区:详解UniRx插件的使用
引用
CSDN
1.
https://unity.csdn.net/677b6d2861f6a61b9464ef74.html
UniRx是Unity官方提供的一个响应式编程库,它通过观察者模式简化了事件和异步操作的管理。本文将详细介绍UniRx的核心概念、常用API,并通过具体代码示例展示如何使用UniRx改写传统的协程实现。
一、定义
UniRx是一个用于Unity的响应式编程库,它通过响应式编程的模式来简化事件和异步操作的管理。
二、核心组成
- Observable(可观察的):表示一个数据流或事件流。
- Operators(操作符):用于转换、组合和过滤Observable的工具。
- Subscription(订阅):观察者订阅一个Observable来接收事件。
三、常用API
(1)常用UI事件
button.OnClickAsObservable()用于监听UI中按钮被按下事件。
// UniRx 方式(Observable)
button.OnClickAsObservable()
.Subscribe(_ => Debug.Log("Button clicked"));
_ =>是一个简化的Lambda表达式语法,表示在这个订阅的过程中不需要使用传入的参数。如果关心事件传递的参数,可以使用其他名称来接收这个参数。比如:
button.OnClickAsObservable()
.Subscribe(button => Debug.Log("Button clicked: " + button.name));
(2)操作符
- Select:用于映射Observable中的数据
Observable.Range(1, 5)
.Select(x => x * 2)
.Subscribe(x => Debug.Log(x));
- Where:用于过滤Observable中的数据
Observable.Range(1, 5)
.Where(x => x % 2 == 0)
.Subscribe(x => Debug.Log(x)); // 输出:2, 4
- TakeWhile:当条件不满足时停止流
(3)订阅与取消订阅
- Subscribe:订阅Observable,事件发生后,执行某个操作
Observable.Range(1, 5)
.Subscribe(x => Debug.Log(x));
- AddTo:将订阅与MonoBehaviour或GameObject生命周期绑定,自动取消订阅
IDisposable subscription = Observable.EveryUpdate()
.Subscribe(_ => Debug.Log("Every frame"))
.AddTo(this);
四、优势
UniRx避免了传统回调函数的复杂性,并且可以通过AddTo()自动管理生命周期,有效防止内存泄漏。
五、注意
订阅应该放在Start()中,而不是Update()中,因为后者意味着每一帧都会创建一个新的订阅。但大多数的订阅只需要在对象被激活时创建。
六、使用UniRx改写协程
源代码
每帧检测是否满足调用协程的条件:
void Update()
{
//Enable lazer
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//如果射线检测到了Enemy层
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity,layer))
{
targetEnemy = hit.collider.transform.root.gameObject;
Debug.Log($"目标敌军是:{targetEnemy.name}");
StartCoroutine(AimAtEnemy());
}
}
}
协程实现:
private IEnumerator AimAtEnemy()
{
// 确保 MultiHingeJoint 实例存在
if (MultiHingeJoint.Instance == null)
{
Debug.LogError("MultiHingeJoint 实例不存在");
yield break;
}
// 瞄准目标
bool isYAligned = false;
bool isXAligned = false;
MultiHingeJoint.Instance.RotateAroundY(aimPart1, FirePoint, targetEnemy);
// 等待炮筒对准目标
while (!isYAligned )
{
// 检查当前是否已经对准
isYAligned = CheckIfAimed(aimPart1, targetEnemy.transform, "Y");
yield return null; // 等待下一帧
}
MultiHingeJoint.Instance.RotateAroundX(aimPart2, FirePoint, targetEnemy);
while (!isXAligned)
{
isXAligned = CheckIfAimed(aimPart2, targetEnemy.transform, "X");
yield return null; // 等待下一帧
}
Debug.Log("炮筒对准完成,发射激光!");
}
代码改写
判断逻辑改写:
void Start()
{
// 使用 UniRx 订阅每帧更新
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0)) // 检测鼠标左键点击
.Select(_ => Camera.main.ScreenPointToRay(Input.mousePosition)) // 计算射线
.Where(ray => Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, layer)) // 射线检测是否击中目标
.Subscribe(hit =>
{
targetEnemy = hit.collider.transform.root.gameObject; // 获取目标敌人
Debug.Log($"目标敌军是:{targetEnemy.name}");
AimAtEnemy().Subscribe().AddTo(this); // 启动瞄准过程
})
.AddTo(this); // 确保在对象销毁时取消订阅
}
协程部分改写:
private IObservable<Unit> AimAtEnemy()
{
// 确保 MultiHingeJoint 实例存在
if (MultiHingeJoint.Instance == null)
{
Debug.LogError("MultiHingeJoint 实例不存在");
return Observable.Empty<Unit>(); // 返回空的 Observable,表示终止操作
}
// 瞄准目标
return Observable.Create<Unit>(observer =>
{
bool isYAligned = false;
bool isXAligned = false;
// 旋转炮筒对准 Y 轴
MultiHingeJoint.Instance.RotateAroundY(aimPart1, FirePoint, targetEnemy);
// 等待炮筒对准 Y 轴
Observable.EveryUpdate()
.Where(_ => !isYAligned) // 只在未对准时继续检查
.TakeWhile(_ => !isYAligned) // 直到条件不满足时停止
.Subscribe(_ =>
{
isYAligned = CheckIfAimed(aimPart1, targetEnemy.transform, "Y");
});
// 旋转炮筒对准 X 轴
MultiHingeJoint.Instance.RotateAroundX(aimPart2, FirePoint, targetEnemy);
// 等待炮筒对准 X 轴
Observable.EveryUpdate()
.Where(_ => !isXAligned) // 只在未对准时继续检查
.TakeWhile(_ => !isXAligned) // 直到对准完成
.Subscribe(_ =>
{
isXAligned = CheckIfAimed(aimPart2, targetEnemy.transform, "X");
});
// 等待两个轴都对准完成
Observable.EveryUpdate()
.Where(_ => isYAligned && isXAligned) // 检查是否两个轴都对准
.Take(1) // 只需要触发一次
.Subscribe(_ =>
{
Debug.Log("炮筒对准完成,发射激光!");
EmitLaser(); // 发射激光
observer.OnCompleted(); // 结束 Observable 操作
});
return Disposable.Empty; // 结束 Observable
});
}
知识点
- Observable.Create
:用来创建一个自定义的Observable。 Observable.Create让我们能够手动控制数据流的发出。observer是一个对象,用来控制Observable的状态。 - Disposable.Empty:表示返回一个空的Disposable对象,这意味着没有其他资源需要清理。这个方法在Observable执行完后自动终止。一般和create成对存在。
- observer.OnCompleted():通知观察者,表示Observable数据流已经完成。这意味着所有数据已经发送完毕,没有更多的数据将会被发出。
更多关于UniRx的详细内容可以参考:知乎专栏
热门推荐
晨光乍现:“朝露溘至”的诗意用法
网红打卡地的“朝露溘至”:短暂繁华背后的深思
怎么样避免车祸?避免车祸的有效措施有哪些?
人保财险教你快速搞定交通事故理赔
地梨子学名叫什么?
医保缴费年限“新规定”?已经正式执行!参保职工要受益了
《隐秘的角落》细节揭秘:你发现隐藏的彩蛋了吗?
《隐秘的角落》:一部现象级悬疑剧的改编秘诀
海花岛最新交通攻略:观光小火车带你畅游全岛
海花岛最新交通攻略出炉!自驾、高铁、观光小火车全都有
改编作品版权处理的新思路
《狄仁杰》与《封神》:改编剧中的历史文化盛宴
蛇年春节禁忌:家里别乱摆蛇形饰品
社保医保中断,小心健康保障“打折”
社保医保中断怎么办?这份实用指南请收好
中医治疗带状疱疹,真的有效吗?
绿豆薏米汤,真的能治愈带状疱疹吗?
北京丰台站到国贸最快路线揭秘:地铁10号线全程攻略
沈阳电报大楼里的“机械股”传奇
消炎利胆片与阿莫西林联用:安全吗?医生这样建议
情感分析技术助力智能客服读懂人心
AI情感分析助力社交媒体舆情监控:技术应用与未来展望
AI助力心理健康:北京教育领域的新探索
北京发布首份教育领域AI应用指南,六大领域29个场景构建智能教育新生态
北京发布首份教育领域AI应用指南,六大领域29个场景规范智能教育发展
北京发布AI教育新方案,打造百所智能校园
北京丰台站:地铁10号线最快捷
春运期间寒潮来袭,丰台火车站出行请注意保暖
北京丰台站最新交通指南:地铁公交换乘、停车指南全攻略
人大代表建议:教育改革应建立心理健康影响评价制度