Interaktionsbar – MRTK2

Interaktionsbar

Komponenten Interactable är en allt-i-ett-container som gör alla objekt lätt att interagera och svara på indata. Interaktionsbar fungerar som en catch-all för alla typer av indata, inklusive beröring, handstrålar, tal osv. och trattar dessa interaktioner till händelser och visuella temasvar . Den här komponenten är ett enkelt sätt att skapa knappar, ändra färg på objekt med fokus och mycket mer.

Så här konfigurerar du Interaktionsbar

Komponenten tillåter tre primära delar av konfigurationen:

  1. Allmän indatakonfiguration
  2. Visuella teman riktade mot flera GameObjects
  3. Händelsehanterare

Allmänna indatainställningar

Allmänna interaktionsbara inställningar

Tillstånd

States är en ScriptableObject-parameter som definierar interaktionsfaserna, t.ex. tryck eller observerad, för interaktionsbara profiler och visuella teman.

DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) levereras med MRTK och är standardparametern för interaktionsbara komponenter.

Exempel på tillstånd ScriptableObject i inspector

Tillgången DefaultInteractableStates innehåller fyra tillstånd och använder implementeringen av InteractableStates tillståndsmodellen.

  • Standard: Ingenting händer, det här är det mest isolerade bastillståndet.

  • Fokus: Objektet pekas på. Det här är ett enskilt tillstånd, inga andra tillstånd har angetts för närvarande, men det kommer att rangordna Standard.

  • Tryck: Objektet pekas på och en knapp eller hand trycker. Läget Tryck ut rangordnar Standard och Fokus. Det här tillståndet anges också som en återställning till Fysisk press.

  • Inaktiverad: Knappen ska inte vara interaktiv och visuell feedback meddelar användaren om den här knappen av någon anledning inte kan användas just nu. I teorin kan det inaktiverade tillståndet innehålla alla andra tillstånd, men när Aktiverad är inaktiverad trumfar den inaktiverade staten alla andra stater.

Ett bitvärde (#) tilldelas till tillståndet beroende på ordningen i listan.

Anteckning

Vi rekommenderar vanligtvis att du använder DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) när du skapar komponenter som kan interagera .

Det finns dock 17 tillgängliga interaktionsbara tillstånd som kan användas för att driva teman, även om vissa är avsedda att drivas av andra komponenter. Här är en lista över dem med inbyggda funktioner.

  • Besökt: Interaktionsbar har klickats.
  • Växlad: Knappen är i ett växlat tillstånd eller dimensionsindex är ett udda tal.
  • Gest: Handen eller styrenheten trycktes på och har flyttats från den ursprungliga positionen.
  • VoiceCommand: Ett talkommando användes för att utlösa det interaktionsbara kommandot.
  • PhysicalTouch: En touch-indata identifieras för närvarande och används NearInteractionTouchable för att aktivera.
  • Greppa: En hand håller på att ta tag i objektets gränser, använd NearInteractionGrabbable för att aktivera

Aktiverad

Växlar om en interaktionsbar startar aktiverad eller inte. Detta motsvarar koden Interactable.IsEnabled i .

En interactables aktiverade egenskap skiljer sig från den aktiverade egenskapen som konfigurerats via GameObject/Component (t.ex. SetActive osv.). Om du inaktiverar GameObject eller Interactable MonoBehaviour inaktiveras allt i klassen från att köras, inklusive indata, visuella teman, händelser osv. Om du inaktiverar via Interactable.IsEnabled inaktiveras de flesta indatahantering, vilket återställer relaterade indatatillstånd. Klassen kommer dock fortfarande att köra varje bildruta och ta emot indatahändelser som ignoreras. Det här är användbart för att visa det interaktionsbara objektet i ett inaktiverat tillstånd, vilket kan göras via visuella teman. Ett typiskt exempel på detta är en skicka-knapp som väntar på att alla obligatoriska indatafält ska slutföras.

Indataåtgärder

Välj indataåtgärden från den mappningsprofil för indatakonfigurationen eller kontrollanten som komponenten Interaktionsbar ska reagera på.

Den här egenskapen kan konfigureras vid körning i kod via Interactable.InputAction.

IsGlobal

Om det är sant markeras komponenten som en global indatalyssnare för den valda indataåtgärden. Standardbeteendet är falskt, vilket begränsar indata till endast denna interaktionsbara collider/GameObject.

Den här egenskapen kan konfigureras vid körning i kod via Interactable.IsGlobal.

Talkommando

Talkommando, från MRTK Speech Commands-profilen, för att utlösa en OnClick-händelse för röstinteraktion.

Den här egenskapen kan konfigureras vid körning i kod via Interactable.VoiceCommand.

Kräver fokus

Om det är sant aktiverar röstkommandot endast interaktionsbar om och endast om den redan har fokus från en pekare. Om det är falskt fungerar Interactable som global lyssnare för det valda röstkommandot. Standardbeteendet är sant eftersom flera globala tallyssnare kan vara svåra att organisera i en scen.

