可互動 — MRTK2

Interactable

元件 Interactable 是一個全內容器,可讓任何物件輕鬆 互動 並回應輸入。 Interactionable 可作為所有類型的輸入的攔截式,包括觸控、手部光線、語音等,以及將這些互動漏斗到 事件視覺主題 回應中。 此元件可讓您輕鬆建立按鈕、變更具有焦點的物件色彩等等。

如何設定 Interactable

此元件允許設定的三個主要區段:

  1. 一般輸入組態
  2. 以多個 GameObject 為目標的視覺主題
  3. 事件處理常式

一般輸入設定

General Interactable Settings

狀態

StateScriptableObject 參數,可定義 可互動設定檔視覺主題的互動階段,例如按下或觀察。

DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) 隨附于 MRTK 現用,而且是Interactiveable元件的預設參數。

States ScriptableObject example in inspector

DefaultInteractableStates資產包含四種狀態,並利用 InteractableStates 狀態模型實作。

  • 預設值:不會發生任何事,這是最隔離的基底狀態。

  • 焦點:正在指向物件。 這是單一狀態,目前未設定其他狀態,但會排名預設值。

  • 按下:物件正指向 ,並按下按鈕或手部。 [按下狀態] 會排名 [預設值] 和 [焦點]。 此狀態也會設定為後援至實體按下。

  • 已停用:按鈕不應該是互動式的,且視覺回饋會讓使用者知道此按鈕目前是否無法使用。 理論上,停用狀態可以包含所有其他狀態,但當 Enabled 關閉時,[已停用] 狀態會支援所有其他狀態。

根據清單中的順序,會將位值 (#) 指派給狀態。

注意

通常建議您在建立Interactable元件時,利用DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) 。

不過,有 17 個可用的可互動狀態可用來驅動主題,但有些狀態是由其他元件所驅動。 以下是內建功能的清單。

  • 流覽:已按一下 [可互動]。
  • 切換:按鈕處於切換狀態,或維度索引為奇數。
  • 手勢:已按下手部或控制器,並已從原始位置移動。
  • VoiceCommand:用來觸發互動的語音命令。
  • PhysicalTouch:目前偵測到觸控輸入,用來 NearInteractionTouchable 啟用。
  • 擷取:手目前正在物件界限中抓取,用來 NearInteractionGrabbable 啟用

Enabled

切換 [互動] 是否會啟動啟用。 這會對應至 Interactable.IsEnabled 程式碼中的 。

Interactable 的啟用屬性與透過 GameObject/Component (設定的已啟用屬性不同,也就是 SetActive etc) 。 停用 GameObject 或 Interactable MonoBehaviour 會停用 類別中所有專案,使其無法執行,包括輸入、視覺主題、事件等。透過 Interactable.IsEnabled 停用會停用大部分的輸入處理、重設相關的輸入狀態。 不過,類別仍會執行每個框架,並接收將忽略的輸入事件。 這很適合用來以停用狀態顯示可透過視覺主題完成的互動。 典型的範例是提交按鈕,等候完成所有必要的輸入欄位。

輸入動作

互動元件應該回應的輸入組態或控制器對應設定檔中選取輸入動作

這個屬性可以在執行時間透過 在程式碼 Interactable.InputAction 中設定。

IsGlobal

如果為 true,這會將元件標示為所選 輸入動作的全域輸入接聽程式。 預設行為為 false,只會將輸入限制為這個 Interactable Collider/GameObject。

這個屬性可以在執行時間透過 在程式碼 Interactable.IsGlobal 中設定。

語音命令

來自 MRTK 語音命令設定檔的語音命令,以觸發 OnClick 事件以進行語音互動。

這個屬性可以在執行時間透過 在程式碼 Interactable.VoiceCommand 中設定。

需要焦點

如果為 true,則語音命令只有在已具有指標的焦點時,才會啟用 Interactable 。 如果為 false, 則 Interactable 會作為所選語音命令的全域接聽程式。 預設行為為 true,因為多個全域語音接聽程式在場景中難以組織。

這個屬性可以在執行時間透過 在程式碼 Interactable.VoiceRequiresFocus 中設定。

選取模式

此屬性會定義選取邏輯。 按一下 [互動] 時,它會逐一查看下一個 維度 層級。 維度 類似于排名,並定義輸入以外的狀態 (也就是焦點、按下等) 。 它們很適合用來定義與按鈕相關聯的切換狀態或其他多排名狀態。 目前的維度層級會由 Interactable.DimensionIndex 追蹤。

可用的選取模式如下:

  • 按鈕 - 維度= 1,簡單可點選的互動
  • 切換 - 維度= 2,關閉狀態之間的/可互動替代專案
  • 多維度 - 尺寸>= 3,每次按一下都會增加目前的維度層級 + 1。 適用于定義清單的按鈕狀態等等。

可互動 也可讓每個 維度定義多個主題。 例如,當 SelectionMode=Toggle時,當取消選取[互動]時,可能會套用一個主題,並在選取元件時套用另一個主題。

目前的選取模式可以透過 Interactable.ButtonMode 在執行時間查詢。 藉由將 屬性設定 Interactable.Dimensions 為符合所需功能,即可在執行時間更新模式。 此外,目前維度對於 切換多維度 模式很有用,可以透過 來 Interactable.CurrentDimension 存取。

可互動的設定檔

設定檔 是建立 GameObject 與 視覺主題之間關聯性的專案。 設定檔會定義當 發生狀態變更時,主題將操作哪些內容。

主題的運作方式非常類似材質。 這些物件是可編寫腳本的物件,其中包含會根據目前狀態指派給物件的屬性清單。 主題也可重複使用,並可跨多個 可互動 的 UX 物件指派。

