Interagovatelné – MRTK2

Interagovatelné

Komponenta Interactable je kontejner typu all-in-one, který umožňuje snadnou interakci s libovolným objektem a odezvu na vstup. Interaktivně funguje jako univerzální funkce pro všechny typy vstupů, včetně dotykového ovládání, paprsků rukou, řeči atd., a tyto interakce se přenesou do událostí a odpovědí na vizuální motivy . Tato komponenta poskytuje snadný způsob vytváření tlačítek, změnu barvy objektů s fokusem a další možnosti.

Jak nakonfigurovat interagovatelné

Komponenta umožňuje tři primární části konfigurace:

  1. Obecná konfigurace vstupu
  2. Vizuální motivy cílené na více objektů GameObject
  3. Obslužné rutiny událostí

Obecné nastavení vstupu

Obecná interagovatelná nastavení

Stavy

States je parametr ScriptableObject , který definuje fáze interakcí, jako je stisknutí nebo pozorování, pro interagovatelné profily a vizuální motivy.

DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) je součástí sady MRTK a je výchozím parametrem pro interagovatelné komponenty.

Příklad States ScriptableObject v inspektoru

Prostředek DefaultInteractableStates obsahuje čtyři stavy a využívá implementaci InteractableStates modelu stavu.

  • Výchozí: Nic se neděje, jedná se o nejizolovanější základní stav.

  • Fokus: Objekt je nasměrován. Jedná se o jeden stav, žádné další stavy nejsou aktuálně nastavené, ale bude mít výchozí pořadí.

  • Stisknutí: Objekt je namířený a tlačítko nebo ruka jsou stisknuty. Stav stisknutí se řadí do pořadí Výchozí a Fokus. Tento stav se také nastaví jako záložní funkce fyzického stisknutí.

  • Zakázáno: Tlačítko by nemělo být interaktivní a vizuální zpětná vazba uživatele informuje, pokud z nějakého důvodu není toto tlačítko v tuto chvíli použitelné. Zakázaný stav může teoreticky obsahovat všechny ostatní stavy, ale když je vypnuto, stav Zakázáno bude převyšovat všechny ostatní stavy.

V závislosti na pořadí v seznamu se stavu přiřadí bitová hodnota (#).

Poznámka

Při vytváření interagovatelných komponent se obecně doporučuje používat DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset).

K dispozici je však 17 interagovatelných stavů, které lze použít k řízení motivů, i když některé mají být řízeny jinými komponentami. Tady je seznam těch, které mají integrované funkce.

  • Navštíveno: Bylo kliknuto na interagovatelný.
  • Přepíná: Tlačítko je v přepínacím stavu nebo index dimenze je liché číslo.
  • Gesto: Ruka nebo ovladač se stiskly a přesunuly se z původní pozice.
  • VoiceCommand: K aktivaci možnosti Interakce se použil hlasový příkaz.
  • PhysicalTouch: Právě se detekuje vstup dotykového ovládání, který se používá NearInteractionTouchable k povolení.
  • Uchopte: Ruka se právě chytá v mezích objektu.NearInteractionGrabbable

Povoleno

Přepíná, jestli se možnost Interakce spustí nebo ne. To odpovídá Interactable.IsEnabled kódu v kódu.

Vlastnost enabled interagovatelného se liší od povolené vlastnosti nakonfigurované přes GameObject/Component (tj. SetActive atd.). Zakázáním objektu GameObject nebo Interagovatelný monoBehaviour zakážete spuštění všeho ve třídě, včetně vstupů, vizuálních motivů, událostí atd. Zakázáním funkce via Interactable.IsEnabled zakážete většinu zpracování vstupů a resetováním souvisejících vstupních stavů. Třída však bude stále spouštět všechny snímky a přijímat vstupní události, které budou ignorovány. To je užitečné pro zobrazení možnosti Interakce v zakázaném stavu, což je možné provést prostřednictvím vizuálních motivů. Typickým příkladem může být tlačítko Odeslat, které čeká na dokončení všech požadovaných vstupních polí.

Vstupní akce

