unity免费插件之unirx
UniRx 是一个用于 Unity 的响应式编程库,它通过响应式编程的模式来简化事件和异步操作的管理。
AssetStore链接:
UniRx - Reactive Extensions for Unity | Integration | Unity Asset Store
一、定义
UniRx 是一个用于 Unity 的响应式编程库,它通过响应式编程的模式来简化事件和异步操作的管理。
二、核心组成
· Observable(可观察的):表示一个数据流或事件流。
· Operators(操作符):用于转换、组合和过滤 Observable 的工具。
· Subscription(订阅):观察者订阅一个 Observable 来接收事件。
三、常用API
(1)常用ui事件
·button.OnClickAsObservable():ui中按钮被按下事件
// UniRx 方式(Observable)
button.OnClickAsObservable()
.Subscribe(_ => Debug.Log("Button clicked"));
_ =>
是一个简化的 Lambda 表达式语法,表示在这个订阅的过程中不需要使用传入的参数。如果关心事件传递的参数,可以使用其他名称来接收这个参数。比如:button
参数是按钮对象,可以访问它的属性(如 name
)来获得更多信息。
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
· Takewhere:当条件不满足时停止流
(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);
四、优势
避免传统回调函数的复杂性,并且可以通过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
});
}
知识点:
(1)Observable.Create<Unit>
来创建一个自定义的 Observable。Observable.Create
让我们能够手动控制数据流的发出。observer
是一个对象,用来控制 Observable 的状态
(2)Disposable.Empty
表示返回一个空的 Disposable
对象,这意味着没有其他资源需要清理。这个方法在 Observable 执行完后自动终止。一般和create成对存在
(3)observer.OnCompleted()
是 通知观察者,表示 Observable 数据流已经完成。这意味着所有数据已经发送完毕,没有更多的数据将会被发出。
网上写unixr比较详细的文章:https://zhuanlan.zhihu.com/p/420299920
更多推荐
所有评论(0)