Interactiebaar — MRTK2

Interactiebaar

Het Interactable onderdeel is een alles-in-één-container waarmee elk object gemakkelijk kan worden gebruikt en reageert op invoer. Interactiebaar fungeert als een catch-all voor alle soorten invoer, waaronder aanraking, handstralen, spraak, enzovoort en trechter deze interacties in gebeurtenissen en visuele themareacties . Dit onderdeel biedt een eenvoudige manier om knoppen te maken, de kleur van objecten met focus te wijzigen en meer.

Interactie configureren

Het onderdeel maakt drie primaire secties van de configuratie mogelijk:

  1. Algemene invoerconfiguratie
  2. Visuele thema's gericht op meerdere GameObjects
  3. Event Handlers

Algemene invoerinstellingen

Algemene instellingen voor interactie

Staten

Statussen is een ScriptableObject-parameter die de interactiefasen definieert, zoals persen of waargenomen, voor interactiebare profielen en visuele thema's.

De DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) wordt geleverd met MRTK out-of-box en is de standaardparameter voor interactable-onderdelen .

Statussen ScriptableObject-voorbeeld in inspector

De asset DefaultInteractableStates bevat vier statussen en maakt gebruik van de implementatie van het InteractableStates statusmodel.

  • Standaardinstelling: er gebeurt niets, dit is de meest geïsoleerde basisstatus.

  • Focus: het object wordt naar gericht. Dit is één status, er zijn momenteel geen andere statussen ingesteld, maar de status wordt hoger dan standaard.

  • Druk op: het object wordt gericht en er wordt een knop of hand ingedrukt. De status Pers uit rangschikt Standaard en Focus. Deze status wordt ook ingesteld als een terugval naar fysieke pers.

  • Uitgeschakeld: de knop mag niet interactief zijn en visuele feedback laat de gebruiker weten of deze knop om een of andere reden op dit moment niet bruikbaar is. In theorie kan de uitgeschakelde status alle andere statussen bevatten, maar wanneer Ingeschakeld is uitgeschakeld, overtroeft de status Uitgeschakeld alle andere statussen.

Een bitwaarde (#) wordt toegewezen aan de status, afhankelijk van de volgorde in de lijst.

Notitie

Het wordt over het algemeen aanbevolen om de DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) te gebruiken bij het maken van Interactable-onderdelen .

Er zijn echter 17 interactiebare statussen beschikbaar die kunnen worden gebruikt om thema's aan te drijven, hoewel sommige zijn bedoeld om te worden aangestuurd door andere onderdelen. Hier volgt een lijst met functies met ingebouwde functionaliteit.

  • Bezocht: op Interactiebaar is geklikt.
  • Wisselknop: de knop heeft een wisselknop of dimensie-index is een oneven getal.
  • Gebaar: De hand of controller is ingedrukt en is verplaatst van de oorspronkelijke positie.
  • VoiceCommand: er is een spraakopdracht gebruikt om interactie te activeren.
  • PhysicalTouch: er is momenteel aanraakinvoer gedetecteerd. Gebruik NearInteractionTouchable om dit in te schakelen.
  • Grab: een hand grijpt momenteel binnen de grenzen van het object, gebruik NearInteractionGrabbable om in te schakelen

Ingeschakeld

Hiermee kunt u instellen of een interactiebare wordt ingeschakeld of niet. Dit komt overeen met de Interactable.IsEnabled in code.

De ingeschakelde eigenschap van een Interactable is anders dan de ingeschakelde eigenschap die is geconfigureerd via GameObject/Component (bijvoorbeeld SetActive, enzovoort). Als u het GameObject of Interactable MonoBehaviour uitschakelt, wordt alles in de klasse uitgeschakeld, inclusief invoer, visuele thema's, gebeurtenissen, enzovoort. Als u via Interactable.IsEnabled uitschakelt, wordt de meeste invoerverwerking uitgeschakeld en worden gerelateerde invoerstatussen opnieuw ingestelde. De klasse voert echter nog steeds elk frame uit en ontvangt invoergebeurtenissen die worden genegeerd. Dit is handig voor het weergeven van interactie in een uitgeschakelde status, wat kan worden gedaan via visuele thema's. Een typisch voorbeeld hiervan is een verzendknop die wacht totdat alle vereiste invoervelden zijn voltooid.

Invoeracties

Selecteer de invoeractie in het profiel voor de invoerconfiguratie of controllertoewijzing waarop het onderdeel Interactie moet reageren.