Vyberte vstupní akci z profilu mapování vstupní konfigurace nebo kontroleru, na kterou má interagovatelná komponenta reagovat.

Tuto vlastnost lze nakonfigurovat za běhu v kódu prostřednictvím Interactable.InputAction.

IsGlobal

Pokud je true, označí se komponenta jako globální vstupní naslouchací proces pro vybranou vstupní akci. Výchozí chování je nepravdivé, což omezí vstup pouze na tento interagovatelný u collider nebo GameObject.

Tuto vlastnost lze nakonfigurovat za běhu v kódu prostřednictvím Interactable.IsGlobal.

Příkaz pro řeč

Příkaz pro řeč z profilu hlasových příkazů MRTK k aktivaci události OnClick pro hlasovou interakci.

Tuto vlastnost lze nakonfigurovat za běhu v kódu prostřednictvím Interactable.VoiceCommand.

Vyžaduje fokus.

Pokud je hodnota true, hlasový příkaz aktivuje interagovatelný pouze v případě, že už má fokus z ukazatele. Pokud je hodnota false, bude interaktivně fungovat jako globální naslouchací proces pro vybraný hlasový příkaz. Výchozí chování je pravdivé, protože několik globálních naslouchacích procesů řeči může být obtížné uspořádat ve scéně.

Tuto vlastnost lze nakonfigurovat za běhu v kódu prostřednictvím Interactable.VoiceRequiresFocus.

Režim výběru

Tato vlastnost definuje logiku výběru. Po kliknutí na interaktivně se iteruje do další úrovně dimenze . Rozměry jsou podobné pořadí a definují stav mimo vstupy (tj. fokus, stisknutí atd.). Jsou užitečné pro definování přepínacích stavů nebo jiných stavů s více pořadími přidružených k tlačítku. Aktuální úroveň dimenze sleduje .Interactable.DimensionIndex

Dostupné režimy výběru jsou:

  • Tlačítko - Rozměry = 1, jednoduché kliknutí interagovatelné
  • Přepnout - Rozměry = 2, interagovatelné střídá stav zapnuto/
  • Více dimenzí - Dimenze>= 3, každé kliknutí zvyšuje aktuální úroveň dimenze + 1. Užitečné pro definování stavu tlačítka v seznamu atd.

Možnost interakce také umožňuje definovat více motivů pro každou dimenzi. Například při VýběruMode=Toggle může být jeden motiv použit, když je možnost Interagovatelnázrušena, a další motiv použit při výběru komponenty.

Aktuální režim výběru lze dotazovat za běhu prostřednictvím Interactable.ButtonMode. Aktualizace režimu za běhu lze dosáhnout nastavením Interactable.Dimensions vlastnosti tak, aby odpovídala požadované funkci. Aktuální dimenze, která je užitečná pro režimy Přepínač a Více dimenzí , je navíc přístupná přes Interactable.CurrentDimension.

Interagovatelné profily

Profily jsou položky, které vytvářejí relaci mezi objektem GameObject a vizuálním motivem. Profil definuje, s jakým obsahem bude motiv manipulovat, když dojde ke změně stavu.

Motivy fungují hodně jako materiály. Jedná se o skriptovatelné objekty, které obsahují seznam vlastností, které budou přiřazeny k objektu na základě aktuálního stavu. Motivy jsou také opakovaně použitelné a je možné je přiřadit několika interagovatelným objektům uživatelského prostředí.

Resetovat při zničení

Vizuální motivy upravují různé vlastnosti cílového objektu GameObject v závislosti na třídě a typu vybraného modulu motivu. Pokud je hodnota Reset On Destroy při zničení interagovatelné komponenty true, komponenta resetuje všechny upravené vlastnosti z aktivních motivů na původní hodnoty. V opačném případě po zničení interagovatelné komponenty ponechá všechny upravené vlastnosti tak, jak jsou. V tomto druhém případě zůstane poslední stav hodnot trvalý, pokud ho nezmění jiná externí komponenta. Výchozí hodnotou je hodnota false.

Profilové teamy

Události