在終結時重設

視覺主題會根據選取的主題引擎類別和類型,修改目標 GameObject 上的各種屬性。 如果損毀互動元件時 重設 On Destroy 為 true,則元件會將所有已修改的屬性從使用中主題重設為其原始值。 否則,當終結時,Interactable 元件會保留任何已修改的屬性。 在此情況下,除非由另一個外部元件改變,否則值的最後一個狀態將會保存。 預設值為 false。

Profile theams

事件

每個 互動 元件都有一個 OnClick 事件,會在直接選取元件時引發。 不過, Interactable 可用來偵測除了 OnClick以外的輸入事件。

按一下 [ 新增事件] 按鈕以新增類型的事件接收者定義。 新增之後,請選取所需的事件種類。

Events example)

有不同類型的事件接收者可以回應不同類型的輸入。 MRTK 隨附下列一組現用的接收者。

您可以建立可擴充 ReceiverBase 的新類別來建立自訂接收者。

Event Toggle Receiver Example

切換事件接收者的範例

可互動的接收者

元件 InteractableReceiver 可讓事件定義于來源 互動 元件外部。 InteractableReceiver會接聽由另一個Interactable引發的篩選事件種類。 如果未直接指派 Interactable 屬性,則 Search Scope屬性會定義InteractableReceiver會接聽本身、父代或子 GameObject 的事件方向。

InteractableReceiverList 會以類似的方式運作,但用於比對事件的清單。

Interactable reciver

建立自訂事件

就像 視覺主題一樣,您可以擴充事件來偵測任何狀態模式或公開功能。

自訂事件可以透過兩種主要方式建立:

  1. ReceiverBase擴充 類別以建立自訂事件,此事件會顯示在事件種類的下拉式清單中。 依預設會提供 Unity 事件,但可以新增其他 Unity 事件,也可以設定事件來隱藏 Unity 事件。 這項功能可讓設計工具與專案上的工程師合作,以建立設計工具可在編輯器中設定的自訂事件。

  2. ReceiverBaseMonoBehavior擴充 類別,以建立可位於Interactable或其他物件上的完全自訂事件元件。 ReceiverBaseMonoBehavior將會參考Interactable來偵測狀態變更。

擴充的範例 ReceiverBase

類別 CustomInteractablesReceiver 會顯示 Interactable 的狀態資訊,以及如何建立自訂事件接收器的範例。

public CustomInteractablesReceiver(UnityEvent ev) : base(ev, "CustomEvent")
{
    HideUnityEvents = true; // hides Unity events in the receiver - meant to be code only
}

建立自訂事件接收器時,下列方法有助於覆寫/實作。 ReceiverBase.OnUpdate() 是一種抽象方法,可用來偵測狀態模式/轉換。 此外,當選取[互動]時, 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 的範例,這是具有工具提示和標籤資訊的自訂屬性。 選取 Interactable GameObject 且已新增相關聯的 事件接收器 類型時,這個屬性會顯示為可在偵測器中設定。

[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;

如何使用 Interactable

建置簡單按鈕

您可以將 Interactable 元件新增至設定為接收輸入事件的 GameObject,以建立簡單的按鈕。 它可以有碰撞器或子系上的碰撞器來接收輸入。 如果使用與 Unity UI 型 GameObjects 互動 ,它應該位於 Canvas GameObject 底下。

藉由建立新的設定檔、指派 GameObject 本身和建立新主題,進一步執行按鈕。 此外,使用 OnClick 事件來發生問題。

注意

按鈕可按下 需要 PressableButton 元件。 此外, PhysicalPressEventRouter 漏斗圖按下事件需要元件給 Interactable 元件。

建立切換和多維度按鈕

切換按鈕

若要讓按鈕切換功能,請將 Selection Mode 欄位變更為輸入 Toggle 。 在 [ 設定檔] 區段中,會針對開啟 [互動 ] 時所使用的每個設定檔新增切換的主題。

SelectionMode當 設定為 [切換] 時,可以使用[IsToggled] 核取方塊,在執行時間初始化時設定控制項的預設值。

CanSelect表示CanDeselect代表反轉時,Interactable可以從開啟開啟

Profile Toggle Visual Themes Example

開發人員可以使用 SetToggledIsToggled 介面,透過程式碼取得/設定 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使用 元件來啟用這項功能。 此控制項可確保在任何指定時間只切換一個 InteractableRadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) 也是絕佳的起點。

若要建立自訂星形按鈕群組:

  1. 建立多個 Interactable GameObjects/buttons
  2. 設定每個 SelectionMode 互動 = Toggle、 CanSelect = true,以及 CanDeselect = false
  3. 在所有 Interactables 上建立空的父 GameObject,並新增 InteractableToggleCollection 元件
  4. 將所有Interactables新增至InteractableToggleCollection上的ToggleList
  5. 設定 InteractableToggleCollection.CurrentIndex 屬性,以判斷在啟動時預設選取的按鈕
Toggle collection

多維度按鈕

多維度選取模式可用來建立循序按鈕,或具有兩個步驟以上的按鈕,例如使用三個值控制速度:快速 (1x) 、快速 (2x) 或最快 (3x) 。

維度是數值時,最多可以新增 9 個主題,以控制每個速度設定按鈕的文字標籤或紋理,每個步驟使用不同的主題。

每次按一下事件都會在執行時間將 DimensionIndex 前 1 往前,直到 Dimensions 達到值為止。 然後迴圈會重設為 0。

Multi-Dimensional profile example

開發人員可以評估 , 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,以接聽可切換的 Interactable 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"));
}

另請參閱