Deze eigenschap kan tijdens runtime in code worden geconfigureerd via Interactable.InputAction.

IsGlobal

Als dit waar is, wordt het onderdeel gemarkeerd als een globale invoerlistener voor de geselecteerde invoeractie. Standaardgedrag is false, waardoor invoer wordt beperkt tot alleen deze Interactable collider/GameObject.

Deze eigenschap kan tijdens runtime in code worden geconfigureerd via Interactable.IsGlobal.

Spraakopdracht

Spraakopdracht uit het MRTK-profiel voor spraakopdrachten om een OnClick-gebeurtenis te activeren voor spraakinteractie.

Deze eigenschap kan tijdens runtime in code worden geconfigureerd via Interactable.VoiceCommand.

Focus vereist

Als dit waar is, activeert de spraakopdracht alleen de Interactiebaar als en alleen als deze al de focus van een aanwijzer heeft. Als dit onwaar is, fungeert de Interactiebare als een globale listener voor de geselecteerde spraakopdracht. Het standaardgedrag is waar, omdat meerdere globale spraaklisteners moeilijk te organiseren zijn in een scène.

Deze eigenschap kan tijdens runtime in code worden geconfigureerd via Interactable.VoiceRequiresFocus.

Selectiemodus

Deze eigenschap definieert de selectielogica. Wanneer op een Interactiebaar wordt geklikt, wordt deze naar een volgend dimensieniveau herhaald. Dimensies is vergelijkbaar met rangschikken en definieert een status buiten de invoer (bijvoorbeeld focus, druk, enzovoort). Ze zijn handig voor het definiëren van wisselstanden of andere statussen met meerdere rangschikkingen die zijn gekoppeld aan een knop. Het huidige dimensieniveau wordt bijgehouden door Interactable.DimensionIndex.

De beschikbare selectiemodi zijn:

  • Knop - Dimensies = 1, eenvoudig klikbaar Interactiebaar
  • Knevel - Dimensies = 2, Wisselbare wisselt tussenaan-uit-status/
  • Meerdere dimensies - Dimensies>= 3, elke klik verhoogt het huidige dimensieniveau + 1. Handig voor het definiëren van een knopstatus voor een lijst, enzovoort.

Met interactie kunnen ook meerdere thema's per dimensie worden gedefinieerd. Wanneer SelectionMode=Wisselknop bijvoorbeeld wordt ingeschakeld, kan het ene thema worden toegepast wanneer de optie Interactie isuitgeschakeld en een ander thema wanneer het onderdeel wordt geselecteerd.

De huidige selectiemodus kan tijdens runtime worden opgevraagd via Interactable.ButtonMode. Het bijwerken van de modus tijdens runtime kan worden bereikt door de Interactable.Dimensions eigenschap zo in te stellen dat deze overeenkomt met de gewenste functionaliteit. Bovendien is de huidige dimensie, handig voor wissel - en multidimensiemodi , toegankelijk via Interactable.CurrentDimension.

Interactiebare profielen

Profielen zijn items die een relatie maken tussen een GameObject en een visueel thema. Het profiel definieert welke inhoud door een thema wordt bewerkt wanneer een statuswijziging plaatsvindt.

Thema's werken veel op materialen. Het zijn scriptbare objecten die een lijst met eigenschappen bevatten die worden toegewezen aan een object op basis van de huidige status. Thema's zijn ook herbruikbaar en kunnen worden toegewezen aan meerdere interactiebare UX-objecten.

Opnieuw instellen bij vernietiging

Visuele thema's wijzigen verschillende eigenschappen op een doel-GameObject, afhankelijk van de klasse en het type thema-engine die is geselecteerd. Als Opnieuw instellen bij vernietigen waar is wanneer het onderdeel interactiebaar wordt vernietigd, worden alle gewijzigde eigenschappen van actieve thema's opnieuw ingesteld op de oorspronkelijke waarden. Als dit niet het geval is, laat het onderdeel Interactie eventuele gewijzigde eigenschappen staan. In dit laatste geval blijft de laatste status van waarden behouden, tenzij deze wordt gewijzigd door een ander extern onderdeel. De standaardwaarde is false.

Theams profilen

gebeurtenis

Elk onderdeel met interactie heeft een OnClick-gebeurtenis die wordt geactiveerd wanneer het onderdeel gewoon is geselecteerd. Interactie kan echter worden gebruikt om andere invoerevenementen dan alleen OnClick te detecteren.

