课程地址 : http://www.sikiedu.com/course/271
凉鞋大大的,可以的话大家多支持一波~
一.UGUI事件支持
UGUI 增强的原理很简单,就是对 UnityEvent 提供了 AsObservable ⽅法。
代码如下:
public Button mButton;
mButton.onClick.AsObservable().Subscribe(_ => Debug.Log("clicked"));
1.按钮点击事件
mButton.OnClickAsObservable()
.Subscribe(_ =>
{
// do something
});
2.Toggle
mToggle.OnValueChangedAsObservable()
.Subscribe(on =>
{
if (on)
{
// do some thing
}
});
同时支持操作符
mButton.OnClickAsObservable()
.First()
.Subscribe(_ =>
{
// do something
});
不⽌如此,还⽀持 EventSystem 的各种 Trigger 接⼝的监听。
3.Image 的拖拽
mImage.OnBeginDragAsObservable().Subscribe(_=>{});
mImage.OnDragAsObservable().Subscribe(eventArgs=>{});
mImage.OnEndDragAsObservable().Subscribe(_=>{});
4.Event
UnityEvent mEvent;
void Start()
{
mEvent.AsObservable()
.Subscribe(_ =>
{
// process event
});
}
二.响应式属性ReactiveProperty
可以替代⼀切变量,给变量创造了很多功能。
假如我们想监听⼀个值是否发⽣了改变。
public int Age
{
get
{
...
}
set
{
if (mAge != value)
{
mAge = value;
// send event
OnAgeChanged();
// call delegate
}
}
}
public void OnAgeChanged()
{
}
这样在类的内部,写⼀次 OnAgeChanged 是没问题的。但是我想在这个类的外部监听这个值的改变,
那就要声明⼀个委托来搞定了。委托的维护成本⽐较低,是可以接受的,直到发现了 UniRx 的ReactiveProperty。就再也不想⽤委托来做这种⼯作了
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);
});
}
}
当任何时候,Age 的值被设置,就会通知所有 Subscribe 的回调函数。
⽽ Age 可以被 Subscribe 多次的。
并且同样⽀持 First、Where 等操作符。
三.MVP 实现
MVP 设计模式 : Model-View-(Reactive)Presenter Pattern
在 Ctrl 中,进⾏ Model 和 View 的绑定。Model 的所有属性都是⽤ ReactiveProperty,然后在 Ctrl 中进⾏订阅。
通过 View 更改 Model 的属性值。形成⼀个 View->Ctrl->Model->Ctrl->View 这么⼀个事件响应环。
参考以下案例,可以看出UniRx可以迎送实现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();
}
}
在 Unity ⾥,序列化是⼀个很重要的功能,如果不可序列化,则在编辑器上就看不到参数。⽽ReactiveProperty 是泛型的,序列化起来⽐较麻烦。为了解决这个问题,UniRx ⽀持了可序列化的ReactiveProperty 类型,⽐如 Int/LongReactivePropety、Float/DoubleReactiveProperty、StringReactiveProperty、BoolReactiveProperty,还有更多,请参见InspectableReactiveProperty.cs。
如果你需要 [Multiline] 或者[Range] 添加到 ReactiveProperty 上,你可以使⽤MultilineReactivePropertyAttribute 和 RangeReactivePropertyAttribute 替换 Multiline 和 Range。
这些 InspectableReactiveProperties 可以在 inspector ⾯板显示,并且当他们的值发⽣变化时发出通知,甚⾄在编辑器⾥变化也可以。
这里提一下MVVM :
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。
这里没有实现MVVM的原因是Unity 没有提供 UI 绑定机制,创建⼀个绑定层过于复杂并且会对性能造成影响(使⽤反射)。尽管如此,视图还是需要更新。Presenters 层知道 View 组件并且能更新它们