最近换了公司(仍然是实习狗),坐标在上海, 楼上是Unity总部。很开心~~
上海和广东差别 并不是很大。就是天气比较冷,口味偏甜, 这家公司是创业公司,做教育类应用的, VR/AR MR 等, 第一天 就要上手SDK,也不是很难,Zspace的 相对VRTK来说 比较 简单,开发工程中遇到Button交互,所以要对它进行 重写,设备是 用射线进行 探测,
其实 重写Button也比较简单,也可以不用重写, 但还是建议重写会比较好。
之前有写过射线交互的例子

原理都差不多的, 射线交互 现在用的挺多的,

NGUI 用的就是射线探测

但UGUI不是,是根据坐标,射线,结合去判断的·。

unity底层 unity底层开发_UI


Button 继承自 Selectable
官方源码

unity底层 unity底层开发_UI_02

FormerlySerializedAs( "“onClick”) ButtonClickEvent m_Onclick
这个特性就是备胎特性,当Onclick被删除 后, Onlickx序列化后就存在 m_Onclick 中

DoStateTransition(currentSelectionState, false);

unity底层 unity底层开发_Button_03


这个 方法 比较重要,就是设置Button的交互转换状态,在重写的时候。需要用到这个方法。

这个方法就是转换 Button的状态

Selectable这个类 继承 UIBehaviour

unity底层 unity底层开发_Button_04

还 继承到UIBehaviour, 而且UIBehaviour 多个 UI 组件都回继承它, 具体是干什么的呢?

UIBehaviour 基本上所有的UI控件 都继承到它

生命周期函数 都这里,

以及一些 事件响应函数

unity底层 unity底层开发_UI_05

继承自 MonoBehaviour 大家都熟悉

MonoBehaviour继承自 Behaviour

unity底层 unity底层开发_UGUI_06


之前 很好奇 为什么 MonoBehaviour 里 可以使用Print() 打印函数 原来是在这里

这里还有 协同函数

其实 背后就是一个迭代器实现的。迭代器背后又是怎么实现的呢,其实就是一个状态机,

MoveNext()方法 依托于switch语句,根据状态机的状态,执行不同代码。MonoBehaviour 是继承自Behaviour的

unity底层 unity底层开发_UGUI_07


Behaviour是继承自 compont的

compont: 消耗性能的BroadcastMessage 名声 很差

unity底层 unity底层开发_UI_08


最后就是UnityEngine 里的Object 基类了

unity底层 unity底层开发_Button_09


Button——Selectable——UIBehaviour(生命周期函数)——Behaviou——Compoent——Object

重写思路,射线分为 射线进入, 射线停留,射线离开

因此 写3个方法 就可以了

事件 传递UML 类图(借助松阳大神的)

unity底层 unity底层开发_UGUI_10


unity底层 unity底层开发_Click_11


ClickHandler 响应 Click

unity底层 unity底层开发_unity底层_12


OnFinishSubmit 这个方法就是 协程,具体就是 点了按钮之后回由个渐渐变色的过程。

最后再梳理一遍 Button

unity底层 unity底层开发_UI_13


Button 继承的类, 事件系统是基于Unity的, 在移除 事件的时候,通过反射去对比

unity底层 unity底层开发_Button_14


一个 无参 无返回 委托。

unity底层 unity底层开发_UI_15


unity底层 unity底层开发_UI_16


unity底层 unity底层开发_unity底层_17


这里的UnityEventBase 类 从当一个中介者的角色,

移除监听 事件时,会调用InvokableCallList 类里的RemoveListener。

RemoveListener方法会调用BaseInvokableCall的 Find方法

unity底层 unity底层开发_Button_18

unity底层 unity底层开发_Button_19


这里的UnityEvent 在移除 事件时,会通过反射,取得MethodInfo 再去 对比。

unity底层 unity底层开发_Button_20


这里不废话c#反射机制了。

EventSystem

优缺点。每次添加 监听 事件时,并没有对应的 事件码, 这样查找就要去 每个通过反射的方式去查找,比较消耗性能,而且添加 每个按钮响应事件 应该 ,给个事件Id ,才知道是哪个事件被触发了。管理很不方便。

下面是 重写 射线Button

public class RayButton : Button
{

    public UnityEngine.Events.UnityEvent MenuUIEvent;
    /// <summary>
    ///  视线进入 
    /// </summary>
    public virtual void RayEneter()
    {
        DoStateTransition(SelectionState.Highlighted, false);
    }
    /// <summary>
    /// 视线停留
    /// </summary>
    public virtual void RayStay()
    {
        ReSetButtonState();
    }

    /// <summary>
    ///  视线离开
    /// </summary>
    public virtual void RayExit()
    {
        DoStateTransition(SelectionState.Normal, false);
    }
    public virtual void TriggerEvent()
    {
        onClick.Invoke();//调用下 Click事件
        DoStateTransition(SelectionState.Pressed, false);
    }
    /// <summary>
    /// 事件完成
    /// </summary>
    public virtual void ReSetButtonState()
    {
        DoStateTransition(SelectionState.Highlighted, false);
    }

}