Každá interagovatelná komponenta má událost OnClick , která se aktivuje, když je komponenta jednoduše vybrána. Interaktivně se ale dá rozpoznat jiné vstupní události než jen při kliknutí na tlačítko OnClick.

Kliknutím na tlačítko Přidat událost přidejte nový typ definice příjemce událostí. Po přidání vyberte požadovaný typ události.

Příklad událostí)

Existují různé typy příjemců událostí, které reagují na různé typy vstupů. MRTK se dodává s následující sadou přijímačů.

Vlastní přijímač lze vytvořit vytvořením nové třídy, která rozšiřuje ReceiverBase.

Příklad přijímače přepínače událostí

Příklad přepínacího příjemce událostí

Interagovatelné přijímače

Komponenta InteractableReceiver umožňuje definovat události mimo zdrojovou interagovatelnou komponentu. InteractableReceiver bude naslouchat filtrovanému typu události aktivovanému jiným interagovatelným. Pokud interagovatelný vlastnost není přiřazena přímo, pak obor vyhledávání vlastnost definuje směr InteractableReceiver naslouchá událostem, které jsou buď na sobě, v nadřazené, nebo v podřízené GameObject.

InteractableReceiverList funguje podobným způsobem, ale pro seznam odpovídajících událostí.

Interagovatelný reciver

Vytváření vlastních událostí

Podobně jako vizuální motivy se události dají rozšířit, aby zjistily jakýkoli stav nebo zpřístupňují funkce.

Vlastní události je možné vytvořit dvěma hlavními způsoby:

  1. Rozšířením ReceiverBase třídy vytvořte vlastní událost, která se zobrazí v rozevíracím seznamu typů událostí. Událost Unity je ve výchozím nastavení poskytována, ale je možné přidat další události Unity nebo ji lze nastavit tak, aby skrývala události Unity. Tato funkce umožňuje návrháři spolupracovat s inženýrem na projektu a vytvořit vlastní událost, kterou může návrhář nastavit v editoru.

  2. Rozšířením ReceiverBaseMonoBehavior třídy vytvořte zcela vlastní komponentu události, která se může nacházet na interagovatelném nebo jiném objektu. Bude ReceiverBaseMonoBehavior odkazovat na možnost Interagovatelná za účelem zjištění změn stavu.

Příklad rozšíření ReceiverBase

Třída CustomInteractablesReceiver zobrazí informace o stavu interagovatelné a je příkladem vytvoření vlastního příjemce událostí.

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

Následující metody jsou užitečné k přepsání nebo implementaci při vytváření vlastního příjemce událostí. ReceiverBase.OnUpdate() je abstraktní metoda, kterou lze použít k detekci vzorů a přechodů stavu. Metody a ReceiverBase.OnClick() jsou navíc ReceiverBase.OnVoiceCommand() užitečné pro vytváření vlastní logiky událostí, když je vybrána možnost Interaktivně.

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
}
Zobrazení polí příjemce vlastních událostí v inspektoru

Skripty ReceiverBase používají InspectorField atributy ke zveřejnění vlastních vlastností v inspektoru. Tady je příklad Vector3, vlastní vlastnosti s popisem a informacemi popisku. Tato vlastnost se zobrazí jako konfigurovatelná v inspektoru, když je vybrán interagovatelný gameobject a je přidán přidružený typ příjemce událostí .

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

Jak používat interagovatelné

Vytvoření jednoduchého tlačítka

Jednoduché tlačítko lze vytvořit přidáním interagovatelné komponenty do objektu GameObject, který je nakonfigurován pro příjem vstupních událostí. Může mít na něm nebo na podřízené sadě schytávače pro příjem vstupu. Pokud používáte Možnost interakce s objekty GameObjects založenými na uživatelském rozhraní Unity, měla by být pod objektem Canvas GameObject.

Udělejte tlačítko o krok dál tím, že vytvoříte nový profil, přiřadíte samotný objekt GameObject a vytvoříte nový motiv. Kromě toho použijte událost OnClick k tomu, aby se něco stalo.

Poznámka