Den här egenskapen kan konfigureras vid körning i kod via Interactable.VoiceRequiresFocus.

Markeringsläge

Den här egenskapen definierar urvalslogik. När en interaktionsbar klickar på itereras den till nästa dimensionsnivå . Dimensioner liknar rangordning och definierar ett tillstånd utanför indata (dvs. fokus, tryck osv.). De är användbara för att definiera växlingslägen eller andra flerrankade tillstånd som är associerade med en knapp. Den aktuella dimensionsnivån spåras av Interactable.DimensionIndex.

Tillgängliga urvalslägen är:

  • Knappen - Dimensioner = 1, enkel klickbar interaktionsbar
  • Växla - Dimensioner = 2, Interaktionsbara alternativ mellan avstängt/ tillstånd
  • Flera dimensioner - Dimensioner>= 3, varje klick ökar den aktuella dimensionsnivån + 1. Användbart för att definiera ett knapptillstånd till en lista osv.

Interaktionsbar gör det också möjligt att definiera flera teman per dimension. När till exempel SelectionMode=Växla kan ett tema tillämpas när interaktionsbar är avmarkerat och ett annat tema används när komponenten väljs.

Det aktuella markeringsläget kan efterfrågas vid körning via Interactable.ButtonMode. Du kan uppdatera läget vid körning genom att ange Interactable.Dimensions egenskapen så att den matchar önskade funktioner. Dessutom kan den aktuella dimensionen, som är användbar för växlingslägen och flerdimensionslägen , nås via Interactable.CurrentDimension.

Interaktionsbara profiler

Profiler är objekt som skapar en relation mellan ett GameObject och ett visuellt tema. Profilen definierar vilket innehåll som ska manipuleras av ett tema när en tillståndsändring sker.

Teman fungerar mycket som material. De är skriptbara objekt som innehåller en lista över egenskaper som ska tilldelas till ett objekt baserat på det aktuella tillståndet. Teman kan också återanvändas och kan tilldelas över flera interaktionsbara UX-objekt.

Återställ vid förstöring

Visuella teman ändrar olika egenskaper för en riktad GameObject, beroende på vilken klass och typ av temamotor som valts. Om Reset On Destroy är sant när komponenten Interactable förstörs återställer komponenten alla ändrade egenskaper från aktiva teman till deras ursprungliga värden. Annars lämnar den interaktionsbara komponenten alla ändrade egenskaper som de är när de förstörs. I det senare fallet bevaras det sista tillståndet för värden om det inte ändras av en annan extern komponent. Standardvärdet är False.

Profilera flöden

Händelser

Varje interaktionsbar komponent har en OnClick-händelse som utlöses när komponenten helt enkelt väljs. Interaktionsbar kan dock användas för att identifiera andra indatahändelser än bara OnClick.

Klicka på knappen Lägg till händelse för att lägga till en ny typ av definition av händelsemottagare. När du har lagt till väljer du den typ av händelse som önskas.

Exempel på händelser)

Det finns olika typer av händelsemottagare som svarar på olika typer av indata. MRTK levereras med följande uppsättning mottagare in-of-box.

En anpassad mottagare kan skapas genom att skapa en ny klass som utökar ReceiverBase.

Exempel på händelseväxlingsmottagare

Exempel på en växlingshändelsemottagare

Interagerande mottagare

Komponenten InteractableReceiver gör att händelser kan definieras utanför källans interaktionsbara komponent. InteractableReceiver lyssnar efter en filtrerad händelsetyp som utlösts av en annan interaktionsbar fil. Om egenskapen Interactable inte är direkt tilldelad definierar egenskapen Sökomfång riktningen som InteractableReceiver lyssnar efter händelser som antingen är på sig själv, i en överordnad eller i ett underordnat GameObject.

InteractableReceiverList fungerar på ett liknande sätt men för en lista över matchande händelser.

Interagerande reciver

Skapa anpassade händelser

Precis som visuella teman kan händelser utökas för att identifiera alla tillståndsmönster eller för att exponera funktioner.

Anpassade händelser kan skapas på två huvudsakliga sätt:

  1. ReceiverBase Utöka klassen för att skapa en anpassad händelse som visas i listrutan med händelsetyper. En Unity-händelse tillhandahålls som standard, men ytterligare Unity-händelser kan läggas till eller så kan händelsen anges för att dölja Unity-händelser. Med den här funktionen kan en designer arbeta med en tekniker i ett projekt för att skapa en anpassad händelse som designern kan konfigurera i redigeraren.

  2. ReceiverBaseMonoBehavior Utöka klassen för att skapa en helt anpassad händelsekomponent som kan finnas på objektet Interactable eller ett annat objekt. ReceiverBaseMonoBehavior Kommer att referera till Interactable för att identifiera tillståndsändringar.

Exempel på förlängning ReceiverBase

Klassen CustomInteractablesReceiver visar statusinformation om en interaktionsbar och är ett exempel på hur du skapar en anpassad händelsemottagare.

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