Klik op de knop Gebeurtenis toevoegen om een nieuw type definitie van gebeurtenisontvanger toe te voegen. Zodra het is toegevoegd, selecteert u het gewenste type gebeurtenis.

Voorbeeld van gebeurtenissen)

Er zijn verschillende soorten gebeurtenisontvangers om te reageren op verschillende typen invoer. MRTK wordt geleverd met de volgende set ontvangers out-of-box.

Een aangepaste ontvanger kan worden gemaakt door een nieuwe klasse te maken die zich uitbreidt.ReceiverBase

Voorbeeld van gebeurtenisknopontvanger

Voorbeeld van een wissel-gebeurtenisontvanger

Interactiebare ontvangers

Met InteractableReceiver het onderdeel kunnen gebeurtenissen worden gedefinieerd buiten het brononderdeel Interactiebaar . De InteractableReceiver luistert naar een gefilterd gebeurtenistype dat wordt geactiveerd door een andere Interactiebare. Als de eigenschap Interactiebaar niet rechtstreeks is toegewezen, definieert de eigenschap Zoekbereik de richting waarin de InteractableReceiver luistert naar gebeurtenissen die zich op zichzelf, in een bovenliggend item of in een onderliggend GameObject bevinden.

InteractableReceiverList werkt op een vergelijkbare manier, maar voor een lijst met overeenkomende gebeurtenissen.

Interactiebare ontvanger

Aangepaste gebeurtenissen maken

Net als bij visuele thema's kunnen gebeurtenissen worden uitgebreid om een statuspatroon te detecteren of om functionaliteit beschikbaar te maken.

Aangepaste gebeurtenissen kunnen op twee manieren worden gemaakt:

  1. Breid de ReceiverBase klasse uit om een aangepaste gebeurtenis te maken die wordt weergegeven in de vervolgkeuzelijst met gebeurtenistypen. Een Unity-gebeurtenis wordt standaard geleverd, maar er kunnen extra Unity-gebeurtenissen worden toegevoegd of de gebeurtenis kan worden ingesteld om Unity-gebeurtenissen te verbergen. Met deze functionaliteit kan een ontwerper samenwerken met een technicus aan een project om een aangepaste gebeurtenis te maken die de ontwerper in de editor kan instellen.

  2. Breid de ReceiverBaseMonoBehavior klasse uit om een volledig aangepast gebeurtenisonderdeel te maken dat zich kan bevinden op het interactiebare of een ander object. De ReceiverBaseMonoBehavior verwijst naar de Interactiebaar om statuswijzigingen te detecteren.

Voorbeeld van uitbreiden ReceiverBase

De CustomInteractablesReceiver klasse geeft statusinformatie weer over een Interactiebaar en is een voorbeeld van het maken van een aangepaste gebeurtenisontvanger.

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

De volgende methoden zijn handig om te overschrijven/implementeren bij het maken van een aangepaste gebeurtenisontvanger. ReceiverBase.OnUpdate() is een abstracte methode die kan worden gebruikt om statuspatronen/overgangen te detecteren. Bovendien zijn de ReceiverBase.OnVoiceCommand() methoden en ReceiverBase.OnClick() handig voor het maken van aangepaste gebeurtenislogica wanneer interactie mogelijk is geselecteerd.

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
}
Aangepaste velden voor gebeurtenisontvanger weergeven in de inspector

ReceiverBase-scripts gebruiken InspectorField kenmerken om aangepaste eigenschappen beschikbaar te maken in de inspector. Hier volgt een voorbeeld van Vector3, een aangepaste eigenschap met knopinfo en labelinformatie. Deze eigenschap wordt weergegeven als configureerbaar in de inspector wanneer een interactable GameObject is geselecteerd en het bijbehorende type gebeurtenisontvanger is toegevoegd.

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

Interactiebaar gebruiken

Een eenvoudige knop maken

U kunt een eenvoudige knop maken door het onderdeel Interactie toe te voegen aan een GameObject dat is geconfigureerd voor het ontvangen van invoergebeurtenissen. Er kan een collider op staan of op een kind om invoer te ontvangen. Als u Interactable gebruikt met een GameObjects op basis van de Unity-gebruikersinterface, moet dit zich onder het Canvas GameObject bevinden.

Ga nog een stap verder door een nieuw profiel te maken, het GameObject zelf toe te wijzen en een nieuw thema te maken. Gebruik bovendien de gebeurtenis OnClick om iets te laten gebeuren.

Notitie

Als u een knop wilt indrukken , is het PressableButton onderdeel vereist. Daarnaast is het PhysicalPressEventRouter onderdeel nodig om gebeurtenissen naar het onderdeel Interactie te verzenden.

Wisselknoppen en knoppen met meerdere dimensies maken

Wisselknop

Als u een knop in-/uitschakelen wilt maken, wijzigt u het Selection Mode veld om te typen Toggle. In de sectie Profielen wordt een nieuw wisselthema toegevoegd voor elk profiel dat wordt gebruikt wanneer de wisselknop Interactie mogelijk is ingeschakeld.

Terwijl de SelectionMode is ingesteld op Wisselknop, kan het selectievakje IsToggled worden gebruikt om de standaardwaarde van het besturingselement in te stellen bij runtime-initialisatie.

CanSelect betekent dat de Interactiebare van naaraan kan gaan, terwijl CanDeselect de inverse betekent.

Voorbeeld van profielknop voor visuele thema's

Ontwikkelaars kunnen de SetToggled interfaces en IsToggled gebruiken om de wisselknopstatus van een interactiebaar via code op te halen/in te stellen.

// 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;
Wisselknopverzameling

Het is gebruikelijk om een lijst met wisselknoppen te hebben waarbij slechts één op elk gewenst moment actief kan zijn, ook wel bekend als een radiale set of keuzerondjes, enzovoort.

Gebruik het InteractableToggleCollection onderdeel om deze functionaliteit in te schakelen. Dit besturingselement zorgt ervoor dat er op elk moment slechts één interactie mogelijk is ingeschakeld. RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) is ook een goed uitgangspunt.

Een aangepaste radiale knopgroep maken:

  1. Meerdere interactiebare GameObjects/knoppen maken
  2. Stel elke interactie in met SelectionMode = Wisselknop, CanSelect = true en CanDeselect = false
  3. Maak een leeg bovenliggend GameObject voor alle Interactables en voeg het onderdeel InteractableToggleCollection toe
  4. Alle Interactables toevoegen aan de ToggleList op de InteractableToggleCollection
  5. Stel de eigenschap InteractableToggleCollection.CurrentIndex in om te bepalen welke knop standaard is geselecteerd bij het starten
Verzameling in-/uitschakelen

Multidimensionale knop

De selectiemodus voor meerdere dimensies wordt gebruikt om opeenvolgende knoppen te maken, of een knop met meer dan twee stappen, zoals het regelen van de snelheid met drie waarden, Snel (1x), Sneller (2x) of Snelste (3x).

Omdat dimensies een numerieke waarde zijn, kunnen er maximaal 9 thema's worden toegevoegd om het tekstlabel of het patroon van de knop voor elke snelheidsinstelling te bepalen, met behulp van een ander thema voor elke stap.

Elke klik-gebeurtenis gaat met 1 naar runtime DimensionIndex totdat de Dimensions waarde is bereikt. Vervolgens wordt de cyclus opnieuw ingesteld op 0.

Voorbeeld van multidimensionaal profiel

Ontwikkelaars kunnen de DimensionIndex evalueren om te bepalen welke dimensie momenteel actief is.

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

Interactiebaar maken tijdens runtime

Interactiebaar kan eenvoudig worden toegevoegd aan elk GameObject tijdens runtime. In het volgende voorbeeld ziet u hoe u een profiel met een visueel thema toewijst.

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

Interactiebare gebeurtenissen via code

U kunt een actie toevoegen aan de basisgebeurtenis Interactable.OnClick via code met het volgende voorbeeld.

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

Gebruik de Interactable.AddReceiver<T>() functie om gebeurtenisontvangers dynamisch toe te voegen tijdens runtime.

In de onderstaande voorbeeldcode ziet u hoe u een InteractableOnFocusReceiver toevoegt, die luistert naar het invoeren/afsluiten van de focus en bovendien actiecode definieert die moet worden uitgevoerd wanneer de gebeurtenisexemplaren worden geactiveerd.

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

De onderstaande voorbeeldcode laat zien hoe u een InteractableOnToggleReceiver toevoegt, die luistert naar geselecteerde/gedeselecteerde statusovergangen op wisselbare Interactables, en bovendien de actiecode definieert die moet worden uitgevoerd wanneer de gebeurtenisexemplaren worden geactiveerd.

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

Zie ook