Aby bylo tlačítko stisknutelné , vyžaduje komponentu PressableButton . Kromě toho je komponenta PhysicalPressEventRouter potřebná k trychtýřové stisknutí událostí do interagovatelné komponenty.

Vytváření přepínačů a tlačítek s více dimenzemi

Přepínací tlačítko

Pokud chcete nastavit, aby tlačítko bylo možné přepnout, změňte Selection Mode pole na typ Toggle. V části Profily se přidá nový přepínací motiv pro každý profil, který se použije, když je zapnutá možnost Interakce .

SelectionMode Zatímco je nastavena na Přepnout, lze zaškrtávací políčko IsToggled použít k nastavení výchozí hodnoty ovládacího prvku při inicializaci za běhu.

CanSelect znamená, že interagovatelné může přejít ze vypnutana zapnuto , zatímco CanDeselect znamená inverzní.

Příklad přepínacího tlačítka vizuálních motivů profilu

Vývojáři můžou pomocí SetToggled rozhraní a IsToggled získat nebo nastavit přepínací stav interagovatelného kódu.

// 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;
Přepnout kolekci tlačítek

Je běžné mít seznam přepínacích tlačítek, kde může být v daném okamžiku aktivní pouze jeden, známý také jako kruhová sada nebo přepínače atd.

InteractableToggleCollection K povolení této funkce použijte komponentu. Tento ovládací prvek zajišťuje, že je v daném okamžiku zapnutý jenom jeden interagovatelný . RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) je také skvělým výchozím bodem.

Vytvoření vlastní kruhové skupiny tlačítek:

  1. Vytvoření více interagovatelných herních objektů/tlačítek
  2. Nastavte každou interakci s selectionMode = Toggle, CanSelect = true a CanDeselect = false.
  3. Vytvořte prázdný nadřazený objekt GameObject pro všechny interaktivovatelné objekty a přidejte komponentu InteractableToggleCollection .
  4. Přidání všech interaktivovatelných položek do přepínače v části InteractableToggleCollection
  5. Nastavte vlastnost InteractableToggleCollection.CurrentIndex a určete, které tlačítko je při spuštění vybrané ve výchozím nastavení.
Přepnout kolekci

Multidimenzionální tlačítko

Režim výběru více dimenzí se používá k vytvoření sekvenčních tlačítek nebo tlačítka, které má více než dva kroky, například ovládání rychlosti třemi hodnotami: Rychle (1x), Rychlejší (2x) nebo Nejrychlejší (3x).

Rozměry jsou číselnou hodnotou a je možné přidat až 9 motivů pro ovládání textového popisku nebo textury tlačítka pro každé nastavení rychlosti pomocí jiného motivu pro každý krok.

Každá událost kliknutí posune DimensionIndex hodnotu o 1 za běhu, dokud Dimensions se nedosáhne hodnoty. Pak se cyklus resetuje na hodnotu 0.

Příklad multidimenzionálního profilu

Vývojáři můžou posoudit DimensionIndex , která dimenze je aktuálně aktivní.

// 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();

Vytváření interagovatelných za běhu

Za běhu lze snadno přidat do libovolného objektu GameObject. Následující příklad ukazuje, jak přiřadit profil s vizuálním motivem.

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()

Interagovatelné události prostřednictvím kódu

Pomocí následujícího příkladu můžete přidat akci do základní Interactable.OnClick události prostřednictvím kódu.

public static void AddOnClick(Interactable interactable)
{
    interactable.OnClick.AddListener(() => Debug.Log("Interactable clicked"));
}

Interactable.AddReceiver<T>() Pomocí funkce můžete dynamicky přidávat příjemce událostí za běhu.

Následující příklad kódu ukazuje, jak přidat InteractableOnFocusReceiver, který naslouchá fokusu enter/exit, a dále definovat kód akce, který se má provést, když se instance události aktivují.

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"));
}

Následující příklad kódu ukazuje, jak přidat InteractableOnToggleReceiver, který naslouchá vybraným nebo nevybraným přechodům stavu na přepínač-able Interactables, a dále definuje kód akce, který se má provést, když se instance události aktivují.

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"));
}

Viz také