這個 Interactable 元件是一個多功能容器,讓任何物件都能輕鬆 互動 並對輸入有反應。 Interactable 作為涵蓋所有類型輸入的綜合平台,包括觸覺、手部光線、語音等,並將這些互動引導成 事件 與 視覺主題 回應。 這個元件提供一個簡單的方式來製作按鈕、用焦點改變物件顏色等等。
如何設定 Interactable
該元件允許三個主要的配置區段:
一般輸入設定
州
States 是一個 ScriptableObject 參數,用來定義互動階段(如 press 或 observed),適用於 Interactable Profiles 和 Visual Themes。
DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) 隨 MRTK 一同附贈,且是 Interactable 元件的預設參數。
DefaultInteractableStates 資產包含四個狀態,並採用InteractableStates狀態模型實作。
預設:什麼都沒發生,這是最孤立的基底狀態。
焦點:物體被指向。 這只是單一狀態,目前沒有其他狀態,但它的排名會超越 Default。
按壓:物體被指向,按鈕或手在按下。 Press 狀態比 Default 和 Focus 更重要。 這個狀態也將成為實體印刷的備用方案。
停用:按鈕不應為互動式,視覺回饋會讓使用者知道此按鈕目前無法使用。 理論上,失能狀態可以包含所有其他狀態,但當啟用關閉時,失能狀態會凌駕於所有其他狀態之上。
根據清單中的順序,狀態會分配一個位元值 (#) 。
注意事項
一般建議在建立 Interactable 元件時,使用 DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) 。
然而,目前有 17 種可互動狀態可用來驅動主題,雖然有些是設計來由其他元件驅動的。 以下是內建功能的清單。
- 已造訪:互動互動平台已被點擊。
- 切換:按鈕處於切換狀態,或維度索引為奇數。
- 手勢:手或控制器被按下後,已從原位移動。
- VoiceCommand:使用語音指令觸發互動裝置。
- PhysicalTouch:目前偵測到觸控輸入,可用
NearInteractionTouchable來啟用。 - 抓取:一隻手正在物件範圍內抓取,用
NearInteractionGrabbable來啟用
Enabled
切換互動物件是否會啟用。 這對應於 in code Interactable.IsEnabled 。
互動物件的啟用屬性與透過 GameObject/Component (SetActive 等設定的啟用屬性不同) 。 停用 GameObject 或 Interactable MonoBehaviour 會讓類別中的所有功能都無法執行,包括輸入、視覺主題、事件等。關閉 via Interactable.IsEnabled 會停用大部分輸入處理,並重置相關的輸入狀態。 然而,該類別仍會執行每一幀並接收輸入事件,這些事件會被忽略。 這對於透過視覺主題(Visual Themes)顯示可互動物件(Interactable)的停用狀態非常有用。 典型例子是提交按鈕,等待所有必要的輸入欄位填寫完畢。
輸入動作
從輸入設定或控制器映射設定中選擇可互動元件應回應的輸入動作。
此特性可在執行時透過程式碼 Interactable.InputAction配置。
IsGlobal
若為真,則該元件將被標記為所選 輸入動作的全域輸入監聽器。 預設行為為 false,這會限制輸入只能用這個 Interactable collider/GameObject。
此特性可在執行時透過程式碼 Interactable.IsGlobal配置。
語音指令
語音指令,來自 MRTK 語音指令設定檔,用來觸發 OnClick 事件以進行語音互動。
此特性可在執行時透過程式碼 Interactable.VoiceCommand配置。
需要專注
如果是真的,語音指令只有在已經有指標焦點時才會啟動互動 裝置 。 若為 false,Interactable 將作為所選語音指令的全域監聽器。 預設行為成立,因為多個全域語音聆聽者在場景中組織起來可能很困難。
此特性可在執行時透過程式碼 Interactable.VoiceRequiresFocus配置。
選擇模式
此性質定義了選擇邏輯。 當點擊互動 物件 時,會迭代到下一個 維度 層級。
維度 類似於等級,定義了輸入之外的狀態, (例如聚焦、按壓等) 。 它們對於定義切換狀態或其他與按鈕相關的多秩狀態非常有用。 目前的維度層級由 Interactable.DimensionIndex追蹤。
可用的選擇模式包括:
- 按鈕 - 尺寸 = 1,簡單可點擊 互動
- 切換 - 維度 = 2,互動式在開關/狀態間交替
- 多維 - 度尺寸>= 3,每次點擊都會增加當前維度等級 + 1。 這對於定義按鍵狀態到清單等很有用。
Interactable 也允許每個 維度定義多個主題。 例如,當 SelectionMode = Toggle 時,當 Interactable取消選擇 時,可能會套用一個主題,當 選擇元件時套用另一個主題。
目前的選擇模式可在執行時透過 Interactable.ButtonMode查詢。 執行時更新模式可透過設定 Interactable.Dimensions 屬性以符合所需功能來實現。 此外,當前維度可用於 切換 模式與 多維 模式,可透過 Interactable.CurrentDimension存取。
可互動的設定檔
設定檔 是建立遊戲物件與 視覺主題之間關係的項目。 設定檔定義了當 狀態變更時,主題將操作哪些內容。
主題的運作方式很像材料。 它們是可腳本化的物件,包含一串屬性清單,根據當前狀態會被指派給物件。 主題也可重複使用,並可跨多個 可互動 的使用者體驗物件指派。
摧毀重置
視覺主題會根據所選主題引擎的類別與類型,修改目標 GameObject 上的各種屬性。 如果在 Interactable 元件被銷毀時 Reset On Destroy 為真,該元件會將所有已修改的主題屬性重設為原始值。 否則,當被銷毀時,Interactable 元件會保留所有修改過的屬性。 在後者情況下,除非被其他外部元件改變,否則最後的數值狀態會持續存在。 預設值為假。
Events
每個 Interactable 元件都有一個 OnClick 事件,當元件被直接選取時就會觸發。 然而, Interactable 也可用於偵測除 OnClick 以外的輸入事件。
點擊 「新增事件 」按鈕以新增一種事件接收器定義。 新增後,選擇想要的事件類型。
)
有不同類型的事件接收器,用以回應不同類型的輸入。 MRTK 出廠時配備以下一組接收器。
InteractableAudioReceiverInteractableOnClickReceiverInteractableOnFocusReceiverInteractableOnGrabReceiverInteractableOnHoldReceiverInteractableOnPressReceiverInteractableOnToggleReceiverInteractableOnTouchReceiver
可透過建立一個擴展 ReceiverBase的類別來建立自訂接收器。
切換事件接收器範例
可互動接收器
該 InteractableReceiver 元件允許在原始 互動 元件之外定義事件。
InteractableReceiver 會監聽其他 Interactable 觸發的過濾事件類型。 若 Interactable 屬性未直接指派,則 搜尋範圍 屬性定義 InteractableReceiver 監聽事件的方向,該方向可能位於自身、父節點或子 GameObject 中。
InteractableReceiverList 行為方式類似,但會列出一串匹配事件。
建立自訂事件
如同 視覺主題,事件可擴展以偵測任何狀態模式或揭露功能。
自訂事件主要有兩種方式:
擴充類別
ReceiverBase以建立一個自訂事件,該事件會出現在事件類型的下拉選單中。 Unity 事件預設提供,但可以新增更多 Unity 事件,或設定該事件隱藏 Unity 事件。 此功能讓設計師能與工程師合作,在專案中建立自訂事件,設計師可在編輯器中設定。擴充類別
ReceiverBaseMonoBehavior,建立一個完全自訂的事件元件,可以駐留在 Interactable 或其他物件上。 它ReceiverBaseMonoBehavior會參考 Interactable 來偵測狀態變化。
延伸的例子 ReceiverBase
該 CustomInteractablesReceiver 類別會顯示互動 物件 的狀態資訊,並示範如何建立自訂事件接收器。
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 的範例,一個自訂屬性,包含提示和標籤資訊。 當選取 可互動 的 GameObject 並新增相關 事件接收 器類型時,這個屬性會在檢查器中顯示為可配置。
[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;
如何使用 Interactable(互動互動)
製作一個簡單的按鈕
可以透過在設定接收輸入事件的 GameObject 中加入 Interactable 元件來建立一個簡單的按鈕。 它可以裝有碰撞器,也可以在子節點上接收輸入。 如果使用 Interactable 搭配基於 Unity UI 的 GameObjects,應該是在 Canvas GameObject 底下。
再往前一步,建立新的設定檔,指派 GameObject 本身,並建立新主題。 此外,利用 OnClick 事件來促成一些事情。
注意事項
要讓按鈕可按,需要元件。PressableButton 此外,該 PhysicalPressEventRouter 元件也需要將新聞事件導向 Interactable 元件。
製作切換與多維按鈕
切換按鈕
要讓按鈕可切換,請將欄位改 Selection Mode 為 Toggle。 在 Profiles 區塊中,每個設定檔會新增一個切換主題,當 Interactable 開啟時會使用該設定檔。
當 設定 SelectionMode 為 Toggle 時, IsToggled 勾選框可用來設定執行時初始化時控制項的預設值。
CanSelect 代表 互動器 可以從 關閉 切換到 開啟 ,而 CanDeSelect 則是反過來。
開發者可以利用 和 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 元件來啟用此功能。 此控制確保任何時候只開啟一個 互動裝置 。
RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) 也是開箱即用的好起點。
要建立自訂的環狀按鈕群組:
- 建立多個 可互動 的遊戲物件/按鈕
- 將每個互動式設定為 SelectionMode = Toggle,CanSelect = true,CanDeSelect = false
- 在所有 Interactables 上建立一個空的父 GameObject,並新增 InteractableToggleCollection 元件
- 將所有互動物件加入 InteractableToggleCollection 的 ToggleList
- 設定 InteractableToggleCollection.CurrentIndex 屬性,決定開始時預設選擇的按鈕
多維按鈕
多維度選擇模式用於建立連續按鈕,或是有超過兩步的按鈕,例如以三個數值控制速度:快速 (1) 、更快 (2) 或最快 (3) 。
由於尺寸為數值,最多可新增 9 個主題來控制每個速度設定的文字標籤或按鈕材質,每個步驟使用不同的主題。
每次點擊事件在執行時會將 前進 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,該接收器會監聽可切換互動 物件的選取/取消狀態轉換,並定義事件實例觸發時執行的動作程式碼。
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"));
}