新点击组件设计评估

交互类型

手柄射线

手柄碰撞

鼠标点击/触屏点击射线

凝视射线

交互实现

Raycast,包含UI和碰撞体
Trigger

问题

底层是否兼容Unity原生的事件, 使用 EventSystems

说明:本文中的XR均指下方所述的 com.unity.xr.interaction.toolkit

兼容Unity事件系统

优点:

  1. Unity的UGUI功能都可兼容,直接使用

  2. 利用XR源码,比较稳定,减少工作量

  3. 使用EventSystems事件的设计方案,提供了设计上的标准,便于后续更多人参与维护

缺点:

  1. 支持了很多用不到的功能, 比如UGUI原生事件可能没有使用到

  2. 限制了代码的灵活性,增加了复杂度。

兼容Unity事件,也可以直接使用XR工具,内部鼠标 VR 点触 操作类型都有支持。可基于此逻辑实现功能接口

XR 和 SR 都实现了Unity事件的触发。使用区别在于XR使用标准的Unity事件结构,用实现新的InputModule。SR没有重载InputModule而独立运行,还添加了其自身的事件接口。

不兼容Unity事件系统

优点:

  1. 可使用比较轻量的代码实现点击逻辑

  2. 不需要基于Unity事件传递逻辑,设计上比较自由

缺点:

  1. 短时间内可能不大稳定

  2. 需要除了设计者外的参与人员,理解Unity官方设计以外的更多内容,维护需要额外开销

XRUIInputModule 源码浅析

源码地址 https://github.com/needle-mirror/com.unity.xr.interaction.toolkit

https://github.com/needle-mirror/com.unity.xr.interaction.toolkit/tree/master/Runtime/UI

XRUIInputModule 实现了VR手柄,鼠标,点触三种交互方式的统一,使用EventSystems接收消息。但是没有对Ray和Trigger交互分别设置,自动给各种UI组件启用了Ray交互。没找到Gaze类型

XR 工具在手柄上添加Raycaster,上层传入 TrackedDeviceEventData 类型,包含Raycast的起始点和方向

Raycast 内容包含 Physics , Physics2D, Graphics ; Graphics 的Raycast部分,使用另外实现的检测算法 RayIntersectsRectTransform

Trigger类型交互使用 XRDirectInteractor 和 XRBaseInteractable 互相检测实现

外层接口

使用原始R接口,以兼容已有元器件和功能。 同时也设计了新接口以供参考

点击接口设计参考

 // JavaScript
 element.AddListener('click',event:ClickEvent=>void)
 // fultter - dart
 Add(new Element({
     otherStyle,
     onClick
 }))

其他
button.AddClickListener(callback)

element.AddClickListener(ray|trigger,event:ClickEvent=>void)

接口方案 1

 VLabEvent.Trigger.AddClickListener(GameObject,ClickEvent)

 VLabEvent.Trigger.AddDoubleListener(GameObject,DoubleClickEvent)

 VLabEvent.Trigger.AddEnterListener(GameObject,EnterEvent)

 VLabEvent.Trigger.AddExitListener(GameObject,ExitEvent)

 VLabEvent.Ray.AddClickListener(GameObject,ClickEvent)

 VLabEvent.Ray.AddDoubleListener(GameObject,DoubleClickEvent)

 VLabEvent.Ray.AddEnterListener(GameObject,EnterEvent)

 VLabEvent.Ray.AddExitListener(GameObject,ExitEvent)

不方便扩展功能

接口方案 2

 VLabEvent.AddClickListener(GameObject,Trigger|Ray,ClickEvent)

 VLabEvent.AddDoubleListener(GameObject,Trigger|Ray,DoubleClickEvent)

 VLabEvent.AddEnterListener(GameObject,Trigger|Ray,EnterEvent)

 VLabEvent.AddExitListener(GameObject,Trigger|Ray,ExitEvent)

接口方案 3

 VLabEvent.AddListener(new Params{
     GameObject,
     isTrigger,
     isRay,
     onClick,
     onEnter,
     onExit
     })

flutter采用此种接口设计,对于需要同时支持多种事件的交互对象使用比较方便。但是对于C#这样的语言,书写起来比较繁琐,参数需要new和参数类型

接口方案 4

 var listener = VLabEvent.AddInteractable(GameObject,Trigger|Ray)
 listener.OnClick += ()=>{};
 listener.OnEnter += ()=>{};
 listener.OnExit += ()=>{};

比较符合UI框架的接口风格

接口方案 5

 var listener = VLabEvent.AddInteractable(GameObject,Trigger|Ray)
 listener.OnClick.AddListener(ClickEvent);
 listener.OnDoubleClick.AddListener(DoubleClickEvent);
 listener.OnEnter.AddListener(EnterEvent);
 listener.OnExit.AddListener(ExitEvent);

比较符合Unity UI 事件的接口风格

总结

点击组件底层其实是重新实现SR或XR内容,将各端交互统一。SR中有有Ray,Trigger,Mouse,Touch几种交互类型的条件,有SR事件接口。XR没有过多设置,使用Unity原生事件接口,VR下可交互的物体使用Ray进行交互,无需单独配置

SR的代码比较复杂,而且很久没有维护更新。XRUIInputModule的源码更加清晰。
新的设计上可以分成三层

  • 底层事件逻辑可以参考XRUIInputModule源码,实现各输入设备交互事件的触发
  • 中层加入新点击组件逻辑,对Ray和Trigger触发进行过滤和判断
  • 外层是提供对外的接口

成果需求

  1. 兼容2D和3D交互

  2. 兼容多平台使用方式一致