该Interactable
组件是一个多合一的容器,可以使任何对象轻松交互并响应输入。交互性是所有类型的输入(包括触摸,手光线,语音等)的统筹兼用,并将这些交互作用转化为事件和视觉主题响应。该组件提供了一种简单的方法来制作按钮,更改具有焦点的对象的颜色等等。
如何配置Interactable
该组件允许配置的三个主要部分:
常规输入设置
状态
状态是ScriptableObject参数,用于定义“交互的配置文件”和“视觉主题”的交互阶段,例如按下或观察。
该DefaultInteractableStates(Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset)附带MRTK外的盒子,并且是默认的参数可交互组件。
该DefaultInteractableStates资产包含四种状态,并利用InteractableStates
状态模型实现。
- 默认值:什么都没有发生,这是最孤立的基本状态。
- 焦点:指向对象。这是一个状态,当前未设置其他任何状态,但其排名将超过默认值。
- 按下:指向对象,并按下按钮或手。按下状态将对“默认”和“焦点”进行排名。此状态也将设置为对物理出版社的后备。
- 禁用:该按钮不应是交互式的,视觉反馈将使用户知道该按钮由于某种原因当前不可用。从理论上讲,禁用状态可以包含所有其他状态,但是当禁用“启用”时,“禁用”状态将胜过所有其他状态。
根据列表中的顺序,为状态分配一个位值(#)。
[!注意]在创建可交互组件时,通常建议使用DefaultInteractableStates(Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset)。
但是,有17种可交互状态可用于驱动主题,尽管有些状态是由其他组件驱动的。这是具有内置功能的列表。
已访问:已单击交互对象。
已切换:按钮处于已切换状态,或者维度索引为奇数。
手势:按下手或控制器并从原始位置移开。
语音命令:语音命令用于触发交互对象。
PhysicalTouch:当前检测到触摸输入,用于
NearInteractionTouchable
启用。抓取:一只手当前正在抓住对象的边界,用于
NearInteractionGrabbable
启用
已启用
切换交互对象是否将开始启用。这对应于Interactable.IsEnabled
in代码。
一个可交互的启用性能比通过游戏对象/组件(即SETACTIVE等),被配置启用的属性不同。禁用GameObject或Interactable MonoBehaviour将禁用类中所有内容的运行,包括输入,视觉主题,事件等。禁用viaInteractable.IsEnabled
将禁用大多数输入处理,并重置相关的输入状态。但是,该类仍将在每一帧运行,并接收将被忽略的输入事件。这对于通过Visual Themes可以在禁用状态下显示交互对象很有用。一个典型的例子是提交按钮,等待所有必填的输入字段完成。
输入动作
从输入配置或控制器映射概要文件中选择Interactionable组件应作出反应的输入操作。
可以在运行时通过来配置此属性Interactable.InputAction
。
IsGlobal
如果为true,则将组件标记为所选输入action的全局输入侦听器。默认行为为false,这会将输入限制为仅此Interactable collider / GameObject。
可以在运行时通过来配置此属性Interactable.IsGlobal
。
语音指令
语音命令,从MRTK语音命令资料,来触发针对语音交互onClick事件。
可以在运行时通过来配置此属性Interactable.VoiceCommand
。
需要重点
如果为true,则仅当且仅当语音命令已经具有指针的焦点时,语音命令才会激活Interactable。如果为false,则交互对象将充当所选语音命令的全局侦听器。默认行为是正确的,因为可能很难在一个场景中组织多个全局语音侦听器。
可以在运行时通过来配置此属性 Interactable.VoiceRequiresFocus
。
选择模式
此属性定义选择逻辑。当一个可交互被点击时,它遍历到下一个维度的水平。尺寸与等级相似,并定义了输入之外的状态(即焦点,按下等)。它们对于定义与按钮关联的切换状态或其他多列状态很有用。当前Dimension级别由跟踪Interactable.DimensionIndex
。
可用的选择模式为:
- 按钮–尺寸= 1,简单可点击可交互
- 切换–尺寸= 2,交互作用在开/关状态之间交替
- 多维–尺寸> = 3,每次单击都会增加当前尺寸级别+1。对于定义列表的按钮状态等有用。
Interactable 还允许每个 Dimension 定义多个主题。例如当的 SelectionMode =Toggle,一个主题可以在所施加的可交互被取消选择,并且该组件时另一个主题施加选择。
可以在运行时通过查询当前选择模式Interactable.ButtonMode
。可以通过设置Interactable.Dimensions
属性以匹配所需功能来在运行时更新模式 。此外,可通过来访问对“切换”和“多维”模式有用的当前尺寸Interactable.CurrentDimension
。
交互配置文件
配置文件是在GameObject和Visual Theme之间建立关系的项目。配置文件定义了状态更改发生时主题将处理的内容。
主题的工作原理很像材料。它们是可编写脚本的对象,其中包含将基于当前状态分配给对象的属性列表。主题也可以重用,并且可以在多个Interactable UX对象之间分配。
销毁时重置
视觉主题会根据所选主题引擎的类和类型来修改目标GameObject上的各种属性。如果在销毁可交互组件时销毁时重置为true,则该组件会将所有修改后的属性从活动主题重置为其原始值。否则,在被破坏时,可交互组件将保留所有修改后的属性。在后一种情况下,除非被另一个外部组件更改,否则值的最后状态将保持不变。默认为false。
事件
每个Interactable组件都有一个OnClick事件,该事件在仅选择该组件时就会触发。但是,Interactable可以用于检测输入事件,而不仅仅是OnClick。
单击添加事件按钮以添加新类型的事件接收器定义。添加后,选择所需事件的类型。
有不同类型的事件接收器来响应不同类型的输入。MRTK随附了以下几套现成的接收机。
InteractableAudioReceiver
InteractableOnClickReceiver
InteractableOnFocusReceiver
InteractableOnGrabReceiver
InteractableOnHoldReceiver
InteractableOnPressReceiver
InteractableOnToggleReceiver
InteractableOnTouchReceiver
可以通过扩展新类来创建自定义接收器ReceiverBase
。
切换事件接收器的示例
互动式接收器
该InteractableReceiver
组件允许在源Interactable组件之外定义事件。该InteractableReceiver将听取由另一发射的过滤事件类型可交互。如果没有直接分配Interactable属性,则“搜索范围”属性将定义InteractableReceiver侦听事件的方向,该方向可以是自身,父对象或子GameObject中的事件。
InteractableReceiverList
行为类似,但包含匹配事件列表。
创建自定义事件
像Visual Themes一样,事件可以扩展为检测任何状态模式或公开功能。
可以通过两种主要方式创建自定义事件:
- 扩展
ReceiverBase
类以创建一个自定义事件,该事件将显示在事件类型的下拉列表中。默认情况下会提供一个Unity事件,但是可以添加其他Unity事件,也可以将该事件设置为隐藏Unity事件。此功能使设计人员可以与工程师合作处理项目,以创建设计人员可以在编辑器中设置的自定义事件。 - 扩展
ReceiverBaseMonoBehavior
该类以创建可以驻留在Interactable或另一个对象上的完全自定义事件组件。该ReceiverBaseMonoBehavior
会参考可交互检测状态的变化。
扩展示例 ReceiverBase
在CustomInteractablesReceiver
约一类的显示状态信息可交互,是如何创建一个自定义事件接收的例子。
public CustomInteractablesReceiver(UnityEvent ev) : base(ev, "CustomEvent")
{
HideUnityEvents = true; // hides Unity events in the receiver - meant to be code only
}
创建自定义事件接收器时,以下方法对于覆盖/实现很有用。ReceiverBase.OnUpdate()
是一种可用于检测状态模式/转换的抽象方法。此外,当选择Interactable时,ReceiverBase.OnVoiceCommand()
和ReceiverBase.OnClick()
方法对于创建自定义事件逻辑很有用。
public override void OnUpdate(InteractableStates state, Interactable source)
{
if (state.CurrentState() != lastState)
{
// the state has changed, do something new
lastState = state.CurrentState();
...
}
}
public virtual void OnVoiceCommand(InteractableStates state, Interactable source,
string command, int index = 0, int length = 1)
{
base.OnVoiceCommand(state, source, command, index, length);
// voice command called, perform some action
}
public virtual void OnClick(InteractableStates state,
Interactable source,
IMixedRealityPointer pointer = null)
{
base.OnClick(state, source);
// click called, perform some action
}
在检查器中显示自定义事件接收器字段
ReceiverBase脚本使用InspectorField
属性在检查器中公开自定义属性。这是Vector3的示例,Vector3是带有工具提示和标签信息的自定义属性。选择Interactable GameObject并添加关联的事件接收器类型后,此属性将在检查器中显示为可配置。
[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;
如何使用互动式
建立一个简单的按钮
通过将Interactable组件添加到配置为接收输入事件的GameObject中,可以创建一个简单的按钮。它可以在其上或在孩子身上带有对撞机,以接收输入。如果将Interactable与基于Unity UI的GameObjects一起使用,则它应位于Canvas GameObject下。
通过创建新的配置文件,分配GameObject本身并创建新的主题,将按钮进一步向前移动。此外,使用OnClick事件可以使某些事情发生。
[!NOTE]使按钮可按下需要该
PressableButton
组件。此外,PhysicalPressEventRouter
还需要该组件将新闻事件集中到Interactable组件。
创建切换和多维按钮
切换按钮
要使按钮可切换,请将Selection Mode
字段更改为Toggle
。在“个人档案”部分中,为打开“互动”时使用的每个个人档案添加了新的切换主题。
当SelectionMode
设置为Toggle时,“ IsToggled”复选框可用于在运行时初始化时设置控件的默认值。
CanSelect表示交互对象可以从关闭变为打开,而CanDeselect表示相反。
开发人员可以使用SetToggled
和IsToggled
接口通过代码获取/设置Interactable的切换状态。
// If using SelectionMode = Toggle (i.e Dimensions == 2)
// Make the Interactable selected and toggled on
myInteractable.IsToggled = true;
// Get whether the Interactable is selected or not
bool isSelected = myInteractable.IsToggled;
切换按钮集合
通常有一系列切换按钮,在任何给定时间都只能激活一个切换按钮,也称为径向按钮或单选按钮等。
使用InteractableToggleCollection
组件启用此功能。此控件可确保在任何给定时间仅打开一个Interactable。该RadialSet(资产/ MRTK / SDK /功能/ UX /可交互/预制件/ RadialSet.prefab)也是一个很好的起点外的框。
要创建自定义的径向按钮组:
- 创建多个可交互的GameObjects /按钮
- 使用SelectionMode = Toggle,CanSelect = true和CanDeselect = false设置每个Interactable
- 在所有Interactables上创建一个空的父GameObject并添加InteractableToggleCollection组件
- 所有加入Interactables到ToggleList上InteractableToggleCollection
- 设置InteractableToggleCollection.CurrentIndex属性,以确定在启动时默认选择哪个按钮
多维按钮
多维选择模式用于创建顺序按钮或具有两个以上步骤的按钮,例如使用三个值控制速度(快速(1x),更快(2x)或最快(3x))。
尺寸为数字值时,可以为每个速度设置添加最多9个主题,以控制按钮的文本标签或纹理,并为每个步骤使用不同的主题。
每个click事件都会DimensionIndex
在运行时将其递增1,直到Dimensions
达到该值为止。然后循环将重置为0。
开发人员可以评估DimensionIndex
以确定当前处于活动状态的维度。
// If using SelectionMode = Multi-dimension (i.e Dimensions >= 3)
//Access the current DimensionIndex
int currentDimension = myInteractable.CurrentDimension;
//Set the current DimensionIndex to 2
myInteractable.CurrentDimension = 2;
// Promote Dimension to next level
myInteractable.IncreaseDimension();
在运行时创建交互
可在运行时将Interactable轻松添加到任何GameObject中。以下示例演示了如何为配置文件分配视觉主题。
var interactableObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
var interactable = interactableObject.AddComponent<Interactable>();
// Get the default configuration for the Theme engine InteractableColorTheme
var newThemeType = ThemeDefinition.GetDefaultThemeDefinition<InteractableColorTheme>().Value;
// Define a color for every state in our Default Interactable States
newThemeType.StateProperties[0].Values = new List<ThemePropertyValue>()
{
new ThemePropertyValue() { Color = Color.black}, // Default
new ThemePropertyValue() { Color = Color.black}, // Focus
new ThemePropertyValue() { Color = Random.ColorHSV()}, // Pressed
new ThemePropertyValue() { Color = Color.black}, // Disabled
};
interactable.Profiles = new List<InteractableProfileItem>()
{
new InteractableProfileItem()
{
Themes = new List<Theme>()
{
Interactable.GetDefaultThemeAsset(new List<ThemeDefinition>() { newThemeType })
},
Target = interactableObject,
},
};
// Force the Interactable to be clicked
interactable.TriggerOnClick()
通过代码进行交互的事件
可以Interactable.OnClick
通过以下示例通过代码向基本事件添加操作。
public static void AddOnClick(Interactable interactable)
{
interactable.OnClick.AddListener(() => Debug.Log("Interactable clicked"));
}
使用该Interactable.AddReceiver<T>()
函数在运行时动态添加事件接收器。
下面的示例代码演示了如何添加一个InteractableOnFocusReceiver,它侦听焦点的进入/退出,并且还定义了在事件实例触发时执行的动作代码。
public static void AddFocusEvents(Interactable interactable)
{
var onFocusReceiver = interactable.AddReceiver<InteractableOnFocusReceiver>();
onFocusReceiver.OnFocusOn.AddListener(() => Debug.Log("Focus on"));
onFocusReceiver.OnFocusOff.AddListener(() => Debug.Log("Focus off"));
}
下面的示例代码演示了如何添加一个InteractableOnToggleReceiver,它侦听可切换Interactables上的已选择/取消选择状态转换,并且还定义了在事件实例触发时执行的动作代码。
public static void AddToggleEvents(Interactable interactable)
{
var toggleReceiver = interactable.AddReceiver<InteractableOnToggleReceiver>();
// Make the interactable have toggle capability, from code.
// In the gui editor it's much easier
interactable.Dimensions = 2;
interactable.CanSelect = true;
interactable.CanDeselect = true;
toggleReceiver.OnSelect.AddListener(() => Debug.Log("Toggle selected"));
toggleReceiver.OnDeselect.AddListener(() => Debug.Log("Toggle un-selected"));
}
也可以看看
原创文章,作者:游戏开发极客,如若转载,请注明出处:https://hololens2.cn/%e5%8f%af%e4%ba%92%e5%8a%a8%e7%9a%84/