Följande metoder är användbara för att åsidosätta/implementera när du skapar en anpassad händelsemottagare. ReceiverBase.OnUpdate() är en abstrakt metod som kan användas för att identifiera tillståndsmönster/övergångar. Dessutom ReceiverBase.OnVoiceCommand() är metoderna och ReceiverBase.OnClick() användbara för att skapa anpassad händelselogik när interaktionsbar har valts.

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
}
Visa anpassade fält för händelsemottagare i inspektören

ReceiverBase-skript använder InspectorField attribut för att exponera anpassade egenskaper i inspektören. Här är ett exempel på Vector3, en anpassad egenskap med knappbeskrivning och etikettinformation. Den här egenskapen visas som konfigurerbar i inspektören när en Interaktionsbar GameObject har valts och har den associerade händelsemottagartypen tillagd.

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

Så här använder du Interaktionsbar

Skapa en enkel knapp

Man kan skapa en enkel knapp genom att lägga till komponenten Interactable i en GameObject som är konfigurerad för att ta emot indatahändelser. Det kan ha en kolliderare på den eller på ett barn för att ta emot indata. Om du använder Interactable med ett Unity UI-baserat GameObjects bör det vara under Canvas GameObject.

Ta knappen ett steg längre genom att skapa en ny profil, tilldela själva GameObject och skapa ett nytt tema. Använd dessutom OnClick-händelsen för att få något att hända.

Anteckning

Att göra en knapp tryckbar kräver komponenten PressableButton . Dessutom behövs komponenten PhysicalPressEventRouter för att tratta presshändelser till komponenten Interactable .

Skapa växlingsknappar och knappar med flera dimensioner

Växlingsknapp

Om du vill göra knappen Växla kan du ändra fältet så att det Selection Mode skriver Toggle. I avsnittet Profiler läggs ett nytt växlat tema till för varje profil som används när interaktionsbar aktiveras.

SelectionMode Medan är inställt på Växla kan kryssrutan IsToggled användas för att ange standardvärdet för kontrollen vid körningsinitiering.

CanSelect innebär att interaktionsbar kan gå från av till medan CanDeselect innebär invertering.

Exempel på visuella teman för profilväxling

Utvecklare kan använda gränssnitten SetToggled och IsToggled för att hämta/ange växlingstillståndet för en interaktionsbar via kod.

// 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;
Växla knappsamling

Det är vanligt att ha en lista över växlingsknappar där endast en kan vara aktiv vid en viss tidpunkt, även känd som en radiell uppsättning eller alternativknappar etc.

Använd komponenten InteractableToggleCollection för att aktivera den här funktionen. Den här kontrollen säkerställer att endast en interaktionsbar aktiveras vid en viss tidpunkt. RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) är också en bra utgångspunkt.

Så här skapar du en anpassad radiell knappgrupp:

  1. Skapa flera interaktionsbara GameObjects/knappar
  2. Ange varje interaktionsbar med SelectionMode = Växla, CanSelect = true och CanDeselect = false
  3. Skapa en tom överordnad GameObject över alla interactables och lägg till komponenten InteractableToggleCollection
  4. Lägg till alla interaktionsbara funktioner i växlingslistanInteractableToggleCollection
  5. Ange egenskapen InteractableToggleCollection.CurrentIndex för att avgöra vilken knapp som väljs som standard vid start
Växla samling

Flerdimensionell knapp

Markeringsläget för flera dimensioner används för att skapa sekventiella knappar eller en knapp som har fler än två steg, som att styra hastigheten med tre värden, Snabb (1x), Snabbare (2x) eller Snabbaste (3x).

Med dimensioner som ett numeriskt värde kan upp till 9 teman läggas till för att styra textetiketten eller strukturen för knappen för varje hastighetsinställning, med ett annat tema för varje steg.

Varje klickhändelse förs vidare med DimensionIndex 1 vid körning tills Dimensions värdet har nåtts. Sedan återställs cykeln till 0.

Exempel på flerdimensionell profil

Utvecklare kan utvärdera DimensionIndex för att avgöra vilken dimension som för närvarande är aktiv.

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

Skapa interaktionsbar vid körning

Interaktionsbar kan enkelt läggas till i valfri GameObject vid körning. I följande exempel visas hur du tilldelar en profil med ett visuellt tema.

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

Interaktionsbara händelser via kod

Man kan lägga till en åtgärd i bashändelsen Interactable.OnClick via kod med följande exempel.

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

Interactable.AddReceiver<T>() Använd funktionen för att lägga till händelsemottagare dynamiskt vid körning.

Exempelkoden nedan visar hur du lägger till en InteractableOnFocusReceiver, som lyssnar efter fokusinmatning/slut och dessutom definierar åtgärdskod som ska utföras när händelseinstanserna utlöses.

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

Exempelkoden nedan visar hur du lägger till en InteractableOnToggleReceiver, som lyssnar efter valda/avmarkerade tillståndsövergångar på växlingsbara interaktionsbara objekt, och definierar dessutom åtgärdskod som ska utföras när händelseinstanserna utlöses.

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